一、隐藏面消除
在绘制3D场景的时候,我们需要决定哪些部分对观察者是可见的,或者说哪些部分对观察者不可见,对于不可见的部分,我们应该及早的丢弃,例如在一个不透明的墙壁后的物体就不应该渲染。这种问题称之为隐藏面消除(Hidden surface elimination),或者称之为找出可见面(Visible surface detemination)。
二、隐藏面消除算法
1.画家算法
隐藏面消除比较简单的做法是画家算法(painter’s algorithm)。画家算法的基本思路是,先绘制场景中离观察者较远的物体,再绘制较近的物体。例如绘制下面图中的物体(来自Z buffer 和 W buffer 簡介),先绘制红色部分,再绘制黄色,最后绘制灰色部分,即可解决隐藏面消除问题。
使用画家算法时,只要将场景中物体按照离观察者的距离远近排序,由远及近的绘制即可。画家算法很简单,但另一方面也存在缺陷,例如下面的图中,三个三角形互相重叠的情况,画家算法将无法处理:
2.Z-buffer
OpenGL存储它的所有深度信息于一个Z缓冲(Z-buffer)中,也被称为深度缓冲(Depth Buffer)。GLFW会自动为你生成这样一个缓冲(就像它也有一个颜色缓冲来存储输出图像的颜色)。深度值存储在每个片段里面(作为片段的z值),当片段想要输出它的颜色时,OpenGL会将它的深度值和z缓冲进行比较,如果当前的片段在其它片段之后,它将会被丢弃,否则将会覆盖。这个过程称为深度测试(Depth Testing),它是由OpenGL自动完成的。
(1)深度测试
深度测试默认是禁用的,所以如果要启用深度测试的话,我们需要用GL_DEPTH_TEST选项来启用它:
glEnable(GL_DEPTH_TEST);
当它启用的时候,如果一个片段通过了深度测试的话,OpenGL会在深度缓冲中储存该片段的z值;如果没有通过深度缓冲,则会丢弃该片段。如果你启用了深度缓冲,你还应该在每个渲染迭代之前使用GL_DEPTH_BUFFER_BIT来清除深度缓冲,否则你仍在使用上一次渲染迭代中写入的深度值:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
清除深度缓冲区的默认值是1.0,表示最大的深度值,深度值的范围在[0.0,1.0]之间,值越小表示越靠近观察者,值越大表示远离观察者。
(2)应用场景
绘制天空盒时,我们需要将它变为场景中的第一个渲染的物体,并且禁用深度写入。这样子天空盒就会永远被绘制在其它物体的背后了。
当接下来绘制的元素不想被当前场景中的元素覆盖(当前场景有个平面,如接下来绘制的元素位置在平面下方,但我们想让该元素在平面上方显示),可以在绘制该元素时禁用深度测试。(禁用深度测试后,当前场景的所有元素深度值都是1.0,离摄像头最远。)