背面剔除 就是对几何体的背面,我们看不到的三角形进行剔除,以便提高性能
我们先来看一个没有背面剔除的例子
这是一个类似于游泳圈的模型,稍微的对其旋转了一下,从侧面看到的效果如下图:
我们看到有一些黑色的线条 这是因为在没有开启 背面剔除 模式的情况下,三角形的排序可能会出现混乱,从而造成这种现象。
我们来看看怎么来写这个例子
工程的创建在前面已经讲过了
首先 头文件部分
<pre name="code" class="cpp">#include <GLTools.h> // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <math.h>
#define FREEGLUT_STATI
#include <GL/glut.h>
全局变量部分
GLFrame viewFrame;
GLFrustum viewFrustum;//视景体
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatix; //模型视图矩阵
GLMatrixStack projectionMatrix; //投影矩阵
GLGeometryTransform transformPipeline;//几何变换管线
GLShaderManager shaderManager;
main函数,几乎和前面没有区别 只是多了一行 用来检测键盘方向键的按下,从而旋转泳圈模型的
<pre name="code" class="cpp">int main(int argc, char* argv[]){
//设置当前工作目录
gltSetWorkingDirectory(argv[0]);
//初始化GLUT库
glutInit(&argc, argv);
//告诉GLUT在创建窗口时要使用哪种类型的窗口显示模式,这里只简单的设置为RGBA颜色模式,双缓冲模式
//双缓冲模式就是图形先渲染到后台缓冲区,然后再调用glutSwapBuffers()一起渲染到前台缓冲区
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);
//要创建的窗口大小
glutInitWindowSize(800, 600);
//要创建的窗口标题
glutCreateWindow("Primitices");
//窗口大小改变时的回调函数
glutReshapeFunc(ChangeSize);
//渲染的回调函数
glutDisplayFunc(RenderScene);
//检测键盘方向键按下的回调函数
glutSpecialFunc(SpecialKeys);
其中ChangeSize和RenderScene函数稍后再讲
//初始化GLEW库,这个库被封装在GLTools中,主要调用OPenGL的一些接口
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
//初始化函数,用于创建渲染环境,初始化数据等,这个函数在后面实现
SetupRC();
//开始主消息循环
glutMainLoop();
return 0;
}
初始化函数 SetupRC()
void SetupRC()
{
// Black background
glClearColor(0.3f, 0.3f, 0.3f, 1.0f );
//初始化着色器管理类
shaderManager.InitializeStockShaders();
//把模型延Z轴的负方向移动7个单位
viewFrame.MoveForward(7.0f);
// gltMakeTorus函数会创建一个泳圈模型的数据,并保存在torusBatch中 随后我们调用torusBatch.Draw() 即可绘制出泳圈模型
gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
//设置点的大小
glPointSize(4.0f);
}
//下面是窗口改变的回调函数ChangeSize
void ChangeSize(int w, int h)
{
// Prevent a divide by zero
if(h == 0)
h = 1;
// 设置视口大小
glViewport(0, 0, w, h);
//创建投影矩阵,并将它载入到投影矩阵堆栈中
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//把模型视图矩阵 和 投影矩阵 设置到管理管线的对象transformPipeline中 以便对模型视图矩阵 和 投影矩阵 进行管理
transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}
//下面是渲染函数 RenderScene
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 开启背面剔除
glEnable(GL_CULL_FACE);
//glDisable(GL_CULL_FACE);
//设置模型视图矩阵
modelViewMatix.PushMatrix(viewFrame);
//设置着色器
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vRed);
//绘制泳圈模型
torusBatch.Draw();
//回复模型视图矩阵
modelViewMatix.PopMatrix();
glutSwapBuffers();
}
//下面是响应键盘按键的函数SpecialKeys
void SpecialKeys(int key, int x, int y)
{
//其中RotateWorld标示把角度转换为弧度
//这里把旋转矩阵放在对象viewFrame中 在渲染函数 RenderScene函数 中
//通过modelViewMatix.PushMatrix(viewFrame) 来使用该旋转矩阵
//绕x转-5度
if(key == GLUT_KEY_UP)
viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);
//绕x转5度
if(key == GLUT_KEY_DOWN)
viewFrame.RotateWorld(m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);
//绕y转-5度
if(key == GLUT_KEY_LEFT)
viewFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);
//绕y转5度
if(key == GLUT_KEY_RIGHT)
viewFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f);
// 刷新窗口
glutPostRedisplay();
}
大家注意到 在渲染函数RenderScene中有这样一句
// 开启背面剔除
glEnable(GL_CULL_FACE);
这样就开启了背面剔除功能 关闭背面剔除函数
glDisable(GL_CULL_FACE);
开启背面剔除 效果如下图
不在有黑色的线条了