PISCOnoob

导航

EarlyZ与Z-PrePass

写在前面:

本文章为个人学习笔记,方便以后自己复习,也希望能帮助到他人。

由于本人水平有限难免出现错误,还请评论区指出,多多指教。

部分图元和素材来源于网络,如有侵权请联系本人删除。

参考资料与链接会在文章末尾贴出。

=======================================================================

1.1

我们知道zbuffer算法在DepthTest中为场景片元排序,确保有正确的顺序,然后把通过DepthTest的片元留下并更新相应的深度缓冲区和颜色缓冲区,把不通过测试的片元舍弃掉,最终得到正确的(想要的)视觉效果。但是这里有一个问题,我们先简单回顾一下rendering pipeline。

从上图中我们可以了解到,包括DepthTest在内的各种Test是位于PixelShader(Fragment Shader)之后的,意味着某些无法通过DepthTest的片元之前仍是要经过PixelShader计算的,最终不需要的东西仍然去计算它无疑是一种浪费。

因此大佬们在VertexShader后PixelShader前再添加一次DepthTest,将不通过测试的片元舍弃掉,不参加后续的PixelShader计算,这一步操作被称为EarlyZ,目前由硬件厂商在硬件中已经写好,不同的硬件厂商对这一操作和技术可能会有不同的命名。

2.1

我们来简单看下EarlyZ在渲染中如何发挥它的作用。

下图三个物体有前后遮挡关系,这时EarlyZ计算得2,3两个物体被1遮挡了,所以就舍弃掉2,3,不参加后续PixelShder的计算节省了性能。

2.2

但是要注意,下面几种情况会使得EarlyZ失效:

  • 开启AlphaTest或clip/discard等舍弃片元的操作
  • 修改深度值
  • 开启Alpha blend

正常来说开启Alpha Test后,A的黑色部分片元被舍弃,能够看到后面B C两个不透明物体;但是开启EarlyZ后,首先记录下了A的深度信息,到了AlphaTest理应舍弃A物体黑色部分,渲染B C,然而因为B C无法通过深度测试而出现错误渲染结果(这时一般会把深度测试设置为Equal)。第二点修改深度值同理。

关于第三点开启AlphaBlend一般会关闭深度写入(ZWriteOff),这就导致EarlyZ无法写入深度信息。

2.3

为了解决上述的问题,我们可以用Z-PrePass。

我们使用两个Pass,首先在第一个Pass(PrePass)仅仅开启深度写入,不输出任何颜色信息,先渲染不透明物体(Opaque),再渲染透明物体(也可以称为Transparent Mask),渲染Mask的时候做Clip。然后我们在第二个Pass(BasePass)中关闭深度写入,并且将深度比较函数设置为相等,正常渲染输出颜色信息,先渲染Opaque再渲染Mask,但是这时不开启Clip。

但是这样显然多了一个pass的消耗,会出现两倍的drawcall。而如果PixelShader非常复杂的话,这么也是值得的,所以还是要看具体的项目才能确定技术方案。

简单来说EarlyZ是底层硬件写好无法修改且在某些情况下会失效,而Z-PrePass则是在失效情况下的一种手动替代方案,目的都是为了减少overdraw节省性能所做的操作。

 

 

参考资料:

1.Unity Shader入门精要–冯乐乐

2.TA百人计划

posted on 2022-11-01 10:43  PISCOnoob  阅读(69)  评论(0编辑  收藏  举报