作为一名DirectX新手,我正在尝试了解深度缓冲区,特别是像素着色器是如何为遮挡像素调用的。
据我所知,光栅化器为每个覆盖被绘制图元的像素调用像素着色器,然后在稍后的输出合并阶段,输出合并检查深度缓冲区,并丢弃、写入或混合后台缓冲区中的像素。
然而,如果我在一个非常复杂的对象前面渲染一个简单的不透明对象,这似乎是浪费的,所以在调用复杂对象的像素着色器之前,让光栅化器检查深度图似乎是很有用的。
在做研究时,我发现了关于早期Z测试/保守Z测试等的参考资料,但关于它的文档似乎也很少。我寻找了一种在光栅化器状态描述对象上配置它的方法,但我只在OM状态描述对象上找到了类似的东西。
这似乎也可以在DX9中用SetRenderState设置(虽然我也没有使用DX9的经验)
从我的研究来看,这似乎是一些硬件在我从前到后渲染对象时所做的事情,对吗?我怎么知道呢?使用DirectX提供的所有控件,没有对此进行控制似乎很奇怪,因为它似乎是一个很好的优化:)
任何关于这方面的信息或参考资料都是有价值的。
发布于 2013-07-28 00:44:59
就深度测试而言,DirectX声明它必须看起来像是在像素着色器之后进行深度测试,而不是说它实际上必须这样做。实际上,早期的z已经在许多制造商的硬件上存在了很多年。通常还有一种比早期更早的Z测试形式,称为分层Z,它不是对单个像素进行操作,而是一次对多个像素的“瓦片”进行操作,以避免早期Z的成本。
早期的Z不是你可以通过在设备上设置的任何特定状态来打开或关闭的东西。硬件将尽可能早地执行z测试,并且以这样一种方式,您不知道它在像素着色器之后的任何地方。
但是,您可以做的某些事情可能会限制硬件尽可能早地执行z测试。Alpha测试,使用'discard‘(删除像素)和alpha to coverage都肯定会禁用早期z写入,因为在硬件可以确定是否写入深度值之前,需要运行像素着色器。如果您正在使用alpha测试/丢弃,并且不需要z-write,那么将它们关闭,那么您将有最大可能的机会使用早期z。
在像素着色器中修改/写入' depth‘是绝对不可以的,如果你想要早期的Z。在这种情况下,硬件甚至不能执行早期测试,因为它还不知道像素的深度是什么,直到你在像素着色器中决定它,它既不能执行早期的z测试,也不能执行早期的z写入。
如果您需要从像素着色器写入深度,但可以保证只写入大于或等于光栅化器生成的深度值,则可以使用相当未记录的SV_DepthGreater输出语义。由于您承诺不会写入小于插值深度的深度值,因此硬件仍然可以尝试执行早期z测试,但随后会将z写入推迟到像素着色器的末尾。(如果您碰巧使用的是倒置的z- SV_DepthLessEqual /z-buffer,那么有一个等价的z-test)。
由于z测试必须显示为在管道的末尾进行,因此在像素着色器中使用UAV也会禁用早期z。由于渲染目标现在不是唯一的输出,并且由于DirectX规范规定必须在结束时进行z测试,因此即使对于最终将无法通过z测试的像素,也应该执行UAV写入。出于这个原因,在着色器Model5中添加了一个名为[earlydepthstencil]的属性,它告诉DirectX您很高兴出现早期z(如果可能),并且即使发生了无人机写入,也不运行像素着色器。
总而言之,如果你没有做上面提到的任何一些奇怪的事情(使用SV_DEPTH修改深度,使用alpha修改覆盖范围,使用裁剪/丢弃等),那么很可能你已经获得了early-Z的好处。如果你不需要z-write,一定要关闭z-write,并且避免写到SV_DEPTH,因为如果你启用了z-write,你绝对不可能提前得到z。
https://stackoverflow.com/questions/17898738
复制相似问题