2

I am new to DirectX 12 and trying to render mesh on DX. So far, I succeeded in retrieving vertices and indices from obj and fbx files and render all vertices on DX 12 using the template universal window project. However, I encountered some problems with the indices buffer as the rendering result of triangle list is completely incorrect, especially when the input mesh is big(hundreds of thousands vertices). Basically, the indices data is written as a pointer array and it seems to be correct. With the line list primitive topology, the rendering result is shown as below. Line list primitive topology rendering result

I am wondering if anyone can give any suggestion where could probably go wrong in the codes. For the IBV settings I am using the exact codes from the template project. Thank you in advance for any helps.

Updates: The data is the obj file data retrieved using FBX SDK. I confirmed both the obj mesh information and the retrieved data, they were precisely matched. So I think the data file is correct. Besides, for the data passing in for the IBV setting, such as buffer byte size, are also correct. For the code, it was from VS DX 12 template universal windows project, as listed below. Thank you very much for helps.

        // 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();
Michael Wei
  • 185
  • 2
  • 10
  • Thanks for the suggestion and I have just updated the question. – Michael Wei Dec 01 '15 at 16:41
  • You suggest it goes wrong after hundreds of thousands of vertices, which of course it will do if you only use 16 bit indices which can't exceed 65,535. However, you aren't clear if it breaks below 65,535 vertices, does it? – Adam Miles Dec 01 '15 at 16:44
  • I used a smaller mesh (530 vertices and 992 faces) but the problem is still there. – Michael Wei Dec 01 '15 at 16:56

3 Answers3

3

I actually work with Michael so I know the answer to this question :). I'll just post it here for people stumbling onto this post.

The problem was indeed using 16-bit (unsigned short) indices when there were over 140000 indices. Max unsigned short is 65535. The solution was using 32-bit indices (unsigned int) with format DXGI_FORMAT_R32_UINT.

0xfeedbacc
  • 301
  • 2
  • 9
2

the data is the obj file data retrieved using FBX SDK. I confirmed both the obj mesh information and the retrieved data, they were precisely matched. So I think the data file is correct. Besides, for the data passing in for the IBV setting, such as buffer byte size, are also correct. For the code, it was from VS DX 12 template universal windows project, as listed below. Thank you very much for helps.

        // 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();
Michael Wei
  • 185
  • 2
  • 10
  • This is not an answer is it, it is just more information? If so you should edit it into the question, not post it as an answer. – Gimby Dec 04 '15 at 10:27
0

For those who use also the DirectX template, and struggling with this issue, I recommend to search for the DrawIndexedInstanced. There I had to update the IndexCountPerInstance parameter according to the increased amount of incides data.

To make it more flexible, the size should be calculated from the indices. Since I set the m_indexBufferView.SizeInBytes to the indices size in bytes, I had to divide it by the size of an 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);
zerocukor287
  • 555
  • 2
  • 8
  • 23