OpenGL-ES 混合本质上是将 2 个片元的颜色进行调和(一般是求和操作),产生一个新的颜色
OpenGL ES 混合发生在片元通过各项测试之后,准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值,不再是新(源)片元直接覆盖缓冲区中的(目标)片元。
OpenGL-ES 混合方程:
Cresult=Csource∗Fsource + Cdestination∗Fdestination
其中:
其中:
Csource:源颜色向量,来自纹理的颜色向量;
Cdestination:目标颜色向量,储存在颜色缓冲中当前位置的颜色向量;
Fsource:源因子,设置了对源颜色加权;
Fdestination:目标因子,设置了对目标颜色加权;
操作符可以是加(+)、减(-)、Min、Max 等。
这里的向量可以理解为通道的含义,比如 RGB 可以用 Vec3 来表示;
启用 OpenGL ES 混合使用 glEnable(GL_BLEND);
然后通过 glBlendFunc 设置混合的方式,其中 sfactor 表示源因子,dfactor 表示目标因子
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// GL_SRC_ALPHA 表示源因子取值为源颜色的 alpha
// GL_ONE_MINUS_SRC_ALPHA 表示目标因子取值为 1- alpha(源颜色的 alpha)
// 操作符默认为 GL_FUNC_ADD ,即加权相加。
// 混合公式变成了 源颜色向量 × alpha + 目标颜色向量 × (1- alpha)
注意下面的混和因子说明表格中,存在 const alpha 的选项,既可以使用 const alpha 混合
我们也可以通过 glBlendEquation 自定义两个颜色之间的操作符:
GL_FUNC_ADD:默认的,彼此元素相加:Cresult=CSrc + CDst;
GL_FUNC_SUBTRACT:彼此元素相减:Cresult=CSrc − CDst ;
GL_FUNC_REVERSE_SUBTRACT:彼此元素相减,但顺序相反:Cresult=CDst - CSrc;
GL_MIN:混合结果的 4 个通道值分别取 2 元素中 4 个通道较小的值;
GL_MAX:混合结果的 4 个通道值分别取 2 元素中 4 个通道较大的值;
//对 RGB 和 Alpha 分别设置 BLEND 函数
//void glBlendFuncSeparate(GLenum srcRGB,GLenum dstRGB,GLenum srcAlpha,GLenum dstAlpha);
glBlendFuncSeperate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
//混合结果颜色 RGB 向量 = 源颜色 RGB 向量 × alpha + 目标颜色 RGB 向量 × (1- alpha);
//混合结果颜色 alpha = 源颜色 alpha × 1 + 目标颜色 alpha × 0;
也可以为 RGB通道和 alpha 通道设置不同的操作符:
void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);`
sss
下面的代码中,loadTgaTextures 生成了两张 Texture,在绘制的时候绘制了两次,第一次绘制了 Dst,第二次绘制了 Src,指定 const alpha 的 SFactor 和 DFactor 都为 0.5
typedef struct
{
GLuint programObject;
GLint samplerLocal;
GLuint textureIdDst;
GLuint textureIdSrc;
} UserData;
static int Init(ESContext *esContext)
{
UserData *userData = esContext->userData;
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec2 a_texCoord; \n"
"out vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec2 v_texCoord; \n"
"layout(location = 0) out vec4 outColor; \n"
"uniform sampler2D s_texture; \n"
"vec4 tempColor; \n"
"void main() \n"
"{ \n"
" tempColor = texture( s_texture, v_texCoord ); \n"
" outColor = vec4(tempColor.r, tempColor.b, tempColor.g, tempColor.a); \n"
"} \n";
userData->programObject = esLoadProgram(vShaderStr, fShaderStr);
userData->samplerLocal = glGetUniformLocation(userData->programObject, "s_texture");
userData->textureIdSrc = loadTgaTextures("./Huskey.tga");
userData->textureIdDst = loadTgaTextures("./scene.tga");
// 启用 alpha 混合 指定 const alpha 值为 0.5
glEnable(GL_BLEND);
glBlendColor(1.0f, 1.0f, 1.0f, 0.5f);
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
return TRUE;
}
static void Draw(ESContext *esContext)
{
UserData *userData = esContext->userData;
GLfloat vVertices[] = {
-1.0f, 1.0f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1.0f, -1.0f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
1.0f, -1.0f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
1.0f, 1.0f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
glViewport(0, 0, esContext->width, esContext->height);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(userData->programObject);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
// Bind the texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, userData->textureIdDst);
// Set the sampler texture unit to 0
glUniform1i(userData->samplerLocal, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
// 任然使用可以 texture0, 但是可以指定不同的 texture id
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, userData->textureIdSrc);
glUniform1i(userData->samplerLocal, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}