8

作为一个 DirectX 菜鸟,我正试图围绕深度缓冲区,特别是如何为模糊像素调用像素着色器。

据我了解,光栅化器为覆盖绘制的原始蜜蜂的每个像素调用像素着色器,然后在输出合并阶段的后期,输出合并检查深度缓冲区并丢弃、写入或混合后台缓冲区中的像素.

如果我在一个非常复杂的对象之前渲染一个简单的不透明对象,这似乎很浪费,所以在调用复杂对象的像素着色器之前让光栅化器检查深度图似乎很有用。

在进行研究时,我发现了对早期 Z 测试/保守 Z 测试等的参考,但似乎也很少有关于它的文档。我寻找一种方法来在光栅化状态 desc 对象上配置它,但我只在 OM 状态 desc 上找到了类似的东西。

似乎这也可以在 DX9 中使用 SetRenderState 进行设置(不过我也没有使用 DX9 的经验)

根据我的研究,如果我从前到后渲染对象,这似乎是某些硬件所做的事情,对吗?我怎么能说出来?有了所有 Control DirectX 给你的东西,你似乎无法控制它,这似乎很奇怪,因为它似乎是一个很好的优化 :)

对此的任何信息或参考资料均已适用

4

1 回答 1

26

就深度测试而言,DirectX 声明深度测试必须出现在像素着色器之后,但并没有说它实际上必须这样做。实际上,早在许多制造商的硬件上已经存在很多年了。通常有一种更早于早期的 Z 测试形式,称为分层 Z,它不是在单个像素上运行,而是一次在多个像素的“瓦片”上运行,以避免早期 Z 的成本。

Early Z 不是您可以通过您在设备上设置的任何特定状态打开或关闭的东西。硬件将尽可能早地执行 z 测试,并且您不知道它在像素着色器之后的任何地方。

您可以做一些事情,尽管这可能会限制硬件尽可能早地进行 z 测试的能力。Alpha 测试、使用“丢弃”(杀死像素)和覆盖范围的 alpha 肯定会禁用 early-z 写入,因为需要在硬件确定是否写入深度值之前运行像素着色器。如果您正在使用 alpha 测试/丢弃并且不需要 z-writes,那么将它们关闭,您就有可能获得 early-z 可用的最佳机会。

如果您想要早期 Z,在像素着色器中修改/写入“深度”是绝对不行的。在这种情况下,硬件甚至无法执行早期测试,因为它还不知道像素的深度是什么,直到您已经在像素着色器中决定了,它既不能执行早期 z 测试,也不能执行早期 z 写入。

如果您需要从像素着色器写入深度,但可以保证您只会写入大于或等于光栅化器生成的深度值,则可以使用未记录的SV_DepthGreater输出语义。由于您承诺不会写入小于插值深度的深度值,因此硬件仍然可以尝试执行 early-z 测试,但随后将 z 写入推迟到像素着色器结束。(SV_DepthLessEqual如果您碰巧使用的是反向 z-test/z-buffer,则有一个等价物)。

由于 z 测试必须出现在管道末端,因此在像素着色器中使用 UAV 也会禁用 early-z。由于渲染目标现在不是唯一的输出,而且由于 DirectX 规范表明它必须出现在最后发生 z 测试,因此即使对于最终将无法通过 z 测试的像素,您的 UAV 写入也应该发生。出于这个原因,在 Shader Model 5 中添加了一个名为[earlydepthstencil]的属性,它告诉 DirectX 您很高兴看到 early-z 发生(如果可能的话)并且即使您有 UAV 写入也不会运行像素着色器。

总而言之,如果您没有做上述任何稍微古怪的事情(使用 SV_DEPTH 修改深度、覆盖范围的 alpha、使用剪辑/丢弃等),那么您很可能已经获得了 early-Z 的好处。如果您不想要 z-writes,请始终关闭它们,并避免写入 SV_DEPTH,因为启用它绝对不可能得到 early-z。

于 2013-07-27T16:44:58.787 回答