之前在项目中就使用过混合,但是研究的不深入,近期美术的一个需求让我下决心重新深入的研究了一下混合以及它在cocos2d-x中的使用,在这里分享给大家。混合(blend,有些翻译书上把它称作混融,以下简称混合),在openGL中,当一个输入的片元通过了所有相关的片元测试,就可以在与颜色缓存中当前的内容通过某种方式进行合并了。最简单的,也是默认的方式,就是直接覆盖已有的值,实际上不能称作是合并。除此之外,我们也可以将帧缓存中已有的颜色与输入的片元颜色进行混合。这是在openGL流程上的定义,从绘制图片的角度说,其实就是上层图片的颜色和下层图片的颜色的合成方式,一般情况下,上层图片会完全覆盖下层,但是有些时候,为了实现某些效果,上下层的图片颜色会有不同的合成算法,为了实现这些颜色混合效果,不仅仅是把上下层的颜色相加减这么简单,下面设几个参数
目标色:Dc 源色:Sc
目标色系数:Ds 原色系数:Ss
关于目标色和原色系数的计算方法,一共有如下的选项:
GL_ZERO (0,0,0)
GL_ONE (1,1,1)
GL_SRC_COLOR (Rs,Gs,Bs)
GL_ONE_MINUS_SRC_COLOR (1 - Rs,1 - Gs,1 - Bs)
GL_DST_COLOR (Rd,Gd,Bd)
GL_ONE_MINUS_DST_COLOR (1 - Rd,1 - Gd,1 - Bd)
GL_SRC_ALPHA (As,As,As)
GL_ONE_MINUS_SRC_ALPHA (1 - As,1 - As,1 - As)
GL_DST_ALPHA (Ad,Ad,Ad)
GL_ONE_MINUS_DST_ALPHA (1 - Ad,1 - Ad,1 - Ad)
GL_SRC_ALPHA_SATURATE (f,f,f) f=min(As,1 - Ad)
目标色和原色分别乘以系数计算后,将得到的两个值按照一定方法计算,就可以得到最后混合的颜色,计算方式包括:
GL_FUNC_ADD ScSs + DcDs
GL_FUNC_SUBTRACT ScSs - DcDs
GL_FUNC_REVERSE_SUBTRACT DcDs - ScSs
GL_MIN min(ScSs,DcDs)
GL_MAX max(ScSs,DcDs)
需要说明的是,默认情况下,目标色和原色的结合采用的是 GL_FUNC_ADD的方式。
另外需要说明的是,有另外两个函数 glBlendFuncSeparate和glBlendEquationSeparate分别设置rgb色和alpha的混合方式(第一个函数设置混合参数,第二个参数设置目标色和原色的混合计算方式)
一个完整的混合流程应该包括如下的三个步骤:
//开启混合
glEnable(GL_BLEND);
//设置混合方式
glBlendEquation(GL_FUNC_ADD);
//设置混合参数生成方式
glBlendFunc(sfactor, dfactor);
首先使用glEnable设置开启混合,然后通过调用glBlendEquation设置目标色和原色的结合方式,最后调用glBlendFunc设置原色和目标色系数的生成方式。
通过下面一个例子会更加深入的理解混合,在adobe的软件中有一个效果叫滤色,滤色是混合模式,存在于颜色混合模式、通道混合模式、图层混合模式的变亮模式组中。混合后的效果类似于多个摄影幻灯片在彼此之上投影。
使用滤色和不使用滤色的效果对比:
左边是使用滤色后的混合效果。
滤色的公式是:
结果色 = 1 - (1 - 原色)* (1 - 目标色)
= 1 - (1 + 原色 * 目标色 - 原色 - 目标色)
= 原色 + 目标色 - 原色 * 目标色
= 1 * 原色 + (1 - 原色)* 目标色
原色的系数是1,目标色的系数是(1 - 原色)
得出的结论是目标色和原色的系数分别是:
blendFunc.src = GL_ONE
blendFunc.dst = GL_ONE_MINUS_SRC_COLOR
这里再分享一个使用滤色的小技巧,在lua中尤其实用,不需要直接创建一个BlendFunc,可以先从精灵中获得这个对象,然后进行修改
local blendFunc = sp:getBlendFunc()
blendFunc.src = GL_ONE
blendFunc.dst = GL_ONE_MINUS_SRC_COLOR
sp:setBlendFunc(blendFunc)
能力不足,水平有限,如有错误,欢迎指出。