
微软
前段时间我在ZXEngine中解决了这个问题,现在就自己来回答一下,希望能给有类似疑问的人提供一个参考。我的最终解决方案是使用ByteAddressBuffer数组。在我最初提出问题时列出了四种可能的方案,而这个最终的解决方法实际上与这些方案都有一定的关联。具体来说,每个材质数据仍然对应一个独立的ID3D12Resource资源。在需要绑定到光线追踪管线的ID3D12DescriptorHeap上,预留出一块连续的区域用于绑定材质数据。这种方式要求预先设定场景所能支持的材质数据的最大值,不过这个数值可以在运行时动态调整。例如,如果我预计当前场景最多包含100个材质数据,那么就需要在ID3D12DescriptorHeap上预留100个DescriptorHandle。接下来,按照创建顶层加速结构(TLAS)时填充底层加速结构(BLAS)的顺序(或者根据自定义的InstanceID),将每个BLAS对应的材质数据ID3D12Resource按顺序绑定到ID3D12DescriptorHeap上即可。在声明根签名参数时,需要为这个材质数据数组分配一个单独的空间,我们假设这里使用的是space1。那么,在HLSL中接收对应数据的声明可以写成以下形式:这种实现方式无需固定材质数量,因此能够支持场景中材质数量的动态变化。同时,只需声明当前着色器代码所需的材质数据结构体即可,无需关心场景中其他材质的情况。在实际使用时,可以通过HLSL内置函数InstanceID()获取当前命中(Hit)的BLAS索引,并用该索引直接访问材质数据数组。得到的材质数据是一个ByteAddressBuffer,此时可以通过ByteAddressBuffer的Load模板函数将其中的数据转换为相应的结构体。完整的HLSL代码如下所示:通过上述方法,问题得以解决。这种方法能够支持任意动态数量以及任意不同数据结构类型的光追材质数据绑定,而且每个着色器代码只需关注自身逻辑即可。这样的效果类似于Vulkan中直接从GPU地址索引数据的方式。我想谈一谈为什么一开始没能想到这个解决方案。实际上,这完全是因为
微软官网的HLSL文档质量太差!我真的很想吐槽他们。文档结构混乱,很难根据自己的需求快速找到相关内容,而且文档内容还不完整!这些问题导致了很大的困扰。