2

我是 DirectX 12 的新手,并试图在 DX 上渲染网格。到目前为止,我成功地从 obj 和 fbx 文件中检索到顶点和索引,并使用模板通用窗口项目在 DX 12 上渲染所有顶点。但是,我遇到了索引缓冲区的一些问题,因为三角形列表的渲染结果完全不正确,尤其是当输入网格很大(数十万个顶点)时。基本上,索引数据被写为一个指针数组,它似乎是正确的。使用线表图元拓扑,渲染结果如下图所示。 线表图元拓扑渲染结果

我想知道是否有人可以提出任何可能在代码中出错的建议。对于 IBV 设置,我使用模板项目中的确切代码。提前感谢您的任何帮助。

更新:数据是使用 FBX SDK 检索到的 obj 文件数据。我确认了 obj 网格信息和检索到的数据,它们是精确匹配的。所以我认为数据文件是正确的。此外,对于 IBV 设置传入的数据,例如缓冲区字节大小,也是正确的。对于代码,它来自 VS DX 12 模板通用 windows 项目,如下所示。非常感谢您的帮助。

        // Create the index buffer resource in the GPU's default heap and copy index data into it using the upload heap.
    // The upload resource must not be released until after the GPU has finished using it.
    Microsoft::WRL::ComPtr<ID3D12Resource> indexBufferUpload;

    //CD3DX12_RESOURCE_DESC indexBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(indexBufferSize);
    DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(defaultHeapProperties),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(indexBufferSize),
        D3D12_RESOURCE_STATE_COPY_DEST,
        nullptr,
        IID_PPV_ARGS(&m_indexBuffer)));

    DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(indexBufferSize),
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(&indexBufferUpload)));

    m_indexBuffer->SetName(L"Index Buffer Resource");
    indexBufferUpload->SetName(L"Index Buffer Upload Resource");


    // Upload the index buffer to the GPU.
    {
        D3D12_SUBRESOURCE_DATA indexData = {0};

        //indexData.pData = cubeIndices;
        indexData.pData = reinterpret_cast<BYTE*>(cubeIndices);
        indexData.RowPitch = indexBufferSize;
        indexData.SlicePitch = indexData.RowPitch;

        UpdateSubresources(m_commandList.Get(), m_indexBuffer.Get(), indexBufferUpload.Get(), 0, 0, 1, &indexData);

        CD3DX12_RESOURCE_BARRIER indexBufferResourceBarrier =
            CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);

        //CD3DX12_RESOURCE_BARRIER indexBufferResourceBarrier =
        //  CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
        m_commandList->ResourceBarrier(1, &indexBufferResourceBarrier);
    }

    // Create a descriptor heap for the constant buffers.
    {
        D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
        heapDesc.NumDescriptors = DX::c_frameCount;
        heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
        // This flag indicates that this descriptor heap can be bound to the pipeline and that descriptors contained in it can be referenced by a root table.
        heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
        DX::ThrowIfFailed(d3dDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_cbvHeap)));

        m_cbvHeap->SetName(L"Constant Buffer View Descriptor Heap");
    }

    CD3DX12_RESOURCE_DESC constantBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(DX::c_frameCount * c_alignedConstantBufferSize);
    DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
        &uploadHeapProperties,
        D3D12_HEAP_FLAG_NONE,
        &constantBufferDesc,
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(&m_constantBuffer)));

    m_constantBuffer->SetName(L"Constant Buffer");

    // Create constant buffer views to access the upload buffer.
    D3D12_GPU_VIRTUAL_ADDRESS cbvGpuAddress = m_constantBuffer->GetGPUVirtualAddress();
    CD3DX12_CPU_DESCRIPTOR_HANDLE cbvCpuHandle(m_cbvHeap->GetCPUDescriptorHandleForHeapStart());
    m_cbvDescriptorSize = d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

    for (int n = 0; n < DX::c_frameCount; n++)
    {
        D3D12_CONSTANT_BUFFER_VIEW_DESC desc;
        desc.BufferLocation = cbvGpuAddress;
        desc.SizeInBytes = c_alignedConstantBufferSize;
        d3dDevice->CreateConstantBufferView(&desc, cbvCpuHandle);

        cbvGpuAddress += desc.SizeInBytes;
        cbvCpuHandle.Offset(m_cbvDescriptorSize);
    }

    // Map the constant buffers.
    DX::ThrowIfFailed(m_constantBuffer->Map(0, nullptr, reinterpret_cast<void**>(&m_mappedConstantBuffer)));
    ZeroMemory(m_mappedConstantBuffer, DX::c_frameCount * c_alignedConstantBufferSize);
    // We don't unmap this until the app closes. Keeping things mapped for the lifetime of the resource is okay.

    // Close the command list and execute it to begin the vertex/index buffer copy into the GPU's default heap.
    DX::ThrowIfFailed(m_commandList->Close());
    ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
    m_deviceResources->GetCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

    // Create vertex/index buffer views.
    m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
    m_vertexBufferView.StrideInBytes = sizeof(VertexPositionColorTexture);
    m_vertexBufferView.SizeInBytes = sizeof(*cubeVertices) * m_VertexNumber;

    m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress();
    m_indexBufferView.SizeInBytes = sizeof(*cubeIndices) * m_VertxIndicesNumber;
    m_indexBufferView.Format = DXGI_FORMAT_R16_UINT;

    // Wait for the command list to finish executing; the vertex/index buffers need to be uploaded to the GPU before the upload resources go out of scope.
    m_deviceResources->WaitForGpu();
4

3 回答 3

3

我实际上和迈克尔一起工作,所以我知道这个问题的答案:)。我将把它贴在这里,以供偶然发现这篇文章的人使用。

当有超过 140000 个索引时,问题确实是使用 16 位(无符号短)索引。最大无符号短整数为 65535。解决方案是使用 32 位索引(无符号整数),格式为 DXGI_FORMAT_R32_UINT。

于 2015-12-10T21:41:49.567 回答
2

数据是使用 FBX SDK 检索到的 obj 文件数据。我确认了 obj 网格信息和检索到的数据,它们是精确匹配的。所以我认为数据文件是正确的。此外,对于 IBV 设置传入的数据,例如缓冲区字节大小,也是正确的。对于代码,它来自 VS DX 12 模板通用 windows 项目,如下所示。非常感谢您的帮助。

        // Create the index buffer resource in the GPU's default heap and copy index data into it using the upload heap.
    // The upload resource must not be released until after the GPU has finished using it.
    Microsoft::WRL::ComPtr<ID3D12Resource> indexBufferUpload;

    //CD3DX12_RESOURCE_DESC indexBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(indexBufferSize);
    DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(defaultHeapProperties),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(indexBufferSize),
        D3D12_RESOURCE_STATE_COPY_DEST,
        nullptr,
        IID_PPV_ARGS(&m_indexBuffer)));

    DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(indexBufferSize),
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(&indexBufferUpload)));

    m_indexBuffer->SetName(L"Index Buffer Resource");
    indexBufferUpload->SetName(L"Index Buffer Upload Resource");


    // Upload the index buffer to the GPU.
    {
        D3D12_SUBRESOURCE_DATA indexData = {0};

        //indexData.pData = cubeIndices;
        indexData.pData = reinterpret_cast<BYTE*>(cubeIndices);
        indexData.RowPitch = indexBufferSize;
        indexData.SlicePitch = indexData.RowPitch;

        UpdateSubresources(m_commandList.Get(), m_indexBuffer.Get(), indexBufferUpload.Get(), 0, 0, 1, &indexData);

        CD3DX12_RESOURCE_BARRIER indexBufferResourceBarrier =
            CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);

        //CD3DX12_RESOURCE_BARRIER indexBufferResourceBarrier =
        //  CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
        m_commandList->ResourceBarrier(1, &indexBufferResourceBarrier);
    }

    // Create a descriptor heap for the constant buffers.
    {
        D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
        heapDesc.NumDescriptors = DX::c_frameCount;
        heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
        // This flag indicates that this descriptor heap can be bound to the pipeline and that descriptors contained in it can be referenced by a root table.
        heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
        DX::ThrowIfFailed(d3dDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_cbvHeap)));

        m_cbvHeap->SetName(L"Constant Buffer View Descriptor Heap");
    }

    CD3DX12_RESOURCE_DESC constantBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(DX::c_frameCount * c_alignedConstantBufferSize);
    DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
        &uploadHeapProperties,
        D3D12_HEAP_FLAG_NONE,
        &constantBufferDesc,
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(&m_constantBuffer)));

    m_constantBuffer->SetName(L"Constant Buffer");

    // Create constant buffer views to access the upload buffer.
    D3D12_GPU_VIRTUAL_ADDRESS cbvGpuAddress = m_constantBuffer->GetGPUVirtualAddress();
    CD3DX12_CPU_DESCRIPTOR_HANDLE cbvCpuHandle(m_cbvHeap->GetCPUDescriptorHandleForHeapStart());
    m_cbvDescriptorSize = d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

    for (int n = 0; n < DX::c_frameCount; n++)
    {
        D3D12_CONSTANT_BUFFER_VIEW_DESC desc;
        desc.BufferLocation = cbvGpuAddress;
        desc.SizeInBytes = c_alignedConstantBufferSize;
        d3dDevice->CreateConstantBufferView(&desc, cbvCpuHandle);

        cbvGpuAddress += desc.SizeInBytes;
        cbvCpuHandle.Offset(m_cbvDescriptorSize);
    }

    // Map the constant buffers.
    DX::ThrowIfFailed(m_constantBuffer->Map(0, nullptr, reinterpret_cast<void**>(&m_mappedConstantBuffer)));
    ZeroMemory(m_mappedConstantBuffer, DX::c_frameCount * c_alignedConstantBufferSize);
    // We don't unmap this until the app closes. Keeping things mapped for the lifetime of the resource is okay.

    // Close the command list and execute it to begin the vertex/index buffer copy into the GPU's default heap.
    DX::ThrowIfFailed(m_commandList->Close());
    ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
    m_deviceResources->GetCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

    // Create vertex/index buffer views.
    m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
    m_vertexBufferView.StrideInBytes = sizeof(VertexPositionColorTexture);
    m_vertexBufferView.SizeInBytes = sizeof(*cubeVertices) * m_VertexNumber;

    m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress();
    m_indexBufferView.SizeInBytes = sizeof(*cubeIndices) * m_VertxIndicesNumber;
    m_indexBufferView.Format = DXGI_FORMAT_R16_UINT;

    // Wait for the command list to finish executing; the vertex/index buffers need to be uploaded to the GPU before the upload resources go out of scope.
    m_deviceResources->WaitForGpu();
于 2015-12-01T16:36:56.043 回答
0

对于那些同时使用 DirectX 模板并遇到此问题的人,我建议搜索DrawIndexedInstanced. 在那里,我不得不IndexCountPerInstance根据增加的 incides 数据量来更新参数。

为了使其更灵活,应根据索引计算大小。由于我将 设置为m_indexBufferView.SizeInBytes以字节为单位的索引大小,因此我必须将其除以unsigned int.

std::vector<unsigned int> indices;
...
// Fill vertex data and indices data
//Render one frame
...
DrawIndexedInstanced(m_indexBufferView.SizeInBytes / sizeof(unsigned int), 1, 0, 0, 0);
于 2021-06-26T13:01:37.643 回答