深度测试
在之前我们已经讲过深度测试的大部分内容,这次就完善一下之前的内容。
首先深度测试解决的问题:当我们绘制的图形旋转时,会发生两个部分重叠的情况,而OpenGL无法分辨哪个图层在前,哪个图层在后,则会出现一部分存在缺口。
而隐藏面的消除除了可以使用正背面剔除外,还可以使用深度测试来解决,而深度测试还可以解决重叠部分的图案的绘制。
在OpenGL的坐标系中,像素点的z坐标距离观察者的距离,当观察者在z轴正半轴,z值越大则越靠近观察者。当观察者在z轴负半轴,z值越小越靠近观察者。
截屏2020-07-12 上午9.49.05.png 15945194638438.png
查看上面两张图,第一张在z轴正半轴,当观察者在z轴正半轴,图形的z轴越大,越靠近观察者,第二张图就不去解释了,道理都一样。
深度缓冲区
在我之前的的案例中,RenderScene函数在每次写时,都会调用一个函数来清除颜色缓冲区,深度缓冲区。防止之前的数据对现在的图形造成干扰。
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
深度缓冲区和颜色缓冲区是对应的。颜色缓冲区存储像素的颜色信息,而深度缓冲区存储像素的深度信息。在决定是否绘制一个物体表面时,首先要将表面对应的像素的深度值与当前深度缓冲区的值进行比较。如果大于深度缓冲区中的值,则丢弃这部分,否则利用这个像素对应的深度值和颜色值分别更新深度缓冲区和颜色缓冲区,这个过程称为深度测试。
深度缓冲区的默认值为1.0,表示最大深度值,他的范围在[0,1]之间。
我们经常通过glEnable(GL_DEPTH_TEST);
和glDisable(GL_DEPTH_TEST);
来开启和关闭深度缓冲区。
z-fighting问题
在深度测试开启后,OpenGL就不会再去绘制模型被遮挡的部分,这样实现的显示更加真实。但是由于深度缓冲区精度的限制对于深度相差非常小的情况下,OpenGL就可能出现不能正确判断两者的深度值,会导致深度测试的结果不可预测,显示出来的现象交错闪烁,交错出现。
例如如下图所示:同一个位置上出现的图层,且深度值出现精度很低时,就使得两个物体靠的非常近,无法确定谁在前,谁在后
15945205942773.png
解决方法:
1、多边形偏移(Polygon Offset)
多边形偏移方法解决问题的原理主要是让深度值之间产生间隔,如果2个图形之间有间隔,那是不是意味着就不会产生干扰。可以理解为在执行深度测试前将立方体的深度值做一些细微的增加,于是就能将重叠的2个图形深度值之间有所区分。
启用多边形偏移方法:
```
glEnable(GL_POLYGON_OFFSET_FILL)
参数列列表:
GL_POLYGON_OFFSET_POINT 对应光栅化模式: GL_POINT
GL_POLYGON_OFFSET_LINE 对应光栅化模式: GL_LINE
GL_POLYGON_OFFSET_FILL 对应光栅化模式: GL_FILL
```
2、指定偏移量
通过glPolygonOffset来制定.glPolygonOffset需要两个参数:factor,units。
每个fragment的深度值都会增加如下所示的偏移量:offset = (m*factor)+(r*units);
,m表示多边形深度的斜率最大值,可以理解为一个多边形越是与近裁剪面平行,m就越接近0,r表示能产生于窗口坐标系的深度值可分辨的差异最小值,r是由具体OpenGL平台制定的一个常量。
void glPolygonOffset(Glfloat factor,Glfloat units);
应⽤用到片段上总偏移计算方程式:
Depth Offset = (DZ * factor) + (r * units); DZ:深度值(Z值)
r:使得深度缓冲区产生变化的最小值
负值,将使得z值距离我们更近,⽽正值,将使得z值距离我们更远.
在我们开启了偏移之后,都需要调用关闭函数glDisable(GL_POLYGON_OFFSET_FILL)
.
在上面了解完zFighting问题之后,我们可以知道预防的方法可以加大两物体之间的距离和尽可能将近裁剪面设置的离观察者远一些。
混合
混合简单来说就是将两个不透明的或者在另一个物体上面的为半透明的图形重叠在一起产生的颜色变化。
我们都知道OpenGL渲染时会把颜色值存在颜色缓冲区中,每个片段的深度值也是放在深度缓冲区。当深度缓冲区被关闭时,新的颜色将简单的覆盖原来的颜色缓冲区颜色值,当深度缓冲区再次打开时,新的颜色片段只是当它比原来的值更接近邻近的裁剪平面才会替换原来的颜色片段。
开启颜色混合:glEnable(GL_BlEND);
下面介绍一下组合颜色的一些变量的概念:
目标颜色:已经存储在颜色缓冲区的颜色值
源颜色:作为当前渲染命令结果进入颜色缓冲区的颜色值。
在混合功能被启动时,源颜色和目标颜色的组合方式是混合方程式控制的,它的方程式为:
Cf = (Cs * S) + (Cd * D)
cf:最终计算参数的颜色
Cs:源颜色
Cd:目标颜色
S:源混合因子
D:目标混合因子
因此,在我们开启混合时,一般都需要开启混合因子的设置
下面这张图介绍了我们该如何设置两个混合因子
其中R,G,B,A分别代表红、绿、蓝、alpha。
S,D分别代表源、目标
C代表常量颜色(默认黑色)
15945222197911.png
例如:
//1、开启混合
glEnable(GL_BLEND);
//2、开启组合函数,计算混合因子
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
下面解释一下上面的混合因子计算:
如果颜色缓冲区已经有一种颜色(1.0f,0.0f,0.0f,1.0f),这个是目标颜色Cd,如果在这上面用一种alpha为半透明的蓝色(0.0f,0.0f,1.0f,0.5f)
那么
Cd = (1.0f,0.0f,0.0f,1.0f),
Cs = (0.0f,0.0f,1.0f,0.5f),
S = 0.5
D = 1-源alpha = 1-0.5f = 0.5f
方程式 Cf = (CsS)+(CdD)
等价于 = (Blue * 0.5f)+(Red * 0.5f)
其他的都一样,套公式。
混合方程式其实是还可以改变的,我们可以从5种不同的方程式中进行选择
选择方程式函数为:glbBlendEquation(GLenum mode);
,函数中的参数可以在下面这张表中任意选择。
除了能使用glBlendFunc来设置混合因子,还可以有更灵活的选择。
void glBlendFuncSeparate(GLenum strRGB,GLenum dstRGB ,GLenum strAlpha,GLenum dstAlpha);
strRGB:源颜色混合因子
dstRGB:目标颜色的混合因子
strAlpha:源颜色的alpha值
dstAlpha:目标颜色的alpha值
glBlendFuncSeparate使用注意事项:
glBlendFunc指定源和目标RGBA值的混合函数;但是glBlendFuncSeparate函数则允许为RGB和Alpha成分单独指定混合函数。
在混合因⼦子表中,GL_CONSTANT_COLOR,GL_ONE_MINUS_CONSTANT_COLOR,GL_CONSTANT_ALPHA,GL _ONE_MINUS_CONSTANT值允许混合方程式中引⼊一个常量混合颜色。
总结:
颜色混合的最终颜色是以目标颜色与后来的源颜色进行组合,在默认混合方程式下,源颜色的alpha值越高,添加的源颜色成分越高,目标颜色所保留的成分就越少。混合函数经常⽤于实现在其他⼀些不透明的物体前面绘制一个透明物体的效果。
在我们通常进行混合时,混合的颜色可能存在另一种颜色的上方或者下方,那么我们要实现混合,那么都必须要使上面的颜色设置一个透明度,否则不会出现颜色混合的情况。
下图是一个颜色混合的demo。
15945234359083.png
网友评论