OpenGL中ZFighting、颜色混合
接上篇 OpenGL深度测试 已经明白处理前后重叠造成缺口问题的解决方案是使用深度测试 glEnable(GL_DEPTH_TEST),这样渲染器就能识别哪面是正面哪面是背面从而进行正常的渲染;那么在使用深度测试的过程中会不会出现一些意外清空呢?
深度测试的潜在风险之 Z-fighting(Z冲突、Z闪烁)问题
因为在开启深度测试后,OpenGL就不会在绘制被遮挡的部分。这样的实现更加符合真实场景,但是由于深度缓存区精度的限制,对于深度相差非常小的情况下(例如在同一平面上进行2次绘制),OpenGL就可能出现不能正确判断两者的深度值,会导致深度测试的结果不可预测,显示出来的现象是交错闪烁的两个画面
Z闪烁如何解决Z-fighting的问题
既然是因为靠的太近无法区分,那么就可以在2个图层之间加入一个微妙的间隔。OpenGL提供了一个解决方案“多边形偏移”
启用多边形偏移 Polygon Offset
glEnable(GL_POLYGON_OFFSET_FILL); //启用多边形偏移 POLYGON Offset
glDisable(GL_POLYGON_OFFSET_FILL); //关闭多边形偏移 POLYGON Offset
参数:
GL_POLYGON_OFFSET_FILL //对应模式:GL_FILL
GL_POLYGON_OFFSET_LINE //对应模式:GL_LINE
GL_POLYGON_OFFSET_POINT //对应模式:GL_POINT
指定偏移量
glPolygonOffset (GLfloat factor, GLfloat units);
每个Fragment的深度值都会增加Offset = (m*factor) + (r*units) 这样的偏移量;一个大于0的Offset会把模型推到离摄像机更远的位置,相反一个小于0的Offset会把模型拉近
这两个参数一般填 -1 和 -1,就可基本满足要求
如何预防ZFighting闪烁问题
1.不要将两个物体靠的太近,避免渲染时三角形叠加在一起(对场景中的物体插入一个少量的偏移)
2.尽可能将近裁剪面设置的离观察者远一些
3.使用更高位数的深度缓存区(比如:32位、64位)
颜色混合
OpenGL渲染时会把颜色值存储在颜色缓存区,每个片段的深度值也放在深度缓存区。
深度缓存区关闭时:新颜色将无脑覆盖原来颜色缓存区的值
深度缓存区打开时:只有当新的颜色片段比原来的值更靠近裁剪平面才会体会原来的颜色片段
在开启深度测试后,2个重叠图层中,其中有一个图层时半透明的,有一个图层时非半透明的;那么此时就不在是简单的比较深度值,然后进行替换,而是要将2个图层颜色进行混合
颜色混合:
1、目标颜色:指已经存储在颜色缓存区的颜色值
2、源颜色:作为当前渲染命令结果进入颜色缓存区的颜色值
使用方式(2种):
开关方式(颜色混合)---单纯的2个图层重叠进行混合
这种混合并不能解决颜色的混合。在固定着色器和可编程着色器都可以使用这种方式
混合方程式---处理图片原图颜色+薄薄的绿色(需要颜色混合方程式的计算)
用于处理类似滤镜效果的场景,简单描述就是将需要处理的图片颜色和图片上覆盖的半透明颜色进行混合 即 两股颜色混合,需要借助混合方程式,来实现两股颜色的混合。一般是在可编程着色器中片元着色器中使用
混合方程式:
Cf = (Cs * S) + (Cd * D),此方程式不需要关注,一般使用默认即可
Cf -- 最终组合的颜色值
Cd:源颜色 -- 当前渲染命令传入的颜色值
Cs:目标颜色 -- 颜色缓冲区中已经存在的颜色值
S:源混合因子
D:目标混合因子 在混合方程中
例如:
目标颜色(红色):(1.0f,0.0f,0.0f,1.0f),如果在上面覆盖一种alpha为0.6的蓝色(0.0f,0.0f,1.0f,0.6f),那么Cd = (1.0f,0.0f,0.0f,1.0f), Cs=(0.0f,0.0f,1.0f,0.6f),
S= 源颜色的alpha值= 0.6, D = 1-源颜色的alpha值 = 0.4
新颜色的alpha值越高,添加的新颜色成分就越高,旧颜色值值就保留的越少
OpenGL混合因子glEnable(GL_BLEND);//1.开启混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //2.设置混合颜色因子
glDisable(GL_BLEND);//3.关闭混合
颜色混合总结:
1、混合函数主要用于实现在一些不透明物体前绘制透明物体的效果
2、在颜色缓存区,每个像素点只能存储一个颜色值(所有有重叠时需要混合)