4、OpenGL 深度测试、多边形偏移、颜色混合问题
一、深度测试
2251862-b36d5f3113c5c678.gif
图中可以看出,在甜甜圈旋转过程中,前后两部分重叠时,出现了缺口,原因是OpenGL并不能清楚的区分两个图层哪个显示在前,哪个显示在后面,由此导致了甜甜圈缺口问题。
那么如何解决这个问题呢 ?
先来了解几个概念
1. 深度
深度是指OpenGL坐标系中,像素点的 Z 坐标距离观察者的距离。
深度与图形像素点的Z坐标的关系:
- 如果观察者在Z轴的正方向,Z值越大,距离观察者越近
- 如果观察者在Z轴的负方向,Z值越小,距离观察者越近
2. 深度缓冲区
深度缓冲区是一块专门的内存区域,存储在显存中,储存屏幕上所绘制图形的每个像素点的深度值。将深度值与屏幕上每个像素点进行一一对应,然后将深度值存储在深度缓冲区。深度缓冲区的范围是[0,1],默认值是1.0,表示深度值得最大值。在深度缓冲区中每个像素只会记录一个深度值。
- 深度值越大,距离观察者越远。
- 深度值越小,距离观察者越近。
3. 深度测试
一个物体在绘制时,像素点的深度值需要与深度缓存中已经存在的深度值作比较,如果新值 > 旧值,则丢弃这部分不绘制,反之将新的深度值更新至深度缓冲区,由于深度缓冲区与颜色缓冲区是一一对应的,同时也需要更新该像素点的颜色值到颜色缓冲区,这个过程就是深度测试。
我们利用深度测试可以解决甜甜圈缺口的问题。首先开启 glEnable(GL_DEPTH_TEST),用于新旧深度值的对比,决定像素点是绘制还是丢弃。流程图如下:
2251862-5bf801f5a9296349.png
- 深度测试的开启,在绘制完成之后。要记得关闭
glDisable(GL_DEPTH_TEST)
4. 隐藏面消除方案
-
正背面剔除:需要根据顶点顺序判断用户可见部分与隐藏面,隐藏面直接丢弃不绘制,只绘制可见部分。
-
深度测试:可以一次性解决隐藏面消除的问题,原理是不管多少图层,只显示可见图层,剩余不可见的都丢弃。
二、多边形偏移:也称Z-Fight(Z冲突,闪烁)问题
开启深度测试之后,由于深度缓冲区精度有限制,导致深度值在误差极小时,OpenGl出现无法判断的情况,画面出现交错闪现的现象。
由于图形靠的太近,导致无法区分出图层的先后次序,针对该问题,OpenGL提供了一种多边形偏移(Polygon offset)方案
使用多边形偏移分三步:
- 开启多边形偏移
glEnable(GL_POLYGON_OFFSET_FILL) - 指定偏移量
glPolygonOffset(GLfloat factor, GLfloat units) - 关闭多边形偏移
glDisable(GL_POLYGON_OFFSET_FILL)
三、颜色混合
当开启深度测试后,两个重叠的图层中,如果上面图层是半透明的,另一个是非半透明的,此时就不能通过深度值比较来进行颜色值得覆盖,而是需要将两个颜色值进行混合,然后存入颜色缓冲区
颜色混合的两种方式:
-
开关方式
glEnable(GL_BLEND)开启,glDisable(GL_BLEND)关闭 -
开关方式+混合方程式
用于处理类似滤镜效果的场景,简单描述就是将需要处理的图片颜色和图片上覆盖的半透明颜色进行混合,单纯的混合已经不能满足我们的需求,这时借助混合方程式来实现两股颜色的混合
glEnable(GL_BlEND);
//设置混合因子--默认值是 GL_SRC_ALPHA 和 GL_ONE_MINUS_SRC_ALPHA
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//关闭
glDisable(GL_BlEND);
在glBlendFunc方法中,是通过混合方程式来得到颜色的组合,默认情况下混合方程式如下所示
//Cd:源颜色 -- 当前渲染命令传入的颜色值
//CS:目标颜色 -- 颜色缓冲区中已经存在的颜色值
//S:源混合因子
//D:目标混合因子
Cf = (Cs * S) + (Cd * D)