专栏首页进击的多媒体开发OpenGL 中的颜色混合和使用

OpenGL 中的颜色混合和使用

因为 Latex 公式显示有问题,建议阅读原文获得更好的阅读体验

在 Android 中有一个类 PorterDuffXfermode ,它是用来设置颜色混合方式的,也就是在已有颜色的基础上再绘制一笔颜色,这两个颜色是如何进行混合的,是新绘制的颜色覆盖了原有颜色,还是新绘制的颜色和原有颜色混合组成另一种颜色呢。

在 OpenGL 中同样有这样颜色混合的问题。

在 OpenGL 的世界模型中是有深度的概念的,也就是由 z 轴坐标值来决定物体距离坐标原地的远近,但到最后世界模型里的物体都要投影到近平面,最后映射到视口上。而且,距离相机也就是视口越近的物体,就会遮住后面的物体,就和用肉眼去观察物体一下,后面的形状会被前面的形状挡住。

但和肉眼观察不同的是,OpenGL 里最终呈现的颜色,是将两个片元混合之后计算的值,我们可以改变这片元混合的方式,这就和前面 Android 里面提到的 PorterDuffXfermode 混合模式一样。

颜色混合基础知识

OpenGL 中的颜色混合就是将通过各种测试准备进入帧缓冲的片元(源片元)与帧缓冲中的原有片元(目标片元)按照设定的比例加权计算最终片元的颜色值。新片元不一定是直接覆盖缓冲区中的源片元。

混合因子

OpenGL 通过设置混合因子来指定两个片元的加权比例,每次都需要给出两个混合因子:

  • 源因子,用于确定将进入帧缓冲的片元在最终片元中的比例
  • 目标因子,用于确定原帧缓冲中的片元在最终片元中的比例

由于 OpenGL 中每个颜色值包括 4 个色彩通道,因此,两种混子因子都有 4 个分量值,分别对应一个色彩通道,具体混合计算细节如下:

  • 设源因子和目标因子分别为

,S 表示是源因子,D 表示是目标因子,r,g,b,a 下标分别表示 红、绿、蓝、透明度 4 个色彩通道。

  • 设源片元和目标片元的颜色值分别为

,R,G,B,A 分别表示红、绿、蓝、透明度 4 个色彩通道,s 下标表示源片元,d 下标表示目标片元。

  • 混合后最终片元颜色各个色彩通道的值是由颜色混合方程式计算而来,系统提供的常用颜色混合方程式如下:

混合方程式

方程式名

最终片元颜色各个色彩通道的值

GL_FUNC_ADD

[R_sS_r+R_dD_r, G_sS_g+G_dD_g, B_sS_b+B_dD_b, A_sS_a+A_dD_a]

GL_FUNC_SUBTRACT

[R_sS_r-R_dD_r, G_sS_g-G_dD_g, B_sS_b-B_dD_b, A_sS_a-A_dD_a]

GL_FUNC_REVERSE_SUBTRACT

[R_dD_r-R_sS_r, G_dD_g-G_sS_g, B_dD_b-B_sS_b, A_dD_a-A_sS_a]

GL_MIN

[min(R_sS_r,R_dD_r),min(G_sS_g,G_dD_g),min(B_sS_b,B_dD_b),min(A_sS_a,A_dD_a)]

GL_MAX

[max(R_sS_r,R_dD_r),max(G_sS_g,G_dD_g),max(B_sS_b,B_dD_b),max(A_sS_a,A_dD_a)]

默认情况下,系统会自动调用 GL_FUNC_ADD 混合方程式来计算最终片元颜色各个色彩通道的值,如果想要调用其他混合方程式来计算最终的片元颜色,系统也有提供对应的方法:

方法签名

说明

glBlendEquation(int mode)

mode 参数的含义为指定混合方程式,用来计算最终片元的颜色,其值为混合方程式的名字

glBlendEquationSeparate(int modeRGB,int modeAlpha)

modeRGB 参数为颜色的 RGB 通道进行混合时所使用的混合方程式名,modeAlpha 参数的含义是颜色的 Alpha 透明度通道进行混合时所使用的混合方程式名字,通过其可以实现 RGB 和 Alpha 通道单独指定混合方程式的功能

源因子和目标因子

对于颜色混合来说,选定了混合方程式,接下来最重要的就是设置混合因子了。

在 OpenGL 中预置了一些混合因子,如下表:

常量名

RGB 混合因子

A 混合因子

GL_ZERO

[0,0,0]

0

GL_ONE

[1,1,1]

1

GL_SRC_COLOR

[R_s,G_s,B_s]

A_s

GL_ONE_MINUS_SRC_COLOR

[1-R_s,1-G_s,1-B_s]

1-As

GL_DST_COLOR

[R_d,G_d,B_d]

A_d

GL_ONE_MINUS_DST_COLOR

[1- R_d, 1- G_d, 1- B_d]

1-A_d

GL_SRC_ALPHA

[A_s, A_s, A_s]

A_s

GL_ONE_MINUS_SRC_ ALPHA

[1- A_s, 1- A_s, 1- A_s]

1-As

GL_DST_ ALPHA

[A_d, A_d, A_d]

A_d

GL_ONE_MINUS_DST_ ALPHA

[1- A_d, 1- A_d, 1- A_d]

1-A_d

GL_SRC_ALPHA_SATURATE

[f , f, f] f=min(A_s, 1-A_d)

1

GL_CONSTANT_COLOR

[R_c, G_c, B_c]

A_c

GL_ONE_MINUS_CONSTANT_COLOR

[1- R_c, 1- G_c, 1- B_c]

1-A_c

GL_CONSTANT_ALPHA

[Ac, Ac, Ac]

A_c

GL_ONE_MINUS_CONSTANT_ALPHA

[1- Ac, 1- Ac, 1- Ac]

1- Ac

其中,常量名称中有 SRC 代表各通道值来自源片元,有 DST 代表各通道值来自目标片元,另外 GL_SRC_ALPHA_SATURATE 只能用作源因子。

对于常量名中有 CONSTANT 的代表使用预设颜色常量值对应色彩通道的值作为相应的因子值,其中的 R_c、G_c、B_c、A_c 分别代表预设颜色常量值的 RGBA 通道的值,如果没有设置则默认值为

设置颜色常量值使用的是 glBlendColor 方法,如下:

1    public static native void glBlendColor(
2        float red,
3        float green,
4        float blue,
5        float alpha
6    );

设置混合的方法

有了混合因子,接下来就是设置混合因子了,OpenGL 提供了如下方法来设置:

方法签名

说明

glBlendFunc(GLenum sfactor, GLenum dfactor)

第一个参数为设置的源因子,第二个参数为设置的目标因子,其值如上表

glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha,GLenum dstAlpha)

第一个参数为设置源因子的 RGB 值;第二个参数为设置目标因子 RGB 值;第三个参数为设置源因子 Alpha 的值;第四个参数为设置目标因子 Alpha 的值。该方法实现了 RGB 和 Alpha 通道单独指定混合因子值的功能

常用混合组合

对于混合因子和混合 方程式的组合太多了,恰当的组合可以产生很好的效果,下面给出两组常用的组合:

  • 源因子 GL_SRC_ALPHA ,目标因子 GL_ONE_MINUS_SRC_ALPHA ,即源因子和目标因子分别为

。此组合实现的是最典型的半透明遮挡效果。若源片元是透明的,则根据透明度透过后面的内容;若源片元不透明,则仅能看到源片元,因此,使用此组合时往往会采用半透明的纹理或颜色对源片元着色。

  • 源因子 GL_SRC_COLOR ,目标因子 GL_ONE_MINUS_SRC_COLOR ,即源因子和目标因子分别为

。此组合可以实现滤光镜效果,也就是平时透过有色眼镜或玻璃观察事物的感觉。与第一种常用组合不同,此组合不要求应用于源片元的颜色或者纹理是半透明的。

具体使用

前面讲了这么多理论,其实就是阐述两个颜色的 RGBA 值如何计算得到最后的 RGBA 值,并且每一个 R、G、B、A 分量都是两个颜色的 R、G、B、A 对应乘以不同的混合因子后相加得到的,这个混合因子的设置可以根据源片元的颜色来设定,也可以根据目标片元的颜色来设定。

先假设有这样的场景:

通过这样的图片经过混合后去查看后面的内容,类似于刺激战场上开镜效果,

显然,图片的黑色区域是要可以透过看到后面内容的,绿色区域也是一样,不然就全遮盖住后面内容了。

这里就可以用到上面的混合因子组合,源因子 GL_SRC_COLOR,目标因子 GL_ONE_MINUS_SRC_COLOR ,这个混合因子是根据源片元的颜色来设定的。

根据这两个混合因子和混合方程式计算,可以得出最后的颜色值。

根据源因子 GL_SRC_COLOR 计算,由于黑色的 RGB 值都为 0 ,RGB 混合因子都为 0,也就是透明的,源片元不会进入到最终片元。

根据源因子 GL_ONE_MINUS_SRC_COLOR 计算,由于黑色的 RGB 值都为 0 ,那么目标颜色的混合因子都为 1,也就是目标颜色都会被显示,可以看到后面的物体。

对于绿色部分,就不存在为0 或者为 1 的情况了,就是两个颜色按照混合因子计算后的值了。

具体的使用过程很简单,大致代码如下:

1            // 先绘制好背景内容 
2            // 开启颜色混合进行绘制
3            GLES20.glEnable(GLES20.GL_BLEND)
4            // 设置混合因子
5            GLES20.glBlendFunc(GLES20.GL_SRC_COLOR, GLES20.GL_ONE_MINUS_SRC_COLOR)
6            // 绘制操作
7            rect!!.drawSelf(textureId)
8            MatrixState.popMatrix()

最后效果如下:

当然,还可以使用另外一种混合因子组合 GL_SRC_ALPHA 和 GL_ONE_MINUS_SRC_ALPHA,根据源因子的透明度来设置混合因子。

关于如何使用 GL_SRC_ALPHA 和 GL_ONE_MINUS_SRC_ALPHA 混合因子,可以参考之前的文章 用 OpenGL 对视频帧内容进行替换,大概原理都一样的,就是图片换成带透明度的,并且更改一下混合因子组合,就不赘述了。

具体的实现可以参考我的 Github 项目,求一波 Star 。

https://github.com/glumes/AndroidOpenGLTutorial

本文分享自微信公众号 - 纸上浅谈(glumes_blog),作者:glumes

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-07-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ​OpenGL 学习系列---坐标系统

    在前面绘制基本图形中,遇到了很明显的问题,圆形不像圆形,正多边形不像正多边形?就像下面图形一样:

    glumes
  • OpenGL 学习系列---基本形状的绘制

    在之前的一篇博客中,讲述了 OpenGL 基础绘制流程 及相关的代码,其中关于 OpenGL 程序编译部分都是可以在其他项目中接着复用的,接下来会讲到如何去绘制...

    glumes
  • 博客图床迁移记

    前几天在群里看到说新浪微博图床挂掉了,图床上的图片链接单独访问还可以,但是在博客文章上就显示不出来了。

    glumes
  • 软件渠道商平均净利润率为15.8%,用友、金蝶渠道商均跑输大盘

    在浩浩荡荡的云端转型浪潮下,软件渠道商生存状态如何?在4月11日由人称T客主办的2019 中国软件渠道伙伴峰会上,T研究联合创始人&高级分析师吴勇带来了T研究对...

    人称T客
  • 渠道商的自我救赎

    从“得渠道者得天下”的王者到SaaS时代需不需要渠道的讨论,从拉新“打单”的拓客到经营老客户,随着云计算等新技术的发展以及其他外部环境的变化,渠道商受到了很大的...

    人称T客
  • 调研:压榨吸干 渠道商熬不了几年变革势在必行

    在上一篇《怨声载道 用友系获渠道商“差评”》的解读中,很多人留言表示,这一评价结果非常客观公正,甚至说渠道商们多少对厂商有些手下留情了,要不然分数应该更低一些。...

    人称T客
  • 苹果匠艺:乔布斯身边的天才

    用户1682855
  • 计算机视觉领域如何从别人的论文里获取自己的idea?

    作者:Cheng Li https://www.zhihu.com/question/353691411/answer/900046621

    小小詹同学
  • centos修改主机名 root@后面的名字

    阿里云买的新的ESC,名字都是一串字符,不利于平时使用。我们可以重命名主机来标记。

    Ryan-Miao
  • 跨平台移动开发 Flutter 初体验安装flutter安装VSCode新建Flutter工程Tips

    打开 Terminal 先cd到你需要安装的目录下, 我这里直接在 ~ 个人目录下

    gwk_iOS

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动