Vries的教程是我看过的最好的可编程管线OpenGL教程,没有之一,其原地址如下,https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/04%20Face%20culling/ 关于面剔除的详细知识了解请看原教程,本篇旨在对Vires基于visual studio平台的编程思想与c++代码做纯Qt平台的移植,代码移植顺序基本按照原教程顺序,并附加一些学习心得,重在记录自身学习之用
- Tip1:这节Vries没有提供源代码,因为代码没有新的内容,只是很简单的调换了下立方体的顶点数据顺序,与开启面剔除测试。
- Tip2:这节的Qt代码移植没有需要注意的地方,直接使用OpenGL原函数即可。
程序源代码链接:https://pan.baidu.com/s/1lZ40oN77BZdu8MEd04nVVw 提取码:3z5a
编译环境:Qt5.9.4
编译器:Desktop Qt5.9.4 MSVC2017 64bit
IDE:QtCreator
一.面剔除
顾名思义,面剔除是将渲染时看不见的一些面进行丢弃,以此来节约资源的使用,以图1为例。
我们换成线框模式进行观察,普通渲染模式下的立方体是具有六个面的,如图2所示,当开启面剔除时,在这个观察视角下,看不见的背面等三个面会进行丢弃,不再显示,如图3所示。
二.环绕顺序
面剔除是个很强大的功能与节约资源的办法,OpenGL依靠组成一个面的顶点环绕顺序,确立这个面在当前视角下是否看得见。它规定,所有从视角出发,顺时针顺序的面为不可见面(丢弃面),逆时针为可见面。
看起来,这个顶点顺序很难控制,这里有一个窍门,每当生成一个面时,我们应该假设要生成的这个面正对着我们,然后总是以逆时针的顺序进行绘制,举例说明。
生成A三角形时,用一些抽象思维,假设我们处于正对A三角形的方向O,这时以逆时针顺序1,2,3绘制这个三角形。绘制B三角形时,同样架设我们处于正对B三角形的方向O',同样以逆时针顺序1,2,3绘制三角形。
好了,现在让我们的场景开始渲染,人眼处为我们的观察位置,在这个视角下,A三角形绘制顺序1,2,3,是逆时针的,可见。B三角形绘制顺序1,2,3,但在这个视角下,却是顺时针的,故不可见。
故我们如果需要开启面剔除,必须注意面的绘制顺序。
这是Vries总结的立方体逆时针绘制顺序:
float vertices[] = {
// positions // textures // normals
//Back Face
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, //bottom-left
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, //top-right
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f,
//Front Face
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
//Left Face
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f,
//Right Face
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
//Bottom Face
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f,
//Top Face
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};
三.函数
与面剔除相关的由三个控制函数:
1. glEnable(GL_CULL_FACE); 开启面剔除模式,该模式默认是关闭状态,
2. glCullFace(GL_FRONT);设置剔除面为正向面,默认提出面为背向面
该函数参数有三个选项:
GL_BACK, 只剔除背向面
GL_FRONT,只剔除正向面
GL_FRONT_AND_BACK,剔除正向面和背向面
3. glFrontFace(GL_CW); 设置顺时针顺序为正向面,默认逆时针GL_CCW为正向面。