OpenGL渲染技巧-多边形偏移、颜色混合

962 阅读5分钟

上一篇博客 OpenGL渲染技巧-正背面剔除及深度测试  里介绍了两种渲染技巧,正背面剔除和深度测试,今天继续介绍渲染技巧另外两种方式:多边形偏移、颜色混合。

多边形偏移

ZFighting闪烁问题

在开启深度测试后,OpenGL 就不会再去绘制物体被遮挡的部分。这样实现的显示更加真实,但是由于深度缓冲区精度的限制对于深度相差⾮常⼩的情况下.(例如在同⼀平⾯上进⾏2次绘制),OpenGL就可能出现不能正确判断两者的深度值,会导致深度测试的结果不可预测,出现2个画⾯交错闪烁的现象,就叫做 “ZFighting”

如下图:


“ZFighting”问题产生的主要原因就是多个图层间距太近,深度值接近,OpenGL无法区分图层绘制的先后顺序,对此,OpenGL提供了一种解决方式叫 多边形偏移(polygon offset)

多边形偏移的三个步骤:

1、开启多边形偏移(Polygon Offffset)

glEnable(GL_POLYGON_OFFSET_FILL)
参数列表:

2、指定偏移量

glPolygonOffset (GLfloat factor, GLfloat units);

  • 通过glPolygonOffset 来指定.glPolygonOffset 需要2个参数: factor , units
  • 每个Fragment 的深度值都会增加如下所示的偏移量:
  • Offset = ( m * factor ) + ( r * units);
  • m : 多边形的深度的斜率的最⼤值,理解⼀个多边形越是与近裁剪⾯平⾏,m 就越接近于0.
  • r : 能产⽣于窗⼝坐标系的深度值中可分辨的差异最⼩值.r 是由具体是由具体OpenGL 平台指定的⼀个常量。⼀个⼤于0的Offset 会把模型推到离你(摄像机)更远的位置,相应的⼀个⼩于0的Offset 会把模型拉
  • ⼀般⽽⾔,只需要将-1 和 -1 这样简单赋值给glPolygonOffset 基本可以满⾜需求

3、关闭多边形偏移(Polygon Offffset)

glDisable(GL_POLYGON_OFFSET_FILL) 

如何预防ZFighting闪烁问题

  1. 不要将两个物体靠的太近,避免渲染时三⻆形叠在⼀起。这种⽅式要求对场景中物体插⼊⼀个少量的偏
  2. 尽可能将近裁剪⾯设置得离观察者远⼀些,会使整个裁剪范围内的精确度变⾼⼀些。但是这种⽅式会使离观察者较近的物体被裁减掉,因此需要调试好裁剪⾯参数。
  3. 使⽤更⾼位数的深度缓冲区,使精确度得到提⾼ 

颜色混合

当开启深度测试后,两个重叠的图层中,如果有一个图层是半透明的,另一个图层是不透明的,此时就不能通过深度值比较,进行颜色值的覆盖,而是需要将两个图层的颜色进行混合,然后存入颜色缓冲区。

混合的使用有两种方式

1、开关方式

//开启,
glEnable(GL_BlEND);
//关闭
glDisable(GL_BlEND);

固定着⾊器/可编程着⾊器都可以使⽤开关⽅式,单纯的2个图层重叠进⾏混合,这种混合并不能解决颜色的混合。

2、开关+混合方程式

一般在可编程着⾊器(⽚元着⾊器)上使用。应用场景:我们有一张原图或颜色,在上面覆盖半透明颜色进行混合。如果只是打开混合的开关让两个图层重叠混合已经不能满足需求了,需要借助混合方程式实现两种颜色的混合。
//开启,
glEnable(GL_BlEND);
//设置混合因子--默认值是 GL_SRC_ALPHA 和 GL_ONE_MINUS_SRC_ALPHA
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//关闭
glDisable(GL_BlEND);
当混合功能被启动时,源颜⾊和⽬标颜⾊的组合⽅式是混合⽅程式控制的。在默认情况下,混合⽅程式如下所示:
//Cf -- 最终组合的颜色值
//Cd:源颜色 -- 当前渲染命令传入的颜色值
//CS:目标颜色 -- 颜色缓冲区中已经存在的颜色值
//S:源混合因子
//D:目标混合因子 
Cf = (Cs * S) + (Cd * D)
可以通过glBlendFunc函数设置混合因⼦

//设置混合因⼦,需要⽤到glBlendFun函数 glBlendFunc(GLenum S,GLenum D); S:源混合因⼦ D:⽬标混合因⼦ 

 举个例子:

如果颜⾊缓存区已经有⼀种颜⾊红⾊(1.0f,0.0f,0.0f,0.0f),这个⽬标颜⾊Cd,如果在这上⾯⽤⼀种
alpha为0.6的蓝⾊(0.0f,0.0f,1.0f,0.6f)
Cd (⽬标颜⾊) = (1.0f,0.0f,0.0f,0.0f);
Cs (源颜⾊) = (0.0f,0.0f,1.0f,0.6f);
S = 源alpha值 = 0.6f
D = 1 - 源alpha值= 1-0.6f = 0.4f
⽅程式Cf = (Cs * S) + (Cd * D)
等价于 = (Blue * 0.6f) + (Red * 0.4f) 

颜色混合总结

  1. 在颜色缓冲区中,每个像素点只能存储一种颜色
  2. 源颜⾊的alpha值越⾼,添加的新颜⾊成分越⾼,⽬标颜⾊所保留的成分就会越少
  3. 混合函数经常⽤于实现在其他⼀些不透明的物体前⾯绘制⼀个透明物体的效果。(比如滤镜)

颜色混合案例:底色不透明+移动图形半透明


上图中四个角的不透明正方形图层在下面,当半透明图层正方形移动到与四个角的正方形重叠时,他们重叠的部分就会发生颜色混合形成新的颜色值,存储到颜色缓冲区。

混合的核心代码

//1.开启混合
    glEnable(GL_BLEND);
    //2.开启组合函数 计算混合颜色因子
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //3.使用着色器管理器
    //*使用 单位着色器
    //参数1:简单的使用默认笛卡尔坐标系(-1,1),所有片段都应用一种颜色。GLT_SHADER_IDENTITY
    //参数2:着色器颜色
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    //4.容器类开始绘制
    squareBatch.Draw();
    
    //5.关闭混合功能
    glDisable(GL_BLEND);



切记:混合绘制完成后,一定要关闭混合,混合的开启是全局的,如果不关闭会对其他项目造成影响。

附:Github完整Demo  06-OpenGL-颜色混合