NDK OpenGL ES 3.0 开发(十二):混合

简介: OpenGL ES 混合本质上是将 2 个片元的颜色进行调和,产生一个新的颜色。OpenGL ES 混合发生在片元通过各项测试之后,准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值,不再是新(源)片元直接覆盖缓冲区中的(目标)片元。

作者:字节流动

来源:https://blog.csdn.net/Kennethdroid/article/details/102630858


OpenGL ES 混合

OpenGL ES 混合本质上是将 2 个片元的颜色进行调和,产生一个新的颜色。OpenGL ES 混合发生在片元通过各项测试之后,准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值,不再是新(源)片元直接覆盖缓冲区中的(目标)片元。

OpenGLES 混合方程:

屏幕快照 2021-02-08 上午10.58.56.png

启用 OpenGL ES 混合使用 glEnable(GL_BLEND);
然后通过 void glBlendFunc(GLenum sfactor, GLenum dfactor); 设置混合的方式,其中 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)

GL_SRC_ALPHA 表示源因子取值为源颜色 alpha (透明度)通道值,GL_ONE_MINUS_SRC_ALPHA 表示目标因子取值为 1- alpha(源颜色的 alpha),由于操作符默认为 GL_FUNC_ADD,即元素相加,所以混合公式变成了源颜色向量 × alpha + 目标颜色向量 × (1- alpha)

混合因子表:

混合因子
GL_ZERO 0
GL_ONE 1
GL_SRC_COLOR 源颜色向量C s o u r c e C_{source}Csource
GL_ONE_MINUS_SRC_COLOR 1−C s o u r c e C_{source}Csource
GL_DST_COLOR 目标颜色向量C d e s t i n a t i o n C_{destination}Cdestination
GL_ONE_MINUS_DST_COLOR 1−C d e s t i n a t i o n C_{destination}Cdestination
GL_SRC_ALPHA C s o u r c e C_{source}Csource的alpha值
GL_ONE_MINUS_SRC_ALPHA 1− C s o u r c e C_{source}Csource的alpha值
GL_DST_ALPHA C d e s t i n a t i o n C_{destination}Cdestination的alpha值
GL_ONE_MINUS_DST_ALPHA 1− C d e s t i n a t i o n C_{destination}Cdestination的alpha值
GL_CONSTANT_COLOR 常颜色向量C c o n s t a n t C_{constant}Cconstant
GL_ONE_MINUS_CONSTANT_COLOR 1−C c o n s t a n t C_{constant}Cconstant
GL_CONSTANT_ALPHA C c o n s t a n t C_{constant}Cconstant的alpha值
GL_ONE_MINUS_CONSTANT_ALPHA 1− C c o n s t a n t C_{constant}Cconstant的alpha值

我们也可以通过 void glBlendEquation(GLenum mode) 自定义操作符:

屏幕快照 2021-02-08 上午10.59.07.png

我们可以为 RGB 和 alpha 通道各自设置不同的混合因子,使用 glBlendFuncSeperate

//对 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);

另外需要格外注意的是,开启混合和深度测试绘制透明物体时,需要遵循物体距观察者(Camera)的距离,由远到近开始绘制,这样可以避免由于深度测试开启后(在透明物体后面)丢弃片元造成的奇怪现象。

未按照顺序绘制

image.png

由远到近顺序绘制

image.png

可以看出未按由远到近顺序绘制的结果,出现了透明物体遮挡了其他物体的奇怪现象,这是由深度测试造成的。

上述场景主要实现逻辑:

float ratio = (float)screenW / screenH;
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
//启动混合,设置混合因子
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_ProgramObj);
//绘制箱子(不透明)
glBindVertexArray(m_VaoIds[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureIds[0]);
glUniform1i(m_SamplerLoc, 0);
UpdateMatrix(m_MVPMatrix, 0, 0, 1.0,  glm::vec3(-1.0f, 0.0f, -1.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
UpdateMatrix(m_MVPMatrix, 0, 0, 1.0,  glm::vec3(2.0f, 0.0f, 0.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
//绘制地板(不透明)
glBindVertexArray(m_VaoIds[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureIds[1]);
glUniform1i(m_SamplerLoc, 0);
UpdateMatrix(m_MVPMatrix, 0, 0, 1.0, glm::vec3(0.0f,  0.0f,  0.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
//绘制窗户(透明)
glBindVertexArray(0);
glBindVertexArray(m_VaoIds[2]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureIds[2]);
glUniform1i(m_SamplerLoc, 0);
//容器 sorted 根据窗户距观察者的距离进行排序
for (auto it = sorted.rbegin(); it != sorted.rend(); ++it)
{
    //遵循物体距观察者(Camera)的距离,由远到近开始绘制
  UpdateMatrix(m_MVPMatrix, 0, 0 , 1.0, it->second, ratio);
  glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
  glDrawArrays(GL_TRIANGLES, 0, 6);
}
glBindVertexArray(0);

联系与交流

技术交流/获取源码可以添加我的微信:Byte-Flow


视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

阿里云社区.png

相关文章
|
1月前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
Android开发之使用OpenGL实现翻书动画
|
1月前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
Android开发之OpenGL的画笔工具GL10
|
5月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
58 0
|
5月前
|
XML Java Android开发
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
39 1
|
存储 编解码 算法
Opengl ES之LUT滤镜(上)
Opengl ES之连载系列
344 0
|
数据安全/隐私保护 开发者
OpenGL ES 多目标渲染(MRT)
Opengl ES连载系列
225 0
|
数据安全/隐私保护 索引
Opengl ES之纹理数组
Opengl ES连载系列
185 0
|
数据安全/隐私保护
Opengl ES之水印贴图
Opengl ES之连载系列
88 0
|
Java 数据安全/隐私保护 Android开发
Opengl ES之矩阵变换(下)
Opengl ES连载系列
84 0
|
Java API 数据安全/隐私保护
Opengl ES之矩阵变换(上)
Opengl ES连载系列
88 0