什么是颜色混合?
定义:我们把OpenGL在渲染时把颜色值存放在颜色缓冲区中,把每个片段(像素)的深度值存放在深度缓冲区中。当深度检测被关闭时,新的颜色值简单地覆盖颜色缓冲区中已经存在的颜色值;当深度检测被打开时,新的颜色值只有当它比原来的颜色更接近临近的裁剪平面时才会替换原来的颜色。当然,这是在OpenGL的混合功能被关闭的情况下。当混合功能被启用时,新的颜色会与颜色缓冲区中原有的颜色进行组合。通过对这些颜色进行不同的组合,可以产生许多种不同的效果。
-
在介绍颜色混合之前,我们需要首先明确目标颜色和源颜色这两个术语的概念。
- 目标颜色:存储在颜色缓冲区中的颜色称为目标颜色,这个颜色包含了单独的红、绿、蓝成分以及一个可选的alpha值。
- 源颜色:作为当前渲染命令的结果进入颜色缓冲区中的颜色称为源颜色,它同样也包含了四种颜色成分(红、绿、蓝和可选的alpha值成分)。
我们通过对目标颜色和源颜色进行不同的组合操作,来实现颜色混合的功能的。
启用混合功能:
glEnable(GL_BLEND);
当混合功能被启用时,源颜色和目标颜色的组合方式是由混合方程式来控制的。在默认情况下,使用的混合方程式如下所示:
Cf = (Cs * S) + (Cd * D)
其中:1. Cf: 最终计算参数的颜⾊
2. Cs: 源颜⾊
3. Cd: ⽬标颜⾊
4. S: 源混合因⼦
5. D: ⽬标混合因⼦
当然我们设置混合因子,需要用到glBlendFun
函数 glBlendFunc(GLenum S,GLenum D);
其中 S
是源混合因⼦,D
是目标混合因⼦。并且S和D我们不难看出是一个枚举值。具体这个枚举值要取的是什么,接下来我们用一个常见的混合函数组合来说明问题:
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
如果颜色缓存区已经有一种颜色红色(1.0f,0.0f,0.0f,1.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)
总结:最终颜色是以原先的红色(⽬标颜色)与 后来的蓝色(源颜色)进行组合。源颜色的
alpha
值越高,添加的蓝色颜色成分越高,目标颜色所保留的成分就会越少。 混合函数经常用于实现在其他一些不透明的物体前面绘制一个透明物体的效果。
改变组合方程式
- 实际上组合方程远不止一种混合方程式,
Cf = (Cs*S)+(Cd*D)
这个只是默认的组合方程式,但这个是最常用的,其他的几种不建议去使用。
选择组合方程式的函数
// mode是枚举值,有以下5种模式
// GL_FUNC_ADD 对应的组合方程式:Cf = (Cs * S) + (Cd * D)
// GL_FUNC_SUBTRACT 对应的组合方程式:Cf = (Cs * S) - (Cd * D)
// GL_FUNC_REVERSE_SUBTRACT 对应的组合方程式:Cf = (Cd * D) + (Cs * s)
// GL_MIN 对应的组合方程式:Cf = min(Cs, Cd)
// GL_MAX 对应的组合方程式:Cf = max(Cs, Cd)
glbBlendEquation(GLenum mode);
- 除了能使⽤
glBlendFunc
来设置混合因子,还可以有更灵活的选择,使用glBlendFuncSeparate
函数,但是使用这个函数时需要注意以下两点:
1.glBlendFunc
指定源和目标RGBA值的混合函数;但是glBlendFuncSeparate
函数则允许为 RGB 和 Alpha 成分单独指定混合函数。- 在混合因子表中,
GL_CONSTANT_COLOR,GL_ONE_MINUS_CONSTANT_COLOR,GL_CONSTANT_ALPHA,GL _ONE_MINUS_CONSTANT
值允许混合方程式中引入一个常量混合颜色。
- 在混合因子表中,
//strRGB: 源颜色的混合因子
//dstRGB: ⽬标颜色的混合因子
//strAlpha: 源颜色的Alpha因子
//dstAlpha: ⽬标颜色的Alpha因子
void glBlendFuncSeparate(GLenum strRGB,GLenum dstRGB ,GLenum strAlpha,GLenum dstAlpha);
- 常量混合颜⾊, 默认初始化为黑色
(0.0f,0.0f,0.0f,1.0f)
,但是还是可以修改这个常量混合颜色。
void glBlendColor(GLclampf red ,GLclampf green ,GLclampf blue ,GLclampf alpha );
接下来我们使用代码来感受一下颜色混合的例子:
以下是混合的核心代码,其他主要代码和之前的一样
//召唤场景
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//定义4种颜色
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 0.5f };
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 0.5f };
GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 0.5f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 0.5f };
//5.召唤场景的时候,将4个固定矩形绘制好
//使用 单位着色器
//参数1:简单的使用默认笛卡尔坐标系(-1,1),所有片段都应用一种颜色。GLT_SHADER_IDENTITY
//参数2:着色器颜色
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
greenBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
redBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
blueBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);
blackBatch.Draw();
//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);
//同步绘制命令
glutSwapBuffers();
}
附上一张颜色混合效果图:
QQ20200713-152913-HD.gif.gif