【问题标题】:Early Z-test / depth-test in DirectX 11DirectX 11 中的早期 Z 测试/深度测试
【发布时间】:2013-07-27 17:59:32
【问题描述】:

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

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

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

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

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

从我的研究看来,如果我从前到后渲染对象,某些硬件就会这样做,对吗?我怎么能说出来?有了 DirectX 提供的所有控制功能,无法控制这一点似乎很奇怪,因为这似乎是一个很好的优化 :)

有关此的任何信息或参考资料均已获知

【问题讨论】:

    标签: optimization directx directx-11 depth-buffer depth-testing


    【解决方案1】:

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

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

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

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

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

    由于 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多