QT+OPenGL十五之深度缓冲区

深度缓冲区

OpenGL中使用深度缓冲区,来高效解决物体遮挡的问题,即相同屏幕位置离我们最近的片段应该被保留并且记录,而比当前片段更远的片段应该被丢弃,也就是深度算法。OpenGL中默认是关闭深度测试的。也就是物体不会相互遮挡,也就是这个鬼样子:


image.png

明明模型被地形遮挡他却还是被我们看见了。

使用深度缓冲区步骤:
glEnable(GL_DEPTH_TEST);//开启深度缓冲区
 glDepthFunc(GL_LEQUAL);//在片段深度值小于等于缓冲区的深度值时通过测试

如果不更新缓冲区会导致,读取的是上一次的结果。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//OpenGL在绘制完或者渲染的开始处刷新颜色和深度缓冲区。
 glDisable(GL_DEPTH_TEST);//关闭深度缓冲区,如果哪一个模型不需要深度测试可以在绘制它前关闭,绘制后打开。
使用OpenGL深度缓冲区的一些属性

image.png

glDepthFunc()函数中使用这些属性。
默认情况下使用的深度函数是GL_LESS,它将会丢弃深度值大于等于当前深度缓冲值的所有片段。
在某些情况下你会需要对所有片段都执行深度测试并丢弃相应的片段,但不希望更新深度缓冲。可以将缓冲区设置成只读的。glDepthMask(GL_FALSE)在开机缓冲区后立即设置。

深度缓冲区精度:

深度缓冲包含了一个介于0.0和1.0之间的深度值,它将会与观察者视角所看见的场景中所有物体的z值进行比较。也就是和近平面(Near)和远平面(Far)之间的任何值进行比较。

image.png

我们需要一种方式来将这些观察空间的z值变换到[0, 1]范围之间。
为了提高精度我们显然是使用非线性算法。
image.png

由于非线性方程与 1/z 成正比,在1.0和2.0之间的z值将会变换至1.0到0.5之间的深度值,这就是一个float提供给我们的一半精度了,这在z值很小的情况下提供了非常大的精度。在50.0和100.0之间的z值将会只占2%的float精度,这正是我们所需要的。因此要知道他不是线性的。即它在z值很小的时候有很高的精度,而z值很大的时候有较低的精度。片段的深度值会随着距离迅速增加。

深度缓冲区可视化:

shader中(GLSL)内嵌了深度属性在gl_FragCoord的z分量。near和far同样内嵌了。

gl_FragCoord.z;

算法也是默认的,我们既然已经拿到了深度值,自然也可以改变算法。

缓冲冲突

当两个物体排放过近导致,计算机精度无法识别处俩个值的差异,就会导致缓冲冲突。即认为俩个面共面,或者就是共面,这回导致顶端争夺,不知道哪个面在最上面,产生视觉错误。lenrnopengl中讲避免方法:
第一个也是最重要的技巧是永远不要把多个物体摆得太靠近,以至于它们的一些三角形会重叠。通过在两个物体之间设置一个用户无法注意到的偏移值,你可以完全避免这两个物体之间的深度冲突。在箱子和地板的例子中,我们可以将箱子沿着正y轴稍微移动一点。箱子位置的这点微小改变将不太可能被注意到,但它能够完全减少深度冲突的发生。然而,这需要对每个物体都手动调整,并且需要进行彻底的测试来保证场景中没有物体会产生深度冲突。

第二个技巧是尽可能将近平面设置远一些。在前面我们提到了精度在靠近近平面时是非常高的,所以如果我们将近平面远离观察者,我们将会对整个平截头体有着更大的精度。然而,将近平面设置太远将会导致近处的物体被裁剪掉,所以这通常需要实验和微调来决定最适合你的场景的近平面距离。

另外一个很好的技巧是牺牲一些性能,使用更高精度的深度缓冲。大部分深度缓冲的精度都是24位的,但现在大部分的显卡都支持32位的深度缓冲,这将会极大地提高精度。所以,牺牲掉一些性能,你就能获得更高精度的深度测试,减少深度冲突。

我们上面讨论的三个技术是最普遍也是很容易实现的抗深度冲突技术了。还有一些更复杂的技术,但它们依然不能完全消除深度冲突。深度冲突是一个常见的问题,但如果你组合使用了上面列举出来的技术,你可能不会再需要处理深度冲突了。

你可能感兴趣的:(QT+OPenGL十五之深度缓冲区)