简介
预乘,指的是在数据提交给GPU之前,就对纹理的RGB分量与alpha值进行计算。
预乘计算
结果颜色 = 源颜色值 + 目标颜色值 * (1 - 源 alpha 值)
result = source.RGB + dest.RGB * (1 - source.A);
对应的颜色混合函数设置为 gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)。
不预乘计算
结果颜色 =(源颜色值 * 源 alpha 值)+ 目标颜色值 * (1 - 源 alpha 值)
result = source.RGB * source.A + dest.RGB * (1 - source.A);
即颜色混合函数的设置为 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)。
预乘解决的问题
- 把计算提前,可以提高混合效率
- 解决线性插值采样,正确渲染
例如:
以最常见的 filtering 方式线性插值为例,一个宽 2px 高 1px 的图片,左边的像素是红色,右边是绿色 10% 透明度,如果把这个图片缩放到 1x1 的大小,那么缩放后 1 像素的颜色就是左右两个像素线性插值的结果,也就是把两个像素各个通道加起来除以2。
- 如果使用没有 Premultiplied Alpha 的颜色进行插值,那么结果就是:((255, 0, 0, 1) + (0, 255, 0, 0.1)) * 0.5 = (127, 127, 0, 0.55)
- 如果绿色 Premultiplied Alpha,也就是(0, 255 * 0.1, 0, 0.1),和红色混合后:((255, 0, 0, 1) + (0, 25, 0, 0.1)) * 0.5 = (127, 25, 0, 0.55)
结论:Premultiplied Alpha 最重要的意义是使得带透明度图片纹理可以正常的进行线性插值
出现的原因
图片周边出现黑边或白边、动画周边出现黑边或白边、spine 的透明区域出现成片的白色
- 黑边或白边问题:因为图片周边存在完全透明(alpha=0),RGB颜色可能是黑色或者白色,因为默认是线性采样, 在采样纹理边界像素时,采样到了透明区域的像素,导致黑边出现。
- 空白区域是白色:是因为默认渲染模式是 gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA),同时又没有预乘,所以alpha通道没有渠道任何作用,导致空白区域的颜色渲染了出来。
解决办法
1,解决黑边或白边
羽化图片缘:把透明边界进行羽化,即有一个全透明到不透明的颜色色过度的过程 (也叫扩边)
例如:动态合图中,在把贴图写入大图时,为了防止颜色溢出,会把纹理四周多绘制1-2个像素,即采用了扩边
2,解决空白区域完全白色
问题:
spine透明通道问题 - Creator 3.x - Cocos中文社区
spine换肤突然多了个白色 - Creator 2.x - Cocos中文社区
3.xSpine premultipliedAlpha问题 - Creator 3.x - Cocos中文社区
参考资料:
iOS之深入解析预乘透明度Premultiplied Alpha_rgba图像blend srcalpha one additive-CSDN博客
关于ccc的spine动画中滤色(screen)属性渲染问题 - Creator 2.x - Cocos中文社区
#Cocos Creator# 2步解决DragonBones的黑边问题