【技术美术百人计划】模板测试与深度测试
模板测试概览:

图1为颜色缓冲区
图2为模板缓冲区,默认为0,给每个片元分配一个[0,255]之间的数值,8位。
图3为通过自定义准则得到的结果。为0则不渲染,为1则渲染。
模板测试在渲染管线的位置:

Pixel Ownership Test:控制像素的使用权限。(只能在game窗口和scene窗口显示。其他位置都会被剔除掉)
Scissor Test:裁剪测试。(在game和scene窗口内,自己可以再次定义渲染范围)
Alpha Test:透明度测试。(设置一个透明度阈值,大于这个阈值就通过测试,相反小于就剔除)
Stencil Test:模板测试
Depth Test:深度测试
Blending:透明度混合
模板测试书面理解:
模板缓冲区可以为屏幕上的每一个像素点保留一个无符号的整数值(通常是8位整数)。
在渲染中,可以用这个值与一个预先设定的参考值相比较,根据比较结果来决定是否更新相应颜色点的值,这个过程被称为模板测试。
模板测试发生在透明度测试后,深度测试前,如果模板测试通过,则更新像素值,反之则不更新。

模板测试语法:
比较操作(ComparisonFunction)
更新值(stencilOperation)
模板测试总结
使用模板缓冲区最重要的两个值:当前模板缓冲值(stencilBufferValue)和模板参考值(referenceValue)。
模板测试主要就是对这两个值使用特定的比较操作:Never,Always,Less,LEqual,Greater,GEqual,Equal。
模板测试之后要对模板缓冲区的值(stencilBufferValue)进行更新操作,更新操作包括:Keep,Zero,Replace,IncrSat,DecrSat,Invert等等。
模板测试之后可以根据结果对模板缓冲区做不同的更新操作,比如模板测试成功操作Pass,模板测试失败操作Fail,深度测试失败操作ZFail,还有正对正面和背面精确更新操作PassBack,PassFront,FailBack等等。

深度测试(Z Test)



深度测试是什么:
所谓深度测试,针对当前对象在屏幕上(frame buffer)对应的像素点,将对像自身的深度值与当前该像素点缓存的深度值作比较,通过则写入颜色缓冲,否则不写入。

深度缓冲区
深度缓冲就像颜色缓冲一样,在每个片段储存信息,和颜色缓冲有着一样的宽度和高度。深度缓冲是由窗口系统自动创建的,他会以16、24、32位float的形式储存深度值。大部分系统中,其精度都是24位的。
Z-Buffer中储存的是当前的深度信息,对于每个像素存储一个深度值。
通过ZWrite和ZTest调用ZBuffer(深度缓冲区)实现相应的效果。
ZWrite(深度写入)
深度写入包括两种状态:ZWrite On 和 ZWrite Off。
当我们开启深度写入时,物体被渲染到屏幕上时,每个像素的深度都写入到深度缓冲区中;反之,则不会写入到深度缓冲中。但是,物体是否被写入深度缓冲,除了ZWrite外,更重要的是ZTest(深度测试)通过,如果ZTest都没通过,那也就不会写入深度了。
ZTest(深度测试)
ZTest分为通过和不通过两种状态,加上ZWrite就是4种状态。
深度测试 On,深度写入 On:写入深度缓冲区,写入颜色缓冲区。
深度测试 On,深度写入 Off:不写入深度缓冲区,写入颜色缓冲区。
深度测试 Off,深度写入 On:不写入深度缓冲区,不写入颜色缓冲区。
深度测试 Off,深度写入 Off:不写入深度缓冲区,不写入颜色缓冲区。
ZTest比较操作
渲染队列
unity有几种内置的渲染队列,从先到后,数字越小越先渲染。
使用方法:
不透明物体渲染顺序:从前到后
透明物体渲染顺序:从后到前
Early-Z
传统渲染管线中,ZTest处于Blending阶段,这时会进行深度测试,所有对象的像素着色器都会计算一遍,会造成大量无用计算,每个像素点会重叠很多计算。
因此,现代GPU运用了Early-Z的技术,在顶点着色器和片元着色器之间进行一次深度测试,如果失败,则不必进行片元计算,提升性能。但是最终ZTest仍要进行,以保证计算遮挡结果的正确。
前面的一次Z-Cull是为了裁剪以达到优化目的,后一次主要是Z-Check,为了检查,如下图:

深度值
世界坐标的Z分量
观察空间的Z分量(线性深度)
准备投影,深度缓冲中存储Z/W分量(透视投影非线性)
https://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/01%20Depth%20testing/

为什么深度缓冲区存储非线性深度呢?
正确的投影特性的非线性深度方程是和1/z成正比的,这样基本上做的是在Z很近的时候是高精度和Z很远的时候是底精度。这样就是模拟了人眼观察,近处的物体很清晰,而远处的物体很模糊。
深度冲突
两个平面或三角形很紧密相互平行,深度缓冲区不具有足够的精度以至于无法得到哪一个靠前。导致了着两个形状不断切换顺序出现怪异问题。这被称为深度冲突(Z-fighting),因为它看上去像形状争夺顶靠前的位置。
解决方法
让物体之间不要离得太近。
尽可能把近平面设置得远一些。
放弃一部分性能来获得更高精度的深度值。
深度测试总结
使用深度缓冲区最重要的两个值:当前深度缓冲区值(ZBufferValue)和深度参考值(referenceValue),并通过比较操作获取理想渲染效果。
Unity中的渲染顺序:先渲染不透明物体,顺序是从前到后;在渲染透明物体,顺序是从后到前。
通过ZWrite和ZTest组合使用控制半透明物体的渲染。
引入Early-Z技术后的深度测试相关的渲染流程。
深度缓冲区中储存的深度值为0-1范围的浮点数,且为非线性,大多数精度都是24位。