我正在尝试实现预乘Alpha混合。在这个页面上:What Is Color Blending?,它们确实解释了标准的alpha混合,但没有解释预乘的值。
Alpha混合:(来源×Blend.SourceAlpha)+(目的地×Blend.InvSourceAlpha)
根据公式,它转化为:
a = ((srcA * srcA) >> 8) + ((tgtA * (255 - srcA)) >> 8);
r = ((srcR * srcA) >> 8) + ((tgtR * (255 - srcA)) >> 8);
g = ((srcG * srcA) >> 8) + ((tgtG * (255 - srcA)) >> 8);
b = ((srcB * srcA) >> 8) + ((tgtB * (255 - srcA)) >> 8);
显然有效......
现在我如何将其转换为处理预乘值?
a = ((srcA)) + ((tgtA * (255 - srcA)) >> 8);
r = ((srcR)) + ((tgtR * (255 - srcA)) >> 8);
g = ((srcG)) + ((tgtG * (255 - srcA)) >> 8);
b = ((srcB)) + ((tgtB * (255 - srcA)) >> 8);
由于它已预先成倍增加,我在第一个任期中放弃了乘法......对! 但结果是在α混合和添加剂混合之间,更倾向于添加剂。最后它看起来并不太混合。它可能是错的,因为它看起来应该像经典的alpha混合;或者这是预期的行为?
谢谢。
答案 0 :(得分:4)
预乘的原因是因为在将源图像添加到目标之前,它实际上最终会对目标的alpha进行平方
例如。如果没有预先乘法,我们会得到源图像数据:
srcA = origA
srcR = origR
srcG = origG
srcB = origB
我们在应用于目标时得到了这个结果图像:
a = ((srcA * srcA) >> 8) + ((tgtA * (255 - srcA)) >> 8)
r = ((srcR * srcA) >> 8) + ((tgtR * (255 - srcA)) >> 8)
g = ((srcG * srcA) >> 8) + ((tgtG * (255 - srcA)) >> 8)
b = ((srcB * srcA) >> 8) + ((tgtB * (255 - srcA)) >> 8)
扩展这个我们得到:
a = ((origA * origA) >> 8) + ((tgtA * (255 - origA)) >> 8)
r = ((origR * origA) >> 8) + ((tgtR * (255 - origA)) >> 8)
g = ((origG * origA) >> 8) + ((tgtG * (255 - origA)) >> 8)
b = ((origB * origA) >> 8) + ((tgtB * (255 - origA)) >> 8)
那里没有惊喜......
现在我们得到预乘的源图像数据:
srcA = (origA * origA) >> 8
srcR = (origR * origA) >> 8
srcG = (origG * origA) >> 8
srcB = (origB * origA) >> 8
当应用于目标时:
a = (srcA >> 8) + ((tgtA * (255 - srcA)) >> 8);
r = (srcR >> 8) + ((tgtR * (255 - srcA)) >> 8);
g = (srcG >> 8) + ((tgtG * (255 - srcA)) >> 8);
b = (srcB >> 8) + ((tgtB * (255 - srcA)) >> 8);
好的,所以我们知道这一点,但是如果我们扩展它,你会看到差异:
a = (origA * origA) >> 8 + ((tgtA * (255 – ((origA * origA) >> 8))) >> 8);
r = (origR * origA) >> 8 + ((tgtR * (255 - ((origA * origA) >> 8))) >> 8);
g = (origG * origA) >> 8 + ((tgtG * (255 – ((origA * origA) >> 8))) >> 8);
b = (origB * origA) >> 8 + ((tgtB * (255 – ((origA * origA) >> 8))) >> 8);
将其与NON Pre-Multiplied扩展:
进行比较a = ((origA * origA) >> 8) + ((tgtA * (255 - origA)) >> 8)
r = ((origR * origA) >> 8) + ((tgtR * (255 - origA)) >> 8)
g = ((origG * origA) >> 8) + ((tgtG * (255 - origA)) >> 8)
b = ((origB * origA) >> 8) + ((tgtB * (255 - origA)) >> 8)
直接你可以看到我们在将origA值应用到目标时对其进行平方,这意味着更多的目标将通过生成的颜色值。
通过对你说,你想要更多的目标来实现。
这就是为什么在预乘时它会消除透明块周围的条带数量,因为那些具有较低Alpha值的像素获得的目标像素数比未预先相乘时更多,这种情况发生在指数上规模。
我希望这可以解决它。
答案 1 :(得分:2)
您遇到的问题取决于您是否将源alpha值预先乘以预乘的一部分。如果你这样做,那么你在目标乘法中使用的srcA就是真实源Alpha的平方,所以你需要取平方根进行计算:
originalSrcA = Math.Sqrt(srcA);
a = ((srcA)) + ((tgtA * (255 - originalSrcA)) >> 8);
r = ((srcR)) + ((tgtR * (255 - originalSrcA)) >> 8);
g = ((srcG)) + ((tgtG * (255 - originalSrcA)) >> 8);
b = ((srcB)) + ((tgtB * (255 - originalSrcA)) >> 8);
如果你没有预先乘以它(我认为更有可能),你需要自己乘以得到与工作结果相同的结果:
a = ((srcA * srcA) >> 8) + ((tgtA * (255 - srcA)) >> 8);
r = ((srcR)) + ((tgtR * (255 - srcA)) >> 8);
g = ((srcG)) + ((tgtG * (255 - srcA)) >> 8);
b = ((srcB)) + ((tgtB * (255 - srcA)) >> 8);
答案 2 :(得分:1)
一个疯狂的猜测:你是否改变了混合量(srcA)?如果是这样,您必须重新计算位图中的预乘Alpha值。如果不这样做,您将获得类似于添加的效果,这可能就是您所描述的。
答案 3 :(得分:0)
经过多次尝试,这就是我想出的:
我也预先乘以alpha通道,我保留了我的第二个公式,我先发布了;这是我得到的最好的结果。
在我发现的最好的文档中,当预乘时,丑陋的边界消失了: http://www.td-grafik.de/ext/xfrog/alpha/index.html和 http://blogs.msdn.com/b/shawnhar/archive/2010/04/08/premultiplied-alpha-in-xna-game-studio-4-0.aspx
嗯,传统的alpha混合并不是真正的比较参考,我想我现在就是因为它看起来比普通的alpha混合更好。
但说实话,我真的不明白100%,(看起来)它有效;另一个谜......
这就是让我觉得没关系的原因;
左:alpha混合; 右:预乘
谢谢大家的帮助!