OpenGL 渲染技巧
1提示: 这个挺重要的.在我们公司项目中这些代码还是经常看到.
当我们观察空间任意一个不透明的物体时,只能看到物体朝向我们的部分表面.其余被遮挡的部分我们是看不到的.但是如果把这些不应该看到的面/线不做处理时,就会表示不清,很混乱.并且会产生二义性.
简单说,在旋转的过程中,因为绘制的顺序错乱导致的. 怎么解决?
油画法
“画家算法”表示头脑简单的画家首先绘制距离较远的场景,然后用绘制距离较近的场景覆盖较远的部分。画家算法首先将场景中的多边形根据深度进行排序,然后按照顺序进行描绘。这种方法通常会将不可见的部分覆盖,这样就可以解决可见性问题。
思考:
-
重复部分,反复绘制是否影响性能?
15579944317570.jpg
-
图形重叠,无法分清先后顺序,如何解决?
15579944433592.jpg
画家算法无法处理相互重叠的多边形在有些场合下,画家算法可能无法解决可见性问题。在这个例子中,多边形 A、B、C 互相重叠,我们无法确定哪一个多边形在上面,哪一个在下面,我们也无法确定两个多边形什么时候在三维空间中交叉。在这种情况下必须用一些方法对这些多边形进行切分、排序。
正背面剔除法
背面剔除,顾名思义,就是在渲染的时候,将背对着观察者的面片丢弃,只将正面朝向观察者(观察者能看到的)面片进行计算。
举个例子:我们显示的立方体盒子,不管从哪个角度看,我们最多只能看到3个面,有时甚至都只能看到一个面,那么,为什么我们还要对其他看不见的面进行渲染计算呢?将看不见的面剔除,我们最少可以节省50%的CPU和GPU资源。
其实问题就是如何判断是正面/背面.我们采用的方法是:定义一个顶点绕序来标识成正面,这样,OpenGL在渲染的时候如果看到这个面的顶点绕序不是正面绕序,那就判定其实背面,把它丢弃。
15579945892386.jpg- 左侧三角形顶点顺序为: 1—> 2—> 3 ; 右侧三角形的顶点顺序为: 1—> 2—> 3 .
- 当观察者在右侧时,则右边的三角形方向为逆时针方向则为正面,而左侧的三角形为顺时针则为.面
- 当观察者在左侧时,则左边的三角形为逆时针方向判定为正面,而右侧的三角形为顺时针判定为背面.
正面和背面是有三角形的顶点定义顺序和观察者方向共同决定的.随着观察者的角度方向的改变,正面背面也会跟着改变
//开启表面剔除(默认背面剔除)
void glEnable(GL_CULL_FACE);
//关闭表面剔除(默认背面剔除)
void glDisable(GL_CULL_FACE);
//用户选择剔除那个面(正面/背面)
void glCullFace(GLenum mode);
mode参数为: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默认GL_BACK
//用户指定绕序那个为正面
void glFrontFace(GLenum mode);
mode参数为: GL_CW,GL_CCW,默认值:GL_CCW
深度测试
在绘制3D场景的时候,需要确定哪些部分对观察者可见,哪些对观察者不可见。OpenGL使用的是Z-buffer方法,也叫深度缓冲区Depth-buffer。
深度: 深度其实就是该像素点在3D世界中距离摄像机的距离,Z值;深度缓存区,就是一块内存区域,专门存储着每个像素点(绘制在屏幕上的)深度值.深度值(Z值)越大,则离摄像机就越远.
在不使用深度测试的时候,如果我们先绘制一个距离比较近的物理,再绘制距离较远的物理,则距离远的位图因为后绘制,会把距离近的物体覆盖掉. 有了深度缓冲区后,绘制物体的顺序就不那么重要的. 实际上,只要存在深度缓冲区,OpenGL 都会把像素的深度值写入到缓冲区中. 除非调用 glDepthMask(GL_FALSE).来禁止写入.
默认情况下,深度缓冲是关闭的,使用时需要显示启用
深度缓冲区(Detph buffer)同颜色缓冲区(color buffer)是对应的,颜色缓冲区存储的像素的颜色信息,而深度缓冲区存储像素的深度信息。在决定是否绘制一个物体的表面时,首先将表面对应像素的深度值与当前深度缓冲区中的值进行比较,如果大于等于深度缓冲区中值,则丢弃这部分;否则利用这个像素对应的深度值和颜色值,分别更新深度缓冲区和颜色缓冲区。这一过程称之为深度测试(Depth Testing)。
深度值一般由16位,24位或者32位值表示,通常是24位。位数越高的话,深度的精确度越好。深度值的范围在[0,1]之间,值越小表示越靠近观察者,值越大表示远离观察者。
//开启深度测试
glEnable(GL_DEPTH_TEST);
//关闭深度测试
glDisable(GL_DEPTH_TEST);
//紧张深度缓存区写入
void glDepthMask(GLBool value);
value : GL_TURE 开启深度缓冲区写入; GL_FALSE 关闭深度缓冲区写入
感谢胖C老师.
网友评论