特征
1. 深度缓冲区具有颜色缓冲区一样的宽度和高度。
2. 深度值以16、24或32位float的形式储存,在大部分系统中为24位。
3. 片段着色器中可访问GLSL内建变量 gl_FragCoord。x和y为片段的屏幕空间坐标,z为深度值。
4. 深度测试在 模版测试之后。
// 深度测试默认禁用,需主动打开
glEnable(GL_DEPTH_TEST);
// 渲染循环中,需清除旧的深度缓冲
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 设置深度缓冲为"只读"。需开启深度测试,设置深度掩码(Depth Mask)为GL_FALSE,此后缓冲区不可修改。
glDepthMask(GL_FALSE);
深度测试函数
即设定片元深度值与深度缓冲区的比较方式。
// 默认情况下使用GL_LESS
glDepthFunc(GL_LESS);
函数 | 描述 |
GL_ALWAYS | 永远通过深度测试 |
GL_NEVER | 永远不通过深度测试 |
GL_LESS | 在片段深度值小于缓冲的深度值时通过测试 |
GL_EQUAL | 在片段深度值等于缓冲区的深度值时通过测试 |
GL_LEQUAL | 在片段深度值小于等于缓冲区的深度值时通过测试 |
GL_GREATER | 在片段深度值大于缓冲区的深度值时通过测试 |
GL_NOTEQUAL | 在片段深度值不等于缓冲区的深度值时通过测试 |
GL_GEQUAL | 在片段深度值大于等于缓冲区的深度值时通过测试 |
深度值精度
线性变换
变换公式:
z值与深度值的关系图:
![](https://img-blog.csdnimg.cn/img_convert/2b4cf6c4ce93830b004a79e1d18ee5ff.png)
深度图可视化:
![](https://img-blog.csdnimg.cn/img_convert/9962a02e31af2ece2d0888853ddb3edc.png)
分析:
1. 实践中是几乎永远不会使用这样的线性深度缓冲(Linear Depth Buffer)的。
2. 一般来说大部分的物体都是靠近近平面的,所以需要提供较大的精度。
3. 由于是线性的,可看到靠的比较近的地方是黑色的,当离得较远的地方有淡淡的灰色。
非线性变换
变换公式:
z值与深度值的关系图:
![](https://img-blog.csdnimg.cn/img_convert/35708a4b740408fdd5022e78c5347fd1.png)
深度图可视化:
![](https://img-blog.csdnimg.cn/img_convert/da2d6299554f8556e22c3118331461c5.png)
分析:
1.在1.0和2.0之间的z值将会变换至1.0到0.5之间的深度值,这就是一个float提供给我们的一半精度了,这在z值很小的情况下提供了非常大的精度。在50.0和100.0之间的z值将会只占2%的float精度。
2. 深度缓冲中的值在屏幕空间中不是线性的(在透视矩阵应用之前在观察空间中是线性的)。
3. 从图中可看到,只有距离立方体非常的近的距离,才能观察到变暗的效果,其他地方基本为白色。
深度值的非线性与线性的转换
// 首先将深度值变换为NDC
float z = depth * 2.0 - 1.0;
// 应用逆变换来获取线性的深度值
float linearDepth = (2.0 * near * far) / (far + near - z * (far - near));
深度冲突(Z-fighting)
原理
1.当两个待渲染物体的三角形网格比较接近,几乎平行排列在一起时会发生深度冲突
2. 又或者是离得较远的物体,由于深度值精度不够,导致计算之后具有相同的深度值。
其本质是深度缓冲没有足够的精度来决定哪个三角形在前面显示,于是这两个三角形会不断地在切换前后顺序导致闪烁。
解决方法
永远不要把多个物体摆得太靠近,以至于它们的一些三角形会重叠。
调整近平面与远平面之间的距离。
使用更高精度的深度缓冲。
Reversed Z
该方法是用于缓解决Z-fighting问题。
当z-buffer中的归一化的深度值属于[0, 1]范围内时,可使用该方法:
原本d = 0 对应near plane,d = 1对应 far plane。
改为 d = 0 对应far plane,d = 1对应 near plane。
原因如下:
1. 由于投影矩阵变幻后,ndc坐标z值并非线性变化的。接近近平面时,精度高,接近远平面时,精度低。
2. 浮点数自身在接近0 时精度是最高的。因此可以把far plane 对应到 d = 0,near plane对应到d = 1。从而可以一定程度上进行缓解。