最近被项目上一个bug折腾的够呛,后来发现问题又是出在alpha blending上面。
其实一直以来对这个东西的了解和认知都处在一个比较浅显的层次上,直到遇到问题,才发现自己还是欠缺深入的理解。今天借着这个机会,争取一次性搞懂里面的细节。首先我们要了解一个概念,预乘alpha的RGBA (premutiplied alpha),和直出alpha的RGBA( straight alpha)
所谓的预乘alpha是指,RGBA的RGB 是已经乘了alpha的,所以,我们可以直接得到一个简单的结论,预乘alpha的RGB总是小于等于Alpha的
那么直出的RGBA就是比较好理解的了,就是RGBA.
这俩概念单独这么说,体现不出来哪里复杂,我们先看一个两个半透明alpha图层叠加的例子;
上层颜色是(147,137,226,0.73)下层是(147,172,11,0.8)
按照我们的理论, 合成后的颜色是: R1 * A1 + R2 * A2 * (1 - A1) = 144.6480 137.0480 208.6240
合成后的alpha是 A1 + A2 * (1 - A1) = 0.9840
这里有点问题,在PS里做这个实验,结果有一点偏差,PS的结果是147, 139, 213;但是在PPT里面算的导师比较接近是144 137 209;
可能是PS里有很多混合模式,我没有选择对?这里大家有比较清楚的吗?欢迎评论区留言一起讨论
下一个问题更加直击灵魂,那就是如果我要在这俩图层上再爹一个图层会是神马效果?
假设上面的这个图层的参数是(178 42 0, 0.6)
我们算出来是164 79 82 , PS的结果是166 80 84, PPT的结果是165 80 84
还有一个比较有趣的问题,根据我们的算法,如果先叠加上面两层,叠加后的结果再和底层叠加可以得到结果一;然后我们改变一下次序,先叠加下面两层,然后再和上层叠加得到结果二。我们按照公式,在matlab里面再算一下子:
C0 = [178 42 0]; A0 = 0.6; C1 = [147,137,226]; A1 = 0.92; C2 = [147 172 11]; A2 = 0.8; C01 = C0 * A0 + C1 * A1 * (1 - A0); A01 = A0 + A1 * (1 - A0); C01_2 = C01 * A01 + C2 * A2 * (1 - A01) C12 = C1 * A1 + C2 * A2 * (1 - A1); A12 = A1 + A2 * (1 - A1); C0_12 = C0 * A0 + C12 * A12 * (1 - A0)
结果如下:
C01_2 = 159.5105 77.5995 80.7882 C0_12 = 163.7335 79.1421 82.1144
可见,按照这个公式算下来,逻辑上是无法自洽的,计算顺序的不同竟然会影响到最终的结果,也就是说,这个运算它不满足结合律
也就是(AB)C != A(BC) 这就有点尴尬了。那么该怎么理解呢,没什么不好理解,如果把这个blending的过程两种方法代数展开,是可以发现的确不相等的。这里我们如果选择相信公式,因为这个公式是我们自己定义的,我们是定义了一种运算,然后发现这种运算不满足结合律。这就是我们的发现;那么对于三层及以上的blending, 我们的做法一般是先算底层的的叠加结果,然后往上层依次递推,也就是上面的C0_12的算法。
为什么要这么算呢,我觉得还是不要问,问就是这么规定的,物体的光线从远处朝着我们的眼睛入射。这就是原因。
另外在尾部再补充一段代码,用matlab算符号表达式,然后代入值快速验证:
clear,clc; syms R1 R2 R3 A1 A2 A3 C1 C2 C1 = R1 * A1 + [R2 * A2 + R3 * A3 * (1 - A2)]*(1 - A1)*(A2 + A3 - A2 * A3); C2 = [R1 * A1 + R2 * A2 * (1 - A1)] * (A1 + A2 - A1*A2) + R3*A3*(1 - A1 - A2 + A1*A2); c1 = subs(C1,[R1, R2, R3, A1, A2, A3],[10, 20, 30, 0.1, 0.3, 0.4]); c2 = subs(C2,[R1, R2, R3, A1, A2, A3],[10, 20, 30, 0.1, 0.3, 0.4]); fprintf('c1 = %3.2f, c2 = %3.2f', double(c1), double(c2))