在directX12中,他们引入了堆描述符。一种描述我们想要发送到着色器的资源的表格的方法。诚然,我在计算机图形学方面非常新,而且在directX11上只做了一点改进。我现在还没有尝试过实例或任何更复杂的东西,所以我有一个对象,每个网格都有这些定义。
Microsoft::WRL::ComPtr<ID3D12Resource> mVertexBuffer;
D3D12_VERTEX_BUFFER_VIEW mVertexBufferView;
// Index Buffer
Microsoft::WRL::ComPtr<ID3D12Resource> mIndexBuffer;
D3D12_INDEX_BUFFER_VIEW mIndexBufferView;
// World View Projection Constant Buffer
Microsoft::WRL::ComPtr<ID3D12Resource> mWVPConstantBuffer;
WVPData mWVPData;
UINT8* mMappedWVPBuffer;
// Directional Light Constant Buffer
Microsoft::WRL::ComPtr<ID3D12Resource> mDirLightConstantBuffer;
DirLightData mDirLightData;
UINT8* mMappedDirLightBuffer;
// CBVHeap
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mCbvHeap;
UINT mCbvDescriptorSize;顶点缓冲区、索引缓冲区、cbvHeap和两个常量缓冲区。一个用于变换矩阵,另一个用于定向光数据。
我不太确定cbvHeap (常量缓冲区视图堆)到底在做什么。我只是知道如何将它应用到屏幕上的内容中。所以我做了实验。我将cbvHeap和mCbvDescriptorSize从网格对象中提取出来,并将它们放在场景对象中(其中包含网格数组),然后在所有网格中使用相同的cbv堆。这是行不通的,因为它提供了一个一致的颜色贯穿整个网格。(即:每个网格都使用相同的常量缓冲区,为它们提供相同的漫射光和环境光数据。)描述符堆所做的到底是什么导致了这一点?我对每个网格的定义正确吗?
发布于 2015-11-11 22:47:47
在DX12中,描述符是一个小记录,基本上是一个指针,它指示GPU在哪里找到一些数据,比如常量缓冲区。由于每个对象都将有自己的常量缓冲区数据,具有自己的特定转换、照明/材料属性等,因此每个对象还必须有一组单独的描述符来指向其单独的数据。
在DX12中有几种设置描述符的方法。首先,可以在命令列表中添加直接更新根表中的描述符的命令。例如,可以使用SetGraphicsRootConstantBufferView()为对象的常量缓冲区设置描述符,然后绘制对象。对多个对象重复。这些描述符将保存在命令列表中,并在GPU上执行命令列表时按顺序应用。
另一种方法是使用描述符堆。描述符堆基本上是存储描述符数组的缓冲区。使用这种方法,命令列表不会为您保存描述符;您必须自己管理它们。如果在GPU使用描述符之前覆盖任何描述符,则会得到错误的结果。这听起来像是程序中正在发生的事情:每次在CPU上发出对象的绘制命令时,您可能都会覆盖堆中的相同描述符,所以当GPU执行命令列表时,只有最后编写的描述符仍然存在,并且该描述符被应用于所有对象。
要解决这个问题,您必须在描述符堆中分配足够的空间来存储要用于框架的所有描述符。将所有对象的描述符写入堆中。然后,在绘制每个对象时,使用带有偏移句柄的SetGraphicsRootDescriptorTable()将着色器指向该对象的数据,该句柄指向该对象的描述符所在的堆中的位置。
只要你还在努力学习和运行一个简单的应用程序,我可能会尽可能坚持根表方法。对于一个更严肃的高性能应用程序,您可能可以使用描述符堆进行优化,例如将给定材料的所有常量和纹理保持在一起,这样您就可以在多个对象之间重用它们,并在一个调用中绑定它们。您可能还希望避免为每个对象设置一个常量缓冲区和描述符堆,而是将许多对象的数据聚合到几个大型缓冲区中;当有大量对象时,这将更有效。
值得注意的是,一个严肃的3D应用程序需要同时运行多个帧的命令列表,以获得CPU/GPU的并行性,这将需要不断的缓冲区和描述符堆来延长以存储多帧的数据。同样,您可以通过一次构建一个命令列表,提交命令列表,然后等待它完成,然后再进入下一个框架,从而掩盖学习/提升的目的。
https://computergraphics.stackexchange.com/questions/1706
复制相似问题