深度测试
在使用OpenGL绘制完下面图形进行旋转时,则出现了下面的情况:
在了解相关资料之后,后面的这种情况出现是因为当图形进行旋转时,两个部分重叠,此时OpenGL不能清楚分辨哪个图层在前,哪个图层在后,则会出现这种仿佛被咬了一个口的现象。当这种情况出现后,可以通过开启深度测试来解决此问题。
什么是深度
深度其实就是该像素点在OpenGL 坐标系中距离观察者的距离,即Z值。观察者可以放在坐标系的任意位置,但是不能简单的说Z值越大或者越小,则观察者就越靠近物体。而是当观察者在Z轴的正方向,Z值越大则靠近观察者;当观察者在Z轴负方向,Z值越小则靠近观察者。
什么是深度缓存区
深度缓存区就是显存中的一块区域,存储着每个像素点(绘制在屏幕上的)深度值,深度值越大,则离观察者越远。
深度测试
深度缓存区(DepthBuffer)和颜色缓存区(ColorBuffer)是对应的。颜色缓存区存储像素的颜色信息,而深度缓存区存储像素的深度信息。在决定是否绘制一个物体表面时,首先要将表面对应的像素的深度值与当前缓存区中的值进行对比。如果大于深度缓存区中的值,则丢弃这部分。否则利用这个像素对应的深度值和颜色值。分别更新深度缓存取和颜色缓存区,这个过程称为“深度测试”。
当开启了深度测试时,在绘制每个像素前,OpenGL会把它的深度值与目前像素点对应存储的深度值进行比较。如果像素点新对应深度值<像素点对应的深度值,(就是比较两个当前图层时,哪一个图层更接近观察者)那么此时就会将该像素点的深度值进行取而代之;相反,则像素点上的新颜色值距离观察者更同时会被遮挡,那么此时它对应的深度值与颜色值就会被抛弃,不进行绘制。
开启深度测试
glEnable(GL_DEPTH_TEST);
关闭深度测试
glDisable(GL_DEPTH_TEST);
深度测试规则
深度缓存区的默认值为1.0,为最大深度值,深度值的范围是[0,1]之间。
深度测试的测试规则为多个枚举值,我们可以通过glDepthFunc(GLenum func)
来修改。其中具体枚举值如下图:
深度测试的潜在风险ZFighting
在我们开启深度测试后,OpenGL就不会再去绘制模型被遮挡的部分,这会使得显示效果更加真实。但是当深度缓存区精度的限制对于深度相差非常小的情况下(在同一平面上进行两次绘制),OpenGL就可能出现不能正确判断两者的深度值,会导致深度测试的结果不可预测,从而导致显示出来的现象交错闪烁两个图像交错出现。
那么如何解决ZFighting
既然是因为因为靠的太近,无法区分图层先后。那么我们可以在图层之间加入一个微妙的间隔。其中OpenGL有提供相应的解决方案,即“多边形偏移”。
- 启用多边形偏移Polygon Offset。在深度值之间产生间隔,让两个图形之间有间隔,那么就意味着就不会因为深度值相差过小而导致深度测试无法预测,将两个重叠的图形之间的深度值区分开来。
//启用多边形偏移
/*
GL_POLYGON_OFFSET_POINT 对应模式:GL_POINT
GL_POLYGON_OFFSET_LINE 对应模式:GL_LINE
GL_POLYGON_OFFSET_FILL 对应模式:GL_FILL
*/
glEnable(GL_POLYGON_OFFSET_FILL);
```
2. 指定偏移量
通过glPolygonOffset来指定。当Offset大于0会把模型推到离你(观察者)更远的位置,当offset小于0时会把模型拉近。一般而言,只需要将-1和-1这样简单赋值就基本上满足需求了。
/*
应用到片段上的总偏移计算公式
Depth Offset = (DZfactor)+(runits);
DZ:深度值(Z)
r:使得深度缓存区产生变化的最小值
*/
glPolygonOffset(GLfloat factor, GLfloat units);
3. 关闭多边形偏移
```//关闭多边形偏移
glDisable(GL_POLYGON_OFFSET_FILL);
预防ZFighting闪烁问题
- 不要将两个物体相隔太近,避免渲染时三角形叠在一起。
- 尽可能将近裁剪面离观察者远一些。
- 使用更高位数的深度缓存区,通常使用的深度缓存区是24位,现在有一些硬件使用32/64位缓存区,使得精确度得到提高