NDK OpenGL ES 3.0 开发(十二):混合-阿里云开发者社区

开发者社区> 视频云小助手> 正文

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_ZERO0
GL_ONE1
GL_SRC_COLOR源颜色向量C s o u r c e C_{source}Csource
GL_ONE_MINUS_SRC_COLOR1−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_COLOR1−C d e s t i n a t i o n C_{destination}Cdestination
GL_SRC_ALPHAC s o u r c e C_{source}Csource的alpha值
GL_ONE_MINUS_SRC_ALPHA1− C s o u r c e C_{source}Csource的alpha值
GL_DST_ALPHAC d e s t i n a t i o n C_{destination}Cdestination的alpha值
GL_ONE_MINUS_DST_ALPHA1− 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_COLOR1−C c o n s t a n t C_{constant}Cconstant
GL_CONSTANT_ALPHAC c o n s t a n t C_{constant}Cconstant的alpha值
GL_ONE_MINUS_CONSTANT_ALPHA1− 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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
NDK OpenGL ES 3.0 开发(十六):相机预览
相机开发是 OpenGL ES 的重要应用,利用 OpenGL 可以很方便地实现相机美颜、滤镜、塑型以及一些动态特效,其性能显著优于对应功能的 CPU 实现。
187 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10088 0
NDK OpenGL ES 3.0 开发(十五):立方体贴图(天空盒)
OpenGL ES 立方体贴图本质上还是纹理映射,是一种 3D 纹理映射。立方体贴图所使的纹理称为立方图纹理,它是由 6 个单独的 2D 纹理组成,每个 2D 纹理是立方图的一个面
59 0
NDK OpenGL ES 3.0 开发(十四):粒子(Particles)
粒子系统本质上是通过一次或者多次渲染绘制出大量位置、形状或者颜色不同的物体(粒子),形成大量粒子运动的视觉效果。所以,粒子系统天然适合用OpenGL ES 实例化(Instancing)实现。
174 0
04.Eclipse下Ndk开发(以文件拆分合并为例模拟一下开发过程,参考文件加密的过程)
(创建于2017/12/6) 1.工具类PatchUtils package com.ren.ndk_file_patch; public class PatchUtils { static{ System.
826 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13891 0
NDK OpenGL ES 3.0 开发(十二):混合
OpenGL ES 混合本质上是将 2 个片元的颜色进行调和,产生一个新的颜色。OpenGL ES 混合发生在片元通过各项测试之后,准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值,不再是新(源)片元直接覆盖缓冲区中的(目标)片元。
92 0
NDK OpenGL ES 3.0 开发(十三):实例化(Instancing)
OpenGL ES 实例化(Instancing)是一种只调用一次渲染函数就能绘制出很多物体的技术,可以实现将数据一次性发送给 GPU ,告诉 OpenGL ES 使用一个绘制函数,将这些数据绘制成多个物体。
77 0
10.Eclipse下Ndk开发(ffmpeg native 方式播放视频,万能解码(SurfaceView, 播放音频,)
(创建于2018/1/26) 遇到的问题 遇到一个很棘手的问题,在Eclipse上引入两个头文件报错 #include #include 右键->Porperties->C/C++General->Paths and Symbols中可以看到 987671.
1143 0
OPENGL学习【一】VS2008开发OPENGL程序开发环境搭建
版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79241439 1.VS2008工具自行在网上下载安装,现只提供VS2008开发工具中配置OPENGL环境的详细步骤。
1017 0
230
文章
0
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载