学习教程来自:【技术美术百人计划】图形 3.5 Early-z和Z-prepass
Early-z和Z-prepass
1.深度测试
Depth Test,用来解决物体可见遮挡性
顶点着色器->曲面细分->几何着色器->光栅化->片元着色器->透明度测试->模板测试->深度测试->混合
渲染流程详见:
技美知识学习1100:渲染管线
没有通过测试的片元会被丢弃,导致这些片元的计算量被浪费
2.提前深度测试
Early-Z,用来解决过多不必要的片元计算问题(1中的缺陷)
顶点着色器->曲面细分->几何着色器->光栅化->提前深度测试->片元着色器->透明度测试->模板测试->深度测试->混合
没有通过Early-Z的片元会被丢弃,不进入片元着色器进行计算
在提前阶段的位置也可以添加模板测试
2.1.Early-Z失效的情况
- 开启Alpha Test或clip/discard等手动丢弃片元操作(但是深度信息还在)
- 手动修改GPU插值得到的深度(原因同上)
- 开启Alpha Blend(深度写入关闭ZWrite Off)
- 关闭深度测试Depth Test
2.2.Early-Z使用条件
当渲染顺序为如图所示时,每次提前深度测试时都抛弃了上一次计算得到的片元,保留了当前的计算结果。这样的渲染顺序不会有优化结果
反之,顺序颠倒后则优化效果最大
左:EarlyZ失效 中:EarlyZ生效 右:EarlyZ生效
结论:
在渲染不透明物体时,尽管prePass提前绘制了深度信息,但也造成了的成倍的Batches数量增加,性能下降。其次,Unity本身没有按照由近到远的顺序渲染物体,而是做了最大限度优化GPU的排序(见下面参考),这使得当在如上图的过程中,序号为9332的物体绘制完成后,编号在这之前的物体都不会通过EarlyZ的深度测试,不会造成大量的OverDraw,也就避免了片元着色器的浪费。
因此手动增加一个Pass来渲染深度,从结果上看没有必要。
来自Unity文档OpaqueSortMode的参考:
Opaque objects are sorted by various criteria (sorting layers, shader queues, materials, distance, lightmaps etc.) to maximize both the CPU efficiency (reduce number of state changes and improve draw call batching), and to maximize GPU efficiency (many GPUs prefer rough front-to-back rendering order for faster rejection of invisible surfaces).
测试场景2:双Pass仿X光透视效果实现
灵感来源及参考资料:
Unity3D-Shader-实现X光效果
一口气解决RenderQueue、Ztest、Zwrite、AlphaTest、AlphaBlend和Stencil
Unity Shader-渲染队列,ZTest,ZWrite,Early-Z
模型来自互联网
实现效果
实现原理
第一个Pass关闭深度写入,使用Greater渲染透视的效果,第二个Pass正常渲染Lambert效果
预先配置: Tags {“Queue”=”Transparent” “RenderType”=”TransParent” “IgnoreProjector”=”True”}
第一个Pass:透视效果
- 配置:ZWrite off ZTest Greater Blend SrcAlpha OneMinusSrcAlpha
- 顶点着色器:片元颜色 = (1-viewDir · normalDir) Color Intensity
- 片元着色器:返回顶点中计算的颜色
第二个Pass:Lambert
- 配置:ZWrite On ZTest LEqual Blend Off
- 计算Lambert漫反射效果
总结earlyZ的限制
- 很多简单物体存在场景中时,如上测试场景1,单独一个Pass计算深度信息消耗很大。
- 有效的排序、合理的渲染顺序可以很好的发挥EarlyZ的效果(见OpaqueSortMode)。
- 反之,渲染顺序的不合理会频繁的让待渲染的物体通过EarlyZ、进行片元计算,造成OverDraw。