OpenGL学习脚印:背面剔除(Face Culling)
写在前面
在绘制封闭类型的几何对象时,开启背面剔除功能能够提高渲染性能。本节简要介绍下背面剔除,示例程序可以在我的github下载。
什么是背面剔除
当我们观察场景中对象时,一般只能以一定角度来观察,那么对象的某些面我们是看不到的,例如你观察一个立方体,最多只能同时看到3个面,有时只能看到1个面,而我们绘制时如果不采取剔除背面的措施,则要绘制6个面,其中包括一些,我们根本看不到的面。对于立方体这个面较少的几何对象,性能开销不明显,但是对于复杂的模型,开启背面剔除则能明显改善渲染性能。 背面剔除,就是早点丢弃对观察者来说是背面的片元的一种方法。
背面剔除的使用
上面提到,要早点丢弃对观察者来说是背面的片元,那么现在的问题是如何确定哪个面是背面的问题? OpenGL中使用顶点绕序(winding order)来确定。所谓绕序就是当几何对象细分为三角形时,三角形顶点相对于中心的定义顺序,具体如下图所示(来自opengl wiki):
左边的图中指定顶点的顺序是顺时针的,右边是逆时针的。
以三角面指向观察者的方向为大拇指指向,其余手指逆时针绕着大拇指,如果手指的绕向和三角面顶点绕向一致,则这个面为正面,否则为背面。
在OpenGL中,我们指定逆时针和顺时针的三角形顶点如下:
GLfloat vertices[] = {
// Clockwise
vertices[0], // vertex 1
vertices[1], // vertex 2
vertices[2], // vertex 3
// Counter-clockwise
vertices[0], // vertex 1
vertices[2], // vertex 3
vertices[1] // vertex 2
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
需要注意的是,三角形的正面还是背面这个是根据观察者的观察方向,而变动的。例如下面的图中(来自www.learnopengl.com):
左侧的三角形顶点顺序为1->2->3,右侧的三角形顶点顺序为1->2->3。当观察者在右侧时,则右边的三角形方向为逆时针方向为正面,而左侧的三角形为顺时针则为背面;当观察者转到左侧时,左侧的三角形为逆时针绕序判定为正面,而右侧的三角形为顺时针绕序判定为背面。可以看出正面和背面是由三角形的顶点定义顺序和观察者的观察方向共同决定的,而且随着观察方向的改变,正面和背面将会跟着改变。
在OpenGL中开启背面剔除需要使用:
glEnable(GL_CULL_FACE);
- 1
同时OpenGL提供了函数glCullFace来供用户选择剔除哪个面:
API void glCullFace(GLenum mode);
mode参数为 GL_FRONT, GL_BACK, GL_FRONT_AND_BACK 3个枚举类型。默认为GL_BACK.
以及glFrontFace函数用来根据绕序指定哪个为正面:
API void glFrontFace(GLenum mode);
mode参数为GL_CW ,GL_CCW。默认值是GL_CCW。
如果要剔除正面,代码:
glCullFace(GL_BACK);
glFrontFace(GL_CW);
- 1
- 2
和下面的代码等价:
glCullFace(GL_FRONT);
- 1
首先我们来对比下使用背面剔除和未使用背面剔除时,穿过立方体内部,我们看到的景象。下图是没有开启背面剔除时:
可以看到,穿过内部时,看到了立方体后面的部分。当开启了背面剔除时,穿过内部时,看不到立方体的背面:
当我们剔除正面时,观察者的位置,决定了哪是正面,当观察者处于立方体正面时,剔除正面看到效果:
当观察者移动到可以看到立方体三个面时,判定正面,顶面和右侧面为正面,则剔除正面后的效果为:
最后的说明
在使用背面剔除时需要注意,在指定物体表面的顶点时,顶点的顺序需要定义为正向的逆时针顺序。启用背面剔除一般而言总能改善渲染性能,但是具体是否开启背面剔除还是要根据应用场景而定。当渲染某些非封闭类型几何对象,例如一颗草的模型时,则不需要开启背面剔除。
OpenGL学习脚印:背面剔除(Face Culling)的更多相关文章
- OpenGL学习脚印:深度測试(depth testing)
写在前面 上一节我们使用AssImp载入了3d模型,效果已经令人激动了.可是绘制效率和场景真实感还存在不足,接下来我们还是要保持耐心,继续学习一些高级主题,等学完后面的高级主题,我们再次来改进我们载入 ...
- OpenGL学习脚印: uniform blocks在着色器中的使用 转自https://blog.csdn.net/wangdingqiaoit/article/details/52717963
写在前面 目前,我们在着色器中要传递多个uniform变量时,总是使用多个uniform,然后在主程序中设置这些变量的值:同时如果要在多个shader之间共享变量,例如投影矩阵projection和视 ...
- Qt OpenGL:学习现代3D图形编程之四,透视投影浅析
一.非真实的世界 与之前几篇文章不同的是,这里要画12个三角形,这个12个三角形构造一个方形棱柱(这里为长方体).棱柱的每个四边形表面由两个三角形组成.这两个三角形其中的一条边重合,而且它们的六个顶点 ...
- OPENGL——背面剔除
Opengl 表面剔除是提高 Opengl 程序渲染效率的一个有效途径. 我们知道,OpenGL 渲染的基本单位是一个个的三角形面片.无论多么复杂的3D 模 型都是由一个个基本的三角型的面片组成的. ...
- OpenGL 背面剔除
在OpenGL种可使用glEnable(GL_CULL_FACE)开启背面剔除功能,即把那些我们看不见的面删除.但在剔除之前我们需要定义正面和背面,这个可以用法线来理解.在数学学科中,法线是用右手法则 ...
- OpenGL学习进程(11)第八课:颜色绘制的详解
本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿. (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. R ...
- OpenGL学习进程(8)第六课:点、边和图形(三)绘制图形
本节是OpenGL学习的第六个课时,下面介绍OpenGL图形的相关知识: (1)多边形的概念: 多边形是由多条线段首尾相连而形成的闭合区域.OpenGL规定,一个多边形必须是一个“凸多边形”. ...
- OpenGL学习进程(10)第七课:四边形绘制与动画基础
本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识: (1)绘制几种不同的四边形: 1)四边形(GL_QUADS) OpenGL的GL_QUADS图 ...
- OpenGL学习进程(9)在3D空间的绘制实例
本节将演示在3D空间中绘制图形的几个简单实例: (1)在3D空间内绘制圆锥体: #include <GL/glut.h> #include <math.h> # ...
随机推荐
- linux进阶与hadoop
Linux进阶命令: find . | ls --help | more grep ll | grep 1.txt grep -ri BASH 1.txt grep -ri BASH ...
- openLDAP 2
一.安装OPENLDAP 二.打开安装目录中的文件 slapd.conf 三.安装完成后退出 编辑文本,输入以下内容,并命名为test.ldif dn: dc=company objectClass: ...
- 什么是展uv
uvw是对应三维模型x.y.z坐标,就像模型的皮肤一样,为了便于绘制贴图,需要将UV尽量展平 展UV就是把你建好的模型展开成平面,别人就可以在那平面上做材质,皮肤等,这些东西.例如展一个正方体的UV, ...
- android-tip-关于SurfaceView的使用
1. SurfaceView的创建和销毁 当SurfaceView隐藏时,SurfaceView被销毁,此时会调用SurfaceHolder.Callback.surfaceDestroyed ...
- 关于《Spark快速大数据分析》运行例子遇到的报错及解决
一.描述 在书中第二章,有一个例子,构建完之后,运行: ${SPARK_HOME}/bin/spark-submit --class com.oreilly.learningsparkexamples ...
- loadrunner-27077报错解决办法
警告 -27077: “每次迭代模拟一个新用户”运行时设置为“开”时,“vuser_init”节将包含 Web 函数.这可能会产生具有多次迭代的不可预测结果 [MsgId: MWAR-27077] ...
- HBase列族高级配置
转自:http://blog.sina.com.cn/s/blog_ae33b83901018euz.html ------------------ HBase有几个高级特性,在你设计表时可以使用.这 ...
- Servlet面试题
Servlet运行在Servlet容器中,其生命周期由容器来管理.Servlet的生命周期通过javax.servlet.Servlet接口中的init().service()和destroy()方法 ...
- [GO]匿名函数和defer
package main import "fmt" func main() { a := 10 b := 20 defer func() { fmt.Printf("a ...
- 编写高质量代码改善C#程序的157个建议——建议99:重写时不应使用子类参数
建议99:重写时不应使用子类参数 重写时,如果使用了子类参数,可能会偏离设计者的预期目标.比如,存在一个如下继承体系: class Employee { } class Manager : Emplo ...