DirectX11-具有流输出的几何着色器

时间:2018-11-21 20:24:25

标签: c++ directx hlsl

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

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

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);

1 个答案:

答案 0 :(得分:1)

除了实际的顶点数据外,用作流输出阶段目标的缓冲区还保持一些内部状态,以跟踪记录了多少几何图形。 DrawAuto()依靠此信息来了解要绘制多少几何图形。当您仅将顶点数据从流输出缓冲区中复制到普通D3D11_BIND_VERTEX_BUFFER时,此信息将丢失。

来自the documentation的相关报价:

  

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

我不确定是否应该将数据从一个流输出缓冲区复制到另一个,然后DrawAuto()从那里复制。我想这可能有用。但是,根据文档,您现在所要做的绝对不起作用。理想情况下,您只需避免复制数据。如果确实必须复制数据(出于某种原因),我还是建议您首先尝试直接从流式传输的缓冲区中进行绘制,以确保其他所有设置均正确,并且只有在可行的情况下,才尝试将其复制到另一个具有两个缓冲区的缓冲区中顶点和流输出绑定标志设置了……