通过上一篇OpenGL-正背面剔除的分析,我们知道要想更好的解决隐藏面消除,并且不引发其他问题,我们只能探寻其他的方法--即本节的深度测试
下面先来了解几个概念
什么是深度?
深度就是像素点在3D世界中距离摄像机的距离,Z值。观察者可以放在坐标系的任何位置,所以不能简单的说Z值越大或越小,观察者就距离物体越近
深度值的精度一般有16位,24位或者36位,位数越高,深度的精确度越好。一般是24位精度。
什么是深度缓冲区?
深度缓冲区就是一块内存区域,用来存储每个像素点的深度值
为什么需要深度缓冲区?
在不使用深度缓冲区的时候,如果我们先绘制距离近的物体,再绘制距离远的物体,那么重合区域就会出现:距离远的物体覆盖距离近的物体的现象。但是有了深度缓冲区之后,绘制顺序就没有那么重要了,深度缓冲区会根据设置的参数,存储需要绘制的像素点对应的深度值(每个像素点只会存储一个对应的深度值,或是近的,或是远的,中间会涉及深度值的替换等),并且或同步更新该像素点对应的颜色值(深度缓存区跟颜色缓存区一一对应),这个过程就是所谓的深度测试
如何使用深度测试?
OpenGL提供了对应的API
//开启深度测试
glEnable(GL_DEPTH_TEST);
注意:在绘制场景前,需要清除深度缓冲区和颜色缓冲区
//设置颜色
glClearColor(0.0f,0.0f,0.0f,1.0f);
//清理缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//深度缓冲区默认值为1.0,表示最⼤大的深度值,深度值的范围为(0,1)之间.
在深度测试之前,我们可以设置深度测试的判断模式
//指定深度测试判断模式
void glDepthFunc(GLEnum mode);
深度测试的判断模式.png
这个设置并不常用,一般使用系统的默认值就足够
我们还可以打开/阻断深度缓冲区的写入
//value : GL_TURE 开启深度缓冲区写⼊入; GL_FALSE 关闭深度缓冲区写⼊入
void glDepthMask(GLBool value);
深度测试解决了什么问题?
使用深度测试代替正背面剔除,我们即消除了隐藏面,又不会导致图像的重合区域出现缺失一块的问题
隐藏面消除.png
重叠区域正常显示.png
深度测试的弊端?
潜在风险:ZFighting闪烁问题
- 因为开启深度测试后,OpenGL 就不会再去绘制模型被遮挡的部分. 这样实现的显示更加真实.但是由于深度缓冲区精度的限制,对于深度相差非常小的情况下.(例如在同⼀平面上进行2次绘制),OpenGL就可能出现不能正确判断两者的深度值,会导致深度测试的结果不可预测.显示出来的现象是交错闪烁.前面2个画面,交错出现.
1.png2.png
那么如何解决呢?
对于这个问题,我们可以通过启⽤ Polygon Offset ⽅式解决。即让深度值之间产⽣间隔.如果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
//指定偏移量
void glPolygonOffset(Glfloat factor,Glfloat units);
//应用到⽚段上总偏移计算⽅方程式:
//Depth Offset = (DZ * factor) + (r * units);
//DZ:深度值(Z值)
//r:使得深度缓冲区产生变化的最⼩值,具体是由OpenGL平台指定的 ⼀个常量.
//负值,将使得z值距离我们更近,⽽正值,将使得z值距离我们更远.
//一般⽽言,只需要将-1.0 和 -1 这样简单赋值给glPolygonOffset 基本可以满⾜需求.
//关闭Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL)