第三十三章 深度测试总结

渲染一个物体,可以用深度缓冲来防止被阻挡的面渲染到其他面的前面。
深度缓冲就像是颜色缓冲一样,在每个片段中存储了信息,通常和颜色缓冲有一样的宽度和高度。在大部分的系统中,深度缓冲的精度是24位,以float的形式存储它的深度值。

深度测试被启用的时候,OpenGL会将一个片段的深度值与深度缓冲的内容进行对比,如果在OpenGL执行的深度测试后,通过了则会将其更新为新的深度值,如果测试失败,则片段被丢弃。
深度缓冲是在片段着色器运行之后,也是在模板测试运行之后,在屏幕空间中运行的。屏幕空间坐标与通过OpenGL的glViewport所定义的视口密切相关,可以直接使用GLSL 内建变量gl_FragCoord从片段着色器直接访问。该函数的x和y分量代表了片段的屏幕空间坐标(0,0是左下角)。注意:gl_FragCoord中包含一个z分量,包含了片段真正的深度值。z值就是需要与深度缓冲内容所对比的值。

补充:大部分的GPU都提供一个提前深度测试的硬件特性。允许深度测试在片段着色器之前运行。只要清楚一个片段永远不会是可见的,则就可以提前丢弃这个片段。片段着色器的开销较大,应尽可能避免运行它们。当使用提前深度测试时,片段着色器的一个限制是不能写入片段的深度值。

深度测试默认禁用的,要启用的话,需要使用函数glEnable:
glEnable(GL_DEPTH_TEST);
启用后,如果一个片段通过了深度测试,则OpenGL会在深度缓冲中存储该片段的z值;如果没有通过深度缓冲,则会丢弃该片段。如果启用了深度缓冲,还应该在每个渲染迭代之前使用GL_DEPTH_BUFFER_BIT来清除深度缓冲,否则会还在使用上一次渲染迭代中的写入的深度值:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
当然,在某些情况下需要对所有片段都执行深度测试并丢弃相应的片段,但不希望更新深度缓冲。这么做得话,代表你只在使用一个只读的深度缓冲。这中需要:设置深度掩码(Depth Mask)设置为GL_FALSE即可:glDepthMask(GL_FLASE);
只有在深度测试被启用后才有效果。

下面看下深度测试函数:
OpenGL允许修改深度测试中使用的比较运算符,允许控制OpenGL什么时候该通过或丢弃一个片段,什么时候去更新深度缓冲:glDepthFunc(GL_LESS);
还有以下比较运算符:
GL_ALWAYS 永远通过深度测试
GL_NEVER 永远不通过深度测试
GL_LESS 在片段深度值小于缓冲的深度值时通过测试
GL_EQUAL 在片段深度值等于缓冲区的深度值时通过测试
GL_LEQUAL 在片段深度值小于等于缓冲区的深度值时通过测试
GL_GREATER 在片段深度值大于缓冲区的深度值时通过测试
GL_NOTEQUAL 在片段深度值不等于缓冲区的深度值时通过测试
GL_GEQUAL 在片段深度值大于等于缓冲区的深度值时通过测试

默认情况下使用的深度函数是GL_LESS,它将会丢弃深度值大于等于当前深度缓冲值的所有片段。

下面看下深度值精度:
深度缓冲是0-1之间的深度值,将会与观察者视角所看到的场景中所有物体的z值进行比较。

观察空间的z值可能是投影平截头体的近平面和远平面之间的任何值。需要把z值变换到[0, 1]直接,一种方法就是线性变换到0-1之间。F=(z-near)/(far-near)
补充:非常近的物体,深度值设置接近0,当物体非常接近远平面,深度值接近1。
当然,线性深度缓冲在实践中不会使用。

需要使用一个非线性的深度方程,与1/z成正比。效果是:在z值很小的时候提供非常高的精度,在z值很远的时候提供更少的精度。F=(1/z-1/near)/(1/far-1/near)

下面看下深度缓冲的可视化:
片段着色器中,内建的gl_FragCoord向量的z值包含了特定片段的深度值。把深度值输出为颜色,就可以看到场景中所有片段的深度值。根据片段的深度值返回一个颜色向量来完成该工作:
void main()
{
FragColor = vec4(vec3(gl_FragCoord.z), 1.0);
}
运行程序后,所有东西都是白色,说明深度值都接近1,因为屏幕空间的深度值是非线性的,片段的深度值会随着距离迅速增加。如果靠近物体,则颜色会逐渐变暗。

可以了解一下怎么让片段的非线性的深度值变成线性的。需要反转深度值的投影变换:首先需要将深度值从0-1变为-1 ~ 1的范围,是标准化设备坐标,在裁剪空间中的。深度值进行归一化,变换坐标到-1 ~ 1:float z = depth *2 -1; 下面使用z值应用逆变换来获取线性的深度值:flaot linearDepth = (2 * near *far)/ (far +near - z * (far - near));
会返回一个near和far之间的深度值。

下面看下深度冲突:
深度冲突指的是:视觉错误,在两个平面或三角形非常紧密地平行排列在一起时,深度缓冲没有足够的精度来决定两个形状哪个在前面,导致两个形状不断地在切换前后顺序,表现出来是两个形状在夺取谁应该处于顶端。
这是深度缓冲一个很常见的问题,当物体在远处时效果会更明显,不能够被完全避免,一般可以减轻或避免深度冲突:
防止深度冲突:不要把多个物体摆的太靠近,以至于一些顶点构成的三角形会重叠。可以在两个物体之间设置一个用户无法注意到的偏移值,可以避免两个物体之间的深度冲突。
还可以将近平面设置的远一些。如果将近平面远离观察者,会对整个平截头体有更大的精度。当然,将近平面设置太远也会导致近处的物体被裁剪掉,通常需要微调来确定近平面的距离。
最后可以牺牲性能,使用更高精度的深度缓冲。可以使用32位的深度缓冲,来获得高精度的深度测试。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值