OpenGL ES 高级进阶:颜色混合

5,157 阅读3分钟

大家好,这是我的OpenGL ES 高级进阶系列文章,在我的github上有一个与本系列文章对应的项目,欢迎关注,链接:github.com/kenneycode/…

今天给大家介绍OpenGL的颜色混合,什么是颜色混合呢?颜色混合就是把两种颜色按某种规则混合起来得到新的颜色,来看一张图:

比如我们两种颜色颜色,一种是纯蓝色ARGB(255, 0, 0, 255),一种是纯绿色ARGB(255, 0, 255, 0),混合时分别各取一半,就得到了混合后的颜色ARGB(255, 0, 127, 127),这就是颜色合混的基本概念。

那么什么时候需要用到颜色混合?我们来看一种最常见的情况,我们把一张带有透明部分的纹理渲染到另一张纹理上,会怎样?

大家可能会说,这不是很显然吗?透明部分会把底图透出来,但如果你在OpenGL里不使用颜色混合直接渲染,你会发现结果是这样的:

透明部分并没有把底图透出来,这是为什么呢?因为颜色混合默认是关闭的,当没开启颜色混合时,把一个颜色渲染到另一个颜色上,新的颜色就会把原颜色完全覆盖,从而得到一个alpha为0的颜色,透出了最底层的黑色。

我们来看看如何用颜色混合来解决这个问题,首先需要开启颜色混合:

// 启用颜色混合
// Enable color blend
GLES30.glEnable(GLES30.GL_BLEND)

还需要设置混合方式,所谓混合方式的就是指定源颜色(将要渲染的颜色)和目标颜色(已经存在的底图颜色)以何种方式进行混合,例如文章开篇时,以源颜色和目标颜色各占0.5的方式进行混合,用式子来表示就是:

			混合后颜色 = 源颜色 * 源因子 + 目标颜色 * 目标因子

OpenGL内置了多种混合方式,通过glBlendFunc()来设置,第一个参数是设置源因子,第二个参数是设置目标因子,在这里,我们需要这样设置:

// 设置混合方式
// Set blend functions
GLES30.glBlendFunc(GLES30.GL_SRC_ALPHA, GLES30.GL_ONE_MINUS_SRC_ALPHA)

GL_SRC_ALPHA表示取源颜色的alpha值作为因子,GL_ONE_MINUS_SRC_ALPHA表示取1减去源颜色的alpha值作为因子,这样能得到什么效果呢?

先来看看源颜色的透明部分和目标颜色(底图颜色)的不透明部分混合,假设我们的目标颜色是ARGB_DST=(1.0, a, b, c),源颜色是ARGB_SRC=(0.0, d, e, f)

此时:

            混合后颜色 = ARGB_SRC * 0.0 + ARGB_DST * (1.0 - 0.0) = ARGB_DST

再来看看源颜色的不透明部分和目标颜色(底图颜色)的不透明部分混合,假设我们的目标颜色是ARGB_DST=(1.0, a, b, c),源颜色是ARGB_SRC=(1.0, d, e, f)

此时:

            混合后颜色 = ARGB_SRC * 1.0 + ARGB_DST * (1.0 - 1.0) = ARGB_SRC

因此效果就是,源图中的透明部分,渲染后的颜色完全是底图颜色,等于透出了底图,源图中的不透明部分,渲染之后的颜色完全是源图的颜色:

这样就得到了正确的效果。

我们再来试试GL_ONE

GLES30.glBlendFunc(GLES30.GL_ONE, GLES30.GL_ONE)

这样就是

                    混合后颜色 = ARGB_SRC * 1.0 + ARGB_DST * 1.0

来看效果:

还有很多种混合方式可以设置,具体可以查询官方文档:www.khronos.org/registry/Op…

glBlendFunc设置的混合因子会同时作用于RGBA四个通道上,我们还可以将A通道和RGB通道设置不同的混合因子:

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

有时内置的混合方式有时候并不能满足我们的要求,例如要实现:

                    混合后颜色 = 源颜色 * 0.123 + 目标颜色 * 0.877

这时用内置的混合方式就不能实现,因为混合因子不能任意设置,这时可以自己在fragment shader中实现。

代码在我githubOpenGLESPro项目中,本文对应的是SampleColorBlend,项目链接:[github.com/kenneycode/…github.com/kenneycode/…

感谢阅读!