实践项目:https://github.com/JackieLong/OpenGL/tree/main/project_culling_test
需求场景

从立方体的外部任意角度观察,只能看到最多3个面,完全可以避免绘制其他的面,提升渲染效率。
一个闭合的形状,它的每一个面都有两侧,每一侧要么面向摄像机(眼睛、观察者),要么背对摄像机。OpenGL通过面剔除(Face Culling)来实现只绘制面向观察者的面。
OpenGL能够检查所有面向(Front Facing)观察者的面,并渲染它们,而丢弃那些背向(Back Facing)的面,节省我们很多的片段着色器调用(它们的开销很大!)。但我们仍要告诉OpenGL哪些面是正向面(Front Face),哪些面是背向面(Back Face)。OpenGL使用了一个很聪明的技巧,分析顶点数据的环绕顺序(Winding Order)。
环绕顺序
在程序代码中,我们会按一定顺序定义如下图两个三角形:
// 顶点的定义顺序就是顶点的绘制顺序const GLfloat vertices[] = {// 三角形(左),顶点绘制顺序:1->2->3,顺时针(clock-wise,CW)vertices[0], // 顶点1vertices[1], // 顶点2vertices[2], // 顶点3// 三角形(右),顶点绘制顺序:1->3->2,逆时针(counter clock-wise,CCW)vertices[0], // 顶点1vertices[2], // 顶点3vertices[1] // 顶点2};
相关API
glEnable(GL_CULL_FACE); // 开启面剔除,默认不开启glFrontFace(mode); // 定义“Front Face”// mode的可能取值如下:// GL_CW: 顶点绘制顺序是顺指针的面是“Front Face”// GL_CCW: 顶点绘制顺序是逆指针的面是“Front Face”,默认值glCullFace(mode); // 剔除朝向摄像机的面。// GL_BACK: 剔除朝向摄像机的背面,默认值// GL_FRONT: 剔除朝向摄像的正面// GL_FRONT_AND_BACK: 都剔除。
具体如何调用,由三角形顶点数据的定义顺序决定:
// 按顺时针定义立方体的六个面的正面(朝外的面)float cubeVertices[] = {// Back face-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // Bottom-left0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // bottom-right0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // bottom-left-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // top-left// Front face-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-right0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // top-right0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // top-right-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // top-left-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left// Left face-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-right-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-left-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-left-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-left-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-right-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-right// Right face0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-left0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-right0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-right0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-left0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left// Bottom face-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // top-right0.5f, -0.5f, -0.5f, 1.0f, 1.0f, // top-left0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-left0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-left-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-right-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // top-right// Top face-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // top-left0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // bottom-right0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // bottom-right-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // top-left-0.5f, 0.5f, 0.5f, 0.0f, 0.0f // bottom-left};// 此时,朝外的面都是顺时针绘制,我们可以如下调用:glEnable(GL_CULLING);glFrontFace(GL_CW);glCullFace(GL_BACK);// 或者glEnable(GL_CULLING);glFrontFace(GL_CCW);glCullFace(GL_FRONT);
