【技术美术百人计划】Early-Z 和 Z-prepass
一、深度测试DepthTest

深度测试是为了解决物体可见遮挡性的问题。




二、提前深度测试Early-Z


Early-Z阶段不仅可以进行深度测试,同样可以添加模板测试
Early-Z失效
开启AlphaTest或clip/discard等丢弃片元操作
手动修改GPU插值得到的深度
开启AlphaBlend
关闭深度测试DepthTest

因此为了达到最大的优化效果,就要从近到远进行渲染,可以通过cpu将物体按据摄像机近平面由近到远进行排序后,再交付cpu进行渲染。但是当场景十分复杂时,频繁的排序操作将消耗cpu的性能;并且如果严格按照由近及远进行渲染的话,无法同时搭配合批优化手段
Z-prepass便是用来解决这个问题的
三、使用Z-Prepass
方式1:双Pass
第一个Pass即Z-Prepass只写入深度,不计算颜色
第二个Pass关闭深度写入并且将深度比较设为相等

动态批处理问题
一个物体拥有多个Pass的shader是无法进行动态批处理的,这也就会带来DrawCall的问题。

方式2:提前分离的Prepass
仍然使用两个Pass,但:
将第一个Pass(Z-Prepass)单独分离出来作为一个单独的shander,并先使用这个shader对整个场景的Opaque物体渲染一遍
第二个Pass仍关闭深度写入,深度比较函数设为相等


四、Z-Prepass所带来的问题

Z-prepass并不是一个一成不变的决策,而是要根据实际项目情况来自行判断是否采用。比如说有一个场景,有非常多的overdraw并且没办法很好的将透明物体从前往后进行排序,那么此时Z-prepass的计算消耗是远小于这些overdraw的消耗的
Early-Z和Z-Prepass的实际应用
头发是层叠的半透明面片,需要从后往前进行渲染才能得到正确的透明度混合结果

普通的渲染方法是先将不透明的部分渲染出来,再渲染透明部分的背面和正面
这种渲染方式会产生非常多的overdraw,因此需要用early-Z进行剔除。但是Early-Z不能启用透明度测试,因此需要额外用一个pass进行透明度测试来形成Z-buffer,即使用Z-prepass

Early-Z的局限性
Early-Z是硬件支持的功能,图形API无法决定是否进行
如果进行了Alpha Clip或者深度写入,会造成Early-Z失效
Early-Z通常是通过preZ来实现的,但是在DrawCall特别高的场景里使用preZ会造成负优化
如果开启了Alpha Test(Discard),导致Early-Z失效,即使被遮挡也一定会进行Pixel计算; 与之相对的Alpha Blend却可以进行正确的Early计算