像素与透明度叠加

Pixels Overlay With transparency

本文关键字:叠加 透明度 像素      更新时间:2023-10-16

我有 2 个像素B8G8R8A8 (32( 格式。 两个像素(顶部和底部(都具有透明度(Alpha通道<255(

在底部像素上叠加顶部像素的方法(公式(是什么? (不使用第三方(。

我试图做这样的事情

struct FColor
{
public:
// Variables.
#if PLATFORM_LITTLE_ENDIAN
#ifdef _MSC_VER
// Win32 x86
union { struct{ uint8 B,G,R,A; }; uint32 AlignmentDummy; };
#else
// Linux x86, etc
uint8 B GCC_ALIGN(4);
uint8 G,R,A;
#endif
#else // PLATFORM_LITTLE_ENDIAN
union { struct{ uint8 A,R,G,B; }; uint32 AlignmentDummy; };
#endif
//...
};
FORCEINLINE FColor AlphaBlendColors(FColor pixel1, FColor pixel2)
{
FColor blendedColor;
//Calculate new Alpha:
uint8 newAlpha = 0;
newAlpha = pixel1.A + pixel2.A * (255 - pixel1.A);
//get FColor as uint32
uint32 colora = pixel1.DWColor();
uint32 colorb = pixel2.DWColor();
uint32 rb1 = ((0x100 - newAlpha) * (colora & 0xFF00FF)) >> 8;
uint32 rb2 = (newAlpha * (colorb & 0xFF00FF)) >> 8;
uint32 g1 = ((0x100 - newAlpha) * (colora & 0x00FF00)) >> 8;
uint32 g2 = (newAlpha * (colorb & 0x00FF00)) >> 8;
blendedColor = FColor(((rb1 | rb2) & 0xFF00FF) + ((g1 | g2) & 0x00FF00));

blendedColor.A = newAlpha;
return blendedColor;
}

但结果远不是我想要的:-(

我寻找了一些 Alpha 混合公式(我从来不明白我将如何计算叠加层的新 alpha(->也许我走错了方向?

编辑:

newAlpha更改为newAlpha = FMath::Min(pixel1.A + pixel2.A, 255);实际上给出了更好的结果,但是这样计算是否正确?我在这里错过了什么吗?

基于已接受答案的工作示例(

FORCEINLINE FColor AlphaBlendColors(FColor BottomPixel, FColor TopPixel)
{
FColor blendedColor;
//Calculate new Alpha:
float normA1 = 0.003921568627451f * (TopPixel.A);
float normA2 = 0.003921568627451f * (BottomPixel.A);
uint8 newAlpha = (uint8)((normA1 + normA2 * (1.0f - normA1)) * 255.0f);
if (newAlpha == 0)
{
return FColor(0,0,0,0);
}
//Going By Straight Alpha formula
float dstCoef = normA2 * (1.0f - normA1);
float multiplier = 255.0f / float(newAlpha);
blendedColor.R = (uint8)((TopPixel.R * normA1 + BottomPixel.R * dstCoef) * multiplier);
blendedColor.G = (uint8)((TopPixel.G * normA1 + BottomPixel.G * dstCoef) * multiplier);
blendedColor.B = (uint8)((TopPixel.B * normA1 + BottomPixel.B * dstCoef) * multiplier);
blendedColor.A = newAlpha;
return blendedColor;
}

首先假设下面有第三个像素恰好是不透明的。

对于进一步的表示法,我将假设 alpha 值在 [0,1] 中。

给定:三个像素,第一个像素在顶部,颜色c_1、c_2、c_3、alpha 值a_1、a_2、a_3 = 1

那么得到的 alpha 值显然是 1,颜色是

(a_1)*c_1 + (1-a_1)(*a_2)*c_2 + (1-a_1)*(1-a_2)*c_3

现在,我们想c_k找到一些值,a_k以便上面的公式等于

(a_k)*c_k + (1-a_k)*c_3

我们可以通过两个步骤解决这个问题:

(1-a_k) = (1-a_1)*(1-a_2)
->
a_k = 1-(1-a_1)*(1-a_2)

(a_k)*c_k = (a_1)*c_1 + (1-a_1)(*a_2)*c_2
->
c_k = [(a_1)*c_1 + (1-a_1)(*a_2)*c_2] / a_k

使用这些公式(alpha值的范围不同(,您将获得所需的颜色。

(不要忘记抓住a_k = 0(

编辑:第三个像素的解释:

当您以任何方式使用两个像素时,即执行导致其用于显示某些内容的操作,它们将被置于其他不透明的现有颜色上。例如,这可能是背景色,但也可能是在某些背景色上应用更多透明像素的结果。

我现在要做的是将你的两种颜色结合起来,找到一种表现得和这两种颜色一样的颜色。也就是说,将其放在某种不透明颜色的顶部应该与将原始的两种颜色放在其顶部的结果相同。这就是我对新颜色的要求,导致我使用的公式。

该公式只不过是在第三种颜色上连续应用两种颜色的结果。