Alpha預乘-混合與不混合[轉]


 

Alpha Blending幾乎是每個3D應用程序的一小部分,但卻很重要。從概念上講,alpha混合用於傳達表面的透明度。通常,消費者應用程序(游戲)傾向於使用RGB來傳達下層表面的顏色,依賴於alpha通道來指示該顏色的“不透明度”。更具體地說,當在管道中啟用alpha混合時,開發人員傾向於使用此表單進行混合:

DestinationColor.rgb = (SourceColor.rgb * SourceColor.a) + (DestinationColor.rgb * (1 - SourceColor.a));

在舊的,固定的功能中,這將被稱為“SourceAlpha,InvSourceAlpha”; 也被稱為“后倍增α”。然而,這種形式的alpha混合存在一個嚴重的缺陷:在許多情況下它會導致錯誤的顏色!最簡單的這些情況可以通過一個簡單的雙像素圖像來說明:

 

一個紅色像素,紅色= 1,alpha為1,綠色像素為綠色= 1,alpha為0.10

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

 

RGBA =(0.5,0.5,0,0.55)

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

 

 

 
規范圖像測試“mandrill”的三個版本。第一個,原始的mandrill。第二個包含與我們的2x1圖像混合時的mandrill,最后一個與2x1紋理的1x1 mipmap混合。

輸入預乘的alpha

使用預乘的alpha,我們在存儲之前首先將紋理組件乘以alpha組件。我們還修改了混合函數,將SourceColor.a更改為One:

DestinationColor.rgb = (SourceColor.rgb * One) + (DestinationColor.rgb * (1 - SourceColor.a));

使用預乘的alpha,我們的原始紋理看起來像這樣:

 

我們的2x1紋理,准備好預乘alpha。R =(1,0,0,1),G =(0,0.1,0,0.1)

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

 

我們預乘的alpha紋理的1x1 mipmap。RGBA =(0.5,0.05,0,0.55)

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

規范的山雀臉。 

 

 

 

   
所有版本的mandrill。從上到下的順序,原始的mandrill,原始的mandrill由我們的預乘α2x1覆蓋,后乘α2x1,預乘1x1,最后是后乘1x1。

從我們的后乘世界過渡

方便地,從后乘的α管道到利用預乘的α的管道的轉換是微不足道的。在紋理保存時間或資產烘焙時間,甚至加載時間,將每個非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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM