
Alpha Blending幾乎是每個3D應用程序的一小部分,但卻很重要。從概念上講,alpha混合用於傳達表面的透明度。通常,消費者應用程序(游戲)傾向於使用RGB來傳達下層表面的顏色,依賴於alpha通道來指示該顏色的“不透明度”。更具體地說,當在管道中啟用alpha混合時,開發人員傾向於使用此表單進行混合:
DestinationColor.rgb = (SourceColor.rgb * SourceColor.a) + (DestinationColor.rgb * (1 - SourceColor.a));
在舊的,固定的功能中,這將被稱為“SourceAlpha,InvSourceAlpha”; 也被稱為“后倍增α”。然而,這種形式的alpha混合存在一個嚴重的缺陷:在許多情況下它會導致錯誤的顏色!最簡單的這些情況可以通過一個簡單的雙像素圖像來說明:

考慮上面的圖像,其分辨率為2x1像素。藝術家想要傳達的是,在綠色像素旁邊有一個紅色的不透明像素,它只會給它背后的物體帶來最輕微的綠色。但是,當我們生成下一個mipmap級別1x1級別時會發生一些有趣的事情。結果可能令人驚訝; 生成的mipmapped紋素是這樣的:

當我們接近這個mipmap級別時,我們將獲得與使用2x1級別時非常不同的結果 - 完全是因為我們決定使用postmultiplied級別。您可以在以下圖片中看到這一點:

輸入預乘的alpha
使用預乘的alpha,我們在存儲之前首先將紋理組件乘以alpha組件。我們還修改了混合函數,將SourceColor.a更改為One:
DestinationColor.rgb = (SourceColor.rgb * One) + (DestinationColor.rgb * (1 - SourceColor.a));
使用預乘的alpha,我們的原始紋理看起來像這樣:

此紋理的1x1 mipmap級別如下所示:

這是很多更合理。我們仍然丟失了一些信息(請注意,如果綠色組件足夠小,或者如果我們的精度太低,綠色將完全消失),但我們保留了更高分辨率的mipmap的意圖。為了比較,這里再次是圖像,增加了我們的預乘混合器:



從我們的后乘世界過渡
方便地,從后乘的α管道到利用預乘的α的管道的轉換是微不足道的。在紋理保存時間或資產烘焙時間,甚至加載時間,將每個非alpha通道乘以alpha。那是:
OutputTexture.rgb = InputTexture.rgb * InputTexture.a; OutputTexture.a = InputTexture.a;
並且不要忘記修改“alpha混合啟用”以使用One作為Source Alpha值。如果我們將預乘的alpha插入到原始混合方程中,很容易看到切換到預乘的alpha會給出完全相同的結果:
DestinationColor.rgb = ((SourceColor.rgb * SourceColor.a) * One) + (DestinationColor.rgb * (1 - SourceColor.a));
所以你可能會問:如果結果相同,為什么還要加倍預乘?原因是紋理過濾。從紋理中獲取樣本時,除非已禁用紋理過濾,否則硬件會將相鄰紋理像素混合在一起並返回加權平均值作為結果。使用傳統的后乘法alpha,此結果將不正確。
原文地址:https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre