当前位置:嗨网首页>书籍在线阅读

16-背面剔除

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

4.11.3 背面剔除

提高渲染效率的另一种方法是利用OpenGL的背面剔除能力。当3D模型完全“闭合”时,意味着内部永远不可见(例如对于立方体和金字塔),那么外表面的那些与观察者背离呈一定角度的部分将始终被同一模型的其他部分遮挡。也就是说,那些背离观察者的三角形不可能被看到(无论如何它们都会在隐藏面消除的过程中被覆盖),因此没有理由光栅化或渲染它们。

我们可以使用命令glEnable(GL_CULL_FACE)要求OpenGL识别并“剔除”(不渲染)背向的三角形。我们还可以使用glDisable(GL_CULL_FACE)禁用背面剔除。默认情况下,背面剔除是关闭的,因此如果您希望OpenGL剔除背向三角形,必须手动启用它。

启用背面剔除时,默认情况下,只有三角形朝前时才会被渲染。此外,默认情况下,如果三角形的3个顶点从OpenGL摄像机中查看是以逆时针顺序排列的(基于它们在缓冲区中定义的顺序),则三角形被视为面向前方。顶点沿顺时针方向排列的三角形(从OpenGL摄像机中看)是朝后的,不会被渲染。这种逆时针方向定义的“前向”有时被称为缠绕顺序,可以使用函数调用glFrontFace(GL_CCW)显式设置逆时针(默认)为正向,或glFrontFace (GL_CW)设置顺时针为正向。类似地,也可以显式设置是否渲染正向或背向的三角形。实际上,为了这个目的,我们指定哪些不被渲染——即哪些被“剔除”。我们可以通过调用glCullFace(GL_BACK)指定面向背面的三角形被剔除(尽管这是不必要的,因为它是默认的)。或者,我们可以通过分别用GL_FRONT或GL_FRONT_AND_BACK替换参数GL_BACK来指定剔除前向三角形,甚至剔除所有三角形。

正如我们将在第6章中看到的那样,3D模型通常被设计成外表面由相同缠绕顺序的三角形构成——最常见的是逆时针——因此如果启用剔除,则默认情况下模型的外部面向相机的表面部分会被渲染。因为默认情况下OpenGL假定的缠绕顺序是逆时针方向,如果模型设计缠绕顺序为顺时针方向,那么如果启用了背面剔除,需要由程序员调用gl_FrontFace (GL_CW)来解决此问题。

注意,在GL_TRIANGLE_STRIP的情况下,每个三角形的缠绕顺序不停地互换。OpenGL通过在构建每个连续三角形时“翻转”顶点序列来补偿这一点,如下所示:0-1-2,然后2-1-3、2-3-4、4-3-5、4-5-6等。

背面剔除通过确保OpenGL不花时间光栅化和渲染从不被看到的表面来提高性能。我们在本章中看到的大多数示例都非常小,以至于没有动机进行背面剔除(图4.9中展示了一个例外,其中包含了100 000个多边形动画实例,这可能会对某些系统造成性能挑战)。在实践中,大多数3D模型通常是“闭合的”,因此习惯上会常规地启用背面剔除。例如,我们可以通过修改display()函数向程序4.3添加背面剔除,如下所示。

void display(GLFWwindow* window, double currentTime) {
   . . .
   glEnable(GL_CULL_FACE);
   // 绘制立方体
   . . .
   glEnable(GL_DEPTH_TEST);
   glDepthFunc(GL_LEQUAL);
   glFrontFace(GL_CW);             // 立方体顶点的缠绕顺序为顺时针方向
   glDrawArrays(GL_TRIANGLES, 0, 36);
   // 绘制金字塔
   . . .
   glEnable(GL_DEPTH_TEST);
   glDepthFunc(GL_LEQUAL);
   glFrontFace(GL_CCW);            // 金字塔顶点缠绕顺序为逆时针方向
   glDrawArrays(GL_TRIANGLES, 0, 18);
}

使用背面剔除时,正确设置缠绕顺序非常重要。不正确的设置,例如当应该设置GL_CCW时设置成了GL_CW,可能会导致渲染出对象的内部而不是其外部,这就会产生类似于不正确的透视矩阵的失真。

效率不是进行背面剔除的唯一原因。在后面的章节中,我们将看到其他用途,例如我们想要查看3D模型内部或使用透明度时的情况。