首页 > 解决方案 > DirectX11 - 具有流输出的几何着色器

问题描述

我正在尝试从几何着色器中流出数据以用作顶点缓冲区以输入到另一个着色器中。但是,这似乎不起作用,调试层什么也没告诉我。缓冲区描述有什么问题吗?

这是我创建输出缓冲区的方式:

D3D11_BUFFER_DESC outputBufferDesc;
ZeroMemory(&outputBufferDesc, sizeof(outputBufferDesc));
outputBufferDesc.ByteWidth = sizeof(XMFLOAT4) + 2 * sizeof(XMFLOAT3);
outputBufferDesc.Usage = D3D11_USAGE_DEFAULT;
outputBufferDesc.BindFlags = D3D11_BIND_STREAM_OUTPUT;
outputBufferDesc.CPUAccessFlags = 0;
outputBufferDesc.MiscFlags = 0;
outputBufferDesc.StructureByteStride = 0;

result = renderer->CreateBuffer(&outputBufferDesc, NULL, &outputBuffer);
if (result != S_OK)
{
    MessageBox(NULL, filename, L"Failed to create stream output buffer", MB_OK);
    exit(0);
}

UINT offset[1] = { 0 };
deviceContext->SOSetTargets(1, &outputBuffer, offset);

第一个着色器的绘制调用:

deviceContext->VSSetShader(vertexShader, NULL, 0);
deviceContext->PSSetShader(pixelShader, NULL, 0);
deviceContext->GSSetShader(streamOutputGeometryShader, NULL, 0);

// Render the triangle.
deviceContext->DrawIndexed(indexCount, 0, 0);

UINT offset[1] = { 0 };
ID3D11Buffer* pNullBuffer = 0;
deviceContext->SOSetTargets(1, &pNullBuffer, offset);

我将信息从该缓冲区复制到第二个缓冲区:

D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));
vertexBufferDesc.ByteWidth = sizeof(XMFLOAT4) + 2 * sizeof(XMFLOAT3);
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;

result = renderer->CreateBuffer(&vertexBufferDesc, NULL, &vertexBuffer);
if (result != S_OK)
{

    MessageBox(NULL, L"Failed to create output mesh vertex buffer", L"Failed", MB_OK);
    exit(0);

}

deviceContext->CopyResource(vertexBuffer, buffer);

我使用顶点缓冲区为网格设置输入拓扑:

unsigned int stride;
unsigned int offset;

// Set vertex buffer stride and offset.
stride = sizeof(XMFLOAT4) + 2 * sizeof(XMFLOAT3);
offset = 0;

deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

最后,第二个着色器的绘制调用很简单:

deviceContext->DrawAuto();

编辑:几何图形正在几何着色器中正确计算,但它没有被流出。我在下面包含了几何着色器创建代码:

D3D11_SO_DECLARATION_ENTRY SODeclarationEntry[3] =
{

    { 0, "SV_POSITION", 0, 0, 4, 0 },
    { 0, "NORMAL", 0, 0, 3, 0 },
    { 0, "TEXCOORD", 0, 0, 3, 0 }

};

// Create the geometry shader from the buffer.
result = renderer->CreateGeometryShaderWithStreamOutput(geometryShaderBuffer->GetBufferPointer(), geometryShaderBuffer->GetBufferSize(), SODeclarationEntry, _countof(SODeclarationEntry),
    NULL, 0, D3D11_SO_NO_RASTERIZED_STREAM, NULL, &streamOutputGeometryShader);

标签: c++directxhlsl

解决方案


除了实际的顶点数据之外,用作 Stream Output Stage 目标的缓冲区还维护一些内部状态,以跟踪写入了多少几何图形。DrawAuto()依靠此信息来了解要绘制多少几何图形。当您仅将流输出缓冲区中的顶点数据复制到 plainD3D11_BIND_VERTEX_BUFFER中时,此信息将丢失。

文档中的相关引用:

DrawAuto 仅在将一个输入缓冲区绑定为插槽 0 处的 IA 阶段的输入进行绘制时才有效。应用程序必须使用两个绑定标志 D3D11_BIND_VERTEX_BUFFER 和 D3D11_BIND_STREAM_OUTPUT 创建 SO 缓冲区资源。

我不确定是否应该可以将数据从一个流输出缓冲区复制到另一个并DrawAuto()从那里复制。我想这可能会奏效。但是,您目前正在做的事情绝对不应该根据文档进行。理想情况下,您只需避免复制数据。如果您真的必须复制数据(无论出于何种原因),我建议您首先尝试直接从您流入的缓冲区中进行绘制,以确保其他所有内容都设置正确,并且只有在成功后才尝试复制到另一个同时包含两者的缓冲区中顶点和流输出绑定标志设置...


推荐阅读