上一章节我们了解了什么是正背面剔除
,但是引入了一个新的问题,就是当圆环旋转到一定角度的时候,会出现缺口,如下图:
要解决这个问题,就涉及到我们这一章节的内容深度测试
什么是深度?
深度就是在OpenGL坐标系中,像素点的z坐标距离观察者的距离
观察者和像素点z坐标有如下关系:
如果观察者在Z轴正方向,Z值越大则越靠近观察者
如果观察者在Z轴负方向,Z值越小则越靠近观察者
深度缓冲区(DepthBuffer)
深度缓冲区存储在显存中,深度缓冲区就是把观察者平面(近裁剪面)的深度值与窗口中每个像素点1对1进行关联以及存储;120 * 120 就需要存储 120 * 120个深度值。
- 深度缓冲区的取值范围为[0,1]
- 每个像素点都会存在一个深度信息
- 深度缓冲区和颜色缓冲区一一对应
- 深度缓冲区的默认值为1.0。表示最大的深度值
当绘制一个物体表面时,首先将对应像素的深度值和当前深度缓冲区中的深度值进行比较,如果大于深度缓冲区中的值,则需要丢弃这部分。否则利用这个像素对应的深度值和颜色值分别更新深度缓冲区和颜色缓冲区。这个过程称为深度测试
开启深度测试:
glEnable(GL_DEPTH_TEST)
关闭深度测试:
glDisable(GL_DEPTH_TEST)
清除深度缓冲区和颜色缓冲区:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
我们可以通过glDepthFunc(GLenum func)
来修改深度测试的规则。测试的规则主要在于该函数中的枚举值:
参数 | 说明 |
---|---|
GL_ALWAYS | 总是通过测试 |
GL_NEVER | 总是不通过测试 |
GL_LESS | 当前深度值<存储的深度值时通过 |
GL_EQUAL | 当前深度值=存储的深度值时通过 |
GL_LEQUAL | 当前深度值<=存储的深度值时通过 |
GL_GREATER | 当前深度值>存储的深度值时通过 |
GL_NOTEQUAL | 当前深度值!=存储的深度值时通过 |
GL_GEQUAL | 当前深度值>=存储的深度值时通过 |
我们修改上一章节的代码(主要是在RenderScene函数中添加如下代码):
//根据设置iDepth标记来判断是否开启深度测试
if(iDepth)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
修改后,我们再次旋转视图:
开启深度测试
我们发现缺口消失了,得到了一个完整的甜甜圈
但是开启深度测试以后还是有一些潜在问题
深度测试的潜在风险 Z-finghting(z冲突,z闪烁)问题
什么是Z-finghting
开启深度测试之后,OpenGL就不会再去绘制模型被遮挡的部分,
这样可以节约性能,免去了不必要的绘制。
但是由于深度缓冲区精度的限制,对于深度相差非常小的
情况下,(例如在同一平面上进行两次绘制)
OpenGL就可能不能正确判断两者的深度值,
会导致深度测试的结果不可预测。
显示出来的图像交错闪烁,如下图:
Z-fighting
ZFighting的解决方案 --- 多边形偏移(Polygon Offset)
既然导致ZFighting的原因是距离太近,无法区分图层的先后。那么我们可以在两个图层中间添加一个深度间隔。这个解决方案也叫多边形偏移
启用多边形偏移:
glEnable(GLPOLYGON_OFFSET_FILL)
关闭多边形偏移:
glDisable(GLPOLYGON_OFFSET_FILL)
开启多边形偏移的可选参数:
参数 | 对应模式 |
---|---|
GL_POLYGON_OFFSET_POINT | GL_POINT |
GL_POLYGON_OFFSET_LINE | GL_LINE |
GL_POLYGON_OFFSET_FILL | GL_FILL |
除了这种默认的方式之外,我们还可以指定偏移量
- 通过glPolygonOffset来指定偏移量,此方法需要两个参数:
factor
,unites
- 每个像素点的深度值都会增加如下所示的偏移量:
Offset = (m * factor) + (r * units)
m:多边形深度斜率的最大值,理解为一个多边形越是与近裁面平行,m就越接近 于0
r :OpenGL能分辨的最小深度值,是由平台决定的一个常量 - 大于0的offset会把模型推到理你更远的位置,反之则越近
- 一般来说,只需要将factor和units设置为 -1这样的值就可以满足需求
预防ZFighting问题
- 避免两个物体靠的太近:在绘制时,插入一个小偏移
- 将近裁剪面(设置透视投影时设置)设置的离观察者远一些:提高裁剪范围内的精确度
- 使用更高位数的深度缓冲区:提高深度缓冲区的精确度
颜色混合
OpenGL在渲染时会把颜色值存储在颜色缓冲区中,每个像素的深度值存放在深度缓冲区中。当深度缓冲区关闭时,新的颜色将简单覆盖原来颜色缓冲区的值,当深度缓冲区打开时,比原来的值更接近的颜色值才会被替换
当开启深度测试之后,两个互相叠加的图层一个是半透明的,另外一个是非半透明的,那么我们就不能简单的进行颜色值的覆盖,而是将两个图层的颜色进行混合;
开启颜色混合
glEnable(GL_BLEND)
关闭颜色混合
glDisable(GL_BLEND)
目标颜色:已经存储在颜色缓冲区的颜色值【前女友】
源颜色:作为当前渲染命令结果进入颜色缓冲区的颜色值【现女友】
当混合功能被启用时,源颜色和目标颜色的组合方式是混合方程式控制的。在默认情况下,混合方程式如下:
Cf = (Cs * S) + (Cd * D)
-
Cf
:最终得出的颜色 -
Cs
:源颜色 -
Cd
:目标颜色 -
S
:源混合因子 -
D
:目标混合因子
设置混合因子
glBlendFunc(GLenum S,GLenum D)
-
S
:源混合因子 -
D
:目标混合因子
在混合方程中,源颜色的alpha值越高,添加的源颜色成分就越高,目标颜色值就保留的越少
网友评论