一、深度测试DepthTest
1.传统渲染管线中的深度测试
深度测试在逐片元操作中的第二步
2.解决物体可见遮挡性的问题
3.深度测试的逻辑
for(each triangle T) //对每一个三角形
{
for(each fragment(x,y,z) in T)//对每一个三角形中的片元
{
if(fragment.z < ZBuffer[x,y])//深度测试:如果片元深度小于ZBuffer深度
{
FrameBuffer[x,y] = fragment.rgb; //更新颜色
ZBuffer[x,y] = fragment.z; //更新深度
}
else
{
//深度测试失败
//什么都不做,片元数据被丢弃
}
}
}
4.深度测试带来的问题
物体2与物体3的计算得到的片元都将会被丢弃
先将1、2、3进行片元着色后,在进行深度测试后抛弃2、3,则2、3在片元部分做的计算都浪费掉了。
二、提前深度测试Early-Z
应用阶段(CPU)->几何阶段(顶点着色器)->early-z(提前深度测试)->光栅化阶段(片元着色器)->各种测试(深度测试,透明度测试,模板测试等)->颜色缓冲区(buffer)
Early-Z失效:
1. 开启Alpha Test 或 clip/discard 等手动丢弃片元操作
2. 手动修改GPU插值得到的深度
3. 开启Alpha Blend
4. 关闭深度测试Depth Test
如果按照3-2-1顺序渲染测试,Early-Z将不会带来任何优化效果
三、使用Z-Prepass
方式一:双Pass法
- 使用两个Pass:
-
- 在第一个Pass即Z-Prepass中仅仅值写入深度,不计算输出任何颜色。
- 在第二个Pass中关闭深度写入,并且将深度比较函数设置为相等。
动态批处理问题:
DrawCall问题:
方式二:提前分离的PrePass
- 仍然使用两个Pass,但:
-
- 将原先第一个Pass(即Z-Prepass)单独分离出来未单独一个Shader,并先使用这个Shader将整个场景的Opaque的物体渲染一遍。
- 而原先材质只剩下元原先的第二个Pass,仍然关闭深度写入,并且将深度比较函数设置为相等。
例子:使用URP下的RendererFeature
Z-Prepass也是透明渲染的一种解决方案
单Pass不写入深度的透明渲染 第一Z-Prepass写入深度,第二Pass(Ztest Equal)透明渲染
四、Z-Prepass所带来的问题
Z-Prepass的计算消耗