Opengl glBlendFunc,颜色混合公式,FrameBuffer混合颜色不正确,预乘alpha总结

对于底图颜色和透明度[c0,1],混合颜色[c1,a1],再混合颜色[c2,a2]。(a1,a2为0-1的不透明度,c0,c1,c2为rgb中任何一个颜色分量,底图为rgb,不透明度为1)

记作:[c0,1] blend [c1,a1] blend [c2,a2] = [cdst,adst]

通常:不透明颜色混合一个半透明颜色,结果为不透明,即:

[c0,1] blend [c1,a1] = [c0*(1-a1) + c1*a1,1]

所以[cdst,adst] = [(c0*(1-a1) + c1*a1)*(1-a2) + c2*a2,1]

又我们希望:[c0,1] blend [c1,a1] blend [c2,a2] == [c0,1] blend ([c1,a1] blend [c2,a2])

即,后面两个透明颜色先混合之后,最后与底图混合,颜色不变,即支持结合律

令 [c1,a1] blend [c2,a2] = [cx,ax],

[c0,1] blend [cx,ax] = [c0*(1-ax) + cx*ax,1] = [cdst,1],

1-ax = (1-a1)*(1-a2) => ax = a1+a2-a1*a2(对称的表达式,最终透明度与混合先后无关,且越混合越不透明)

cx = (c1*a1*(1-a2) + c2 * a2) / ax

[c1,a1] blend [c2,a2] = [ (c1 * a2 *(1-a2) + c2 * a2) / adst, adst=(a1+a2-a1*a2)]

由于最终的cdst需要除以adst,不够简洁,所以出现了预乘alpha的混合公式:

[Cdst,adst] = [C1,a1] blend [C2,a2] = [C1 * (1-a2) + C2,a1*(1-a2) + a2],C1 = c1*a1,C2=c2*a2,Cdst = cdst*adst

对应于Opengl中设置

glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

由于,实际使用的颜色,大多数都是非预乘的,所以更改一下混合算法

[Cdst,adst] = [C1,a1] blend [c2,a2] = [C1 * (1-a2) + c2*a2,a1*(1-a2) + a2]

对应Opengl中设置

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

就是源颜色应该乘以alpha之后,再当做预乘alpha混合运算,用这个公式有个前提,C1必须是预乘alpha的,也就是说,用这个公式,一个预乘alpha的颜色 混合 非预乘alpha的颜色,最终出来的也是一个预乘alpha的颜色

由此,可以得出一个结论,由于Opengl内部颜色混合运算使用的预乘alpha颜色混合算法,所以从FrameBuffer或者从显存中读rgba,都应该是预乘了alpha的图片。

如果要将FrameBuffer正确的混合到最终的图像上,首先FrameBuffer应该初始化一个预乘的颜色,通常是(0,0),接着把FrameBuffer按照预乘alpha的混合方式,混合到底图。

Opengl,DirectX内部使用预乘alpha,是由算法决定的,通过设置BlendFunc,虽然可以实现混合非预乘的颜色,但是原理是通过将非预乘alpha的颜色,预乘alpha之后再进行混合,并不是真正的非预乘颜色混合。

另外:不透明颜色,即是非预乘alpha,也是预乘alpha的颜色,两个公式都适用

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值