在绘制3D场景的时候,我们需要决定哪些部分是对观察者 可⻅的,或者哪些部分是对观察者不可⻅的.对于不可见的部分,应该及早丢弃.例如在⼀个不透明的墙壁后,就不应该渲染.这种情况叫做”隐藏面消除”(Hidden surface elimination).
当我们去看一个正方体时,只能最多看到3个面,正方体有6个面,那么其他3个面是看不到的,那么也不需要渲染。所以,我们只需要渲染我们看到的3个面!
那么怎么判断那些面是可见的,哪些面是不可见的呢?即如何告诉OpenGL哪些面是正面。哪些面是反面?
答案就是通过分析顶点数据的顺序
正⾯和背面是有三角形的顶点定义顺序和观察者方向共同决定的.随着观察者的⻆度方向的改变,正面背面也会跟着改变。
从而引入OpenGL的正背面剔除概念
void glEnable(GL_CULL_FACE);
void glDisable(GL_CULL_FACE);
void glCullFace(GLenum mode);
//model参数为: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK,默认GL_BACK
void glFrontFace(GLenum mode);
//mode参数为:GL_CW,GL_CCW,默认是为GL_CCW
代码举例:
glCullFace(GL_BACK);
glFrontFace(GL_CW);
void glCullFace(GL_FRONT);
深度其实就是该像素点在3D世界坐标系中,距离摄像机的距离,Z值
深度缓冲区,为一块内存区域,专门存储着每个像素点的深度值。深度值(Z值)越大,即像素点离摄像机越远,那当我们没有开启混合(Blend)的时候,两张图片在同一像素点有不同的Z值,那么我们会舍弃Z值较大的,渲染并显示Z值较小的。
在不使用深度测试的时候,如果我们先绘制一个距离比较近的物体,再绘制距离较远的物体,则距离远的位图因为后绘制,会把距离近的物体覆盖掉. 有了深度缓冲区后,绘制物体的顺序就不那么重要了. 实际上,只要存在深度缓冲区,OpenGL 都会把像素的深度值写⼊到缓冲区中. 除⾮调⽤ glDepthMask(GL_FALSE).来禁⽌写入.
那么深度测试在这种背景下产生了,他会比较同一个像素点的深度大小,来决定是否显示
深度缓冲区(DepthBuffer)和颜色缓存区(ColorBuffer)是对应的.颜色缓存区存储像素的颜色信息,⽽深度缓冲区存储像素的深度信息. 在决定是否绘制一个物体表面时, ⾸先要将表面对应的像素的深度值与当前深度缓冲区中的值进行比较. 如果大于深度缓冲区中的值,则丢弃这部分.否则 利用这个像素对应的深度值和颜色值.分别更新深度缓冲区和颜色缓存区. 这个过程称为”深度测 试”
深度值一般由16位,24位或者32位值表示,位数越多越精确。值的范围位于[0,1]之间
但是我们通常设置Z值是不在[0,1]范围内的,那么就需要将Z值转换成深度值,下面的线性方程转换成深度值
这的far和near参考下图中的观察者坐标系
但正确投影特性的非线性深度方程是和1/z成正比的,非线性方程和1/z成正比
当z值越大时,越接近于1,并且当深度精度越大时,越准确
glEnable(GL_DEPTH_TEST);
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
void glDepthFunc(GLEnum mode);
void glDepthMask(GLBool value);
value : GL_TURE 开启深度缓冲区写⼊入; GL_FALSE 关闭深度缓冲区写⼊入
由于深度值是有精度的,当精度不够的时候,OpenGL就不能很好的区分深度值,如下图的重叠部分,深度值很接近,就会出现图片闪烁,上下交替。
让深度值之间产⽣间隔.如果2个图形之间有间隔,是不是意味着就不会产⽣生干涉.可以理解为在执行深度测试前将⽴方体的深度值做⼀些细微的增加.于是就能将重叠的2个图形深度值之前有所区分.
//启⽤用Polygon Offset ⽅方式
glEnable(GL_POLYGON_OFFSET_FILL)
参数列列表:
GL_POLYGON_OFFSET_POINT 对应光栅化模式: GL_POINT
GL_POLYGON_OFFSET_LINE 对应光栅化模式: GL_LINE
GL_POLYGON_OFFSET_FILL 对应光栅化模式: GL_FILL
glDisable(GL_POLYGON_OFFSET_FILL);
不要将两个物体靠的太近,避免渲染时三角形叠在一起。这种方式要求对场景中物体插入一个少量的偏移,那么就可能避免ZFighting现象。例如上⾯的⽴⽅体和平面问题中,将平⾯下移0.001f就可以解决这个问题。当然⼿动去插⼊这个小的偏移是要付出代价的.