Индексный буфер DirectX 12
Я новичок в DirectX 12 и пытаюсь сделать сетку на DX. До сих пор мне удалось извлечь вершины и индексы из файлов obj и fbx и визуализировать все вершины в DX 12, используя шаблон универсального оконного проекта. Однако я столкнулся с некоторыми проблемами с буфером индексов, так как результат рендеринга списка треугольников совершенно неверен, особенно когда входная сетка велика (сотни тысяч вершин). В основном данные индексов записываются в виде массива указателей, и это кажется правильным. С топологией примитива списка строк результат рендеринга показан ниже. Результат рендеринга примитивной топологии списка строк
Мне интересно, если кто-нибудь может дать какие-либо предложения, где, возможно, может пойти не так в кодах. Для настроек IBV я использую точные коды из шаблона проекта. Заранее спасибо за любую помощь.
Обновления: данные - это данные файла obj, полученные с помощью FBX SDK. Я подтвердил как информацию об объекте, так и полученные данные, они были точно сопоставлены. Поэтому я думаю, что файл данных правильный. Кроме того, для данных, передаваемых для настройки 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();
3 ответа
Я на самом деле работаю с Майклом, поэтому я знаю ответ на этот вопрос:). Я просто опубликую это здесь для людей, спотыкающихся на этот пост.
Проблема действительно заключалась в использовании 16-битных (беззнаковых коротких) индексов, когда было более 140000 индексов. Макс. Unsigned short равно 65535. Решение было использовать 32-битные индексы (без знака int) с форматом DXGI_FORMAT_R32_UINT.
Данные - это данные файла obj, полученные с помощью FBX SDK. Я подтвердил как информацию об объекте, так и полученные данные, они были точно сопоставлены. Поэтому я думаю, что файл данных правильный. Кроме того, для данных, передаваемых для настройки 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();
Тем, кто использует также шаблон DirectX и борется с этой проблемой, я рекомендую поискать
DrawIndexedInstanced
. Там мне пришлось обновить
IndexCountPerInstance
параметр в соответствии с увеличенным количеством данных об инцидентах.
Чтобы сделать его более гибким, размер следует рассчитывать по индексам. Поскольку я установил
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);