深度测试
这一章提到了之前的深度函数,首先要开启深度测试,然后要在loop中及时清除深度
glEnable(GL_DEPTH_TEST);
...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
通过开启深度测试,画面就会正常显示点与点的位置信息,里屏幕近的物体会覆盖远的物体。
也就是z-buffer,用来确定一个片段是否在其他片段后方的。
当深度测试(Depth Testing)被启用的时候,OpenGL会将一个片段的深度值与深度缓冲的内容进行对比。OpenGL会执行一个深度测试,如果这个测试通过了的话,深度缓冲将会更新为新的深度值。如果深度测试失败了,片段将会被丢弃。
一般来说 深度测试在着色器运行之后的,也就是说先把点的颜色得到,再看要不要丢弃,这种做法比较浪费资源,所有也有提前深度测试的方法。
从这段也可以知道,再片段着色器工作时不仅会确定颜色,而且会有x,y,z。
还有一种,就是我已经有一个深度缓冲,我不想再修改他了,那就通过下面这个把深度缓冲变成只读就行。
深度测试函数
这样就比较自由了,我们可以控制如何丢弃片段。不过一般都是less。
如果改成GL_ALWAYS的话,画面就会按照绘制的顺序来进行覆盖画面。
深度缓冲的精度
我们需要把世界坐标中的物体坐标以及视角屏幕之间的距离做一个变换到0-1上,但是我们一般不会用线性的,而是用非线性的1/z,这是为什么呢,因为离得很远的时候,我不需要那么大的精度来计算谁在前面谁在后面,而越靠近屏幕我的精度要求就越高。
可视化
我们试试把深度z可视化吧,之前提到过gl_fragcoord中会包含x,y,z,其中z就是深度。我们把深度通过颜色显示出来
FragColor = vec4(vec3(gl_FragCoord.z),1.0f);
先看远处,可以看到基本就是全白,但是近处的这里立方体不是那么的白,就是前面的非线性深度,越靠近屏幕就会越暗,比1小。
深度冲突
当把两个物体放的很近的时候,或者说一个箱子放在地板上,那么箱子的底面和地板的深度是一样的,这个时候不知道显示哪个就会导致画面闪烁。
那么如何避免呢?
1.不要把物体放的太近。通过在两个物体之间设置一个用户无法注意到的偏移值,你可以完全避免这两个物体之间的深度冲突。在箱子和地板的例子中,我们可以将箱子沿着正y轴稍微移动一点。箱子位置的这点微小改变将不太可能被注意到,但它能够完全减少深度冲突的发生。然而,这需要对每个物体都手动调整,并且需要进行彻底的测试来保证场景中没有物体会产生深度冲突。
2.尽可能将近平面设置远一些。这什么意思呢?因为在前面我们提到了精度在靠近近平面时是非常高的,所以如果我们将近平面远离观察者,我们将会对整个平截头体有着更大的精度。
3.使用更高精度的深度缓冲