我一直在尝试实现基于计算着色器的粒子系统。
我有一个计算着色器,它使用带有 D3D11_BUFFER_UAV_FLAG_COUNTER 标志的 UAV 构建粒子的结构化缓冲区。
当我添加到这个缓冲区时,我会检查这个粒子是否有任何复杂的行为,我想过滤掉这些行为并在单独的计算着色器中执行。例如,如果粒子想要执行碰撞检测,我将其索引添加到另一个结构化缓冲区,也带有 D3D11_BUFFER_UAV_FLAG_COUNTER 标志。
然后我运行第二个计算着色器,它处理所有索引,并对这些粒子应用碰撞检测。
然而,在第二个计算着色器中,我估计大约 5% 的索引是错误的——它们属于不支持碰撞检测的其他粒子。
这是执行列表构建的计算着色器代码:
// append to destination buffer
uint dstIndex = g_dstParticles.IncrementCounter();
g_dstParticles[ dstIndex ] = particle;
// add to behaviour lists
if ( params.flags & EMITTER_FLAG_COLLISION )
{
uint behaviourIndex = g_behaviourCollisionIndices.IncrementCounter();
g_behaviourCollisionIndices[ behaviourIndex ] = dstIndex;
}
如果我将“添加到行为列表”位拆分为单独的计算着色器,并在粒子列表构建后运行它,一切都会完美运行。但是我认为我不应该这样做 - 再次通过所有粒子是浪费带宽。
我怀疑IncrementCounter
实际上并不能保证将唯一索引返回到 UAV,并且正在进行一些巧妙的优化,这意味着该索引仅在使用它的计算着色器内有效。因此我尝试将它传递给第二个计算着色器无效。
任何人都可以对这里发生的事情给出任何具体的答案吗?如果有办法让我将过滤保持在与我的核心更新相同的计算着色器中?
谢谢!