1. 程式人生 > >【翻譯】第六章節:透明度(關於混合)

【翻譯】第六章節:透明度(關於混合)

轉載地址:http://www.omuying.com/article/94.aspx

原文連結:http://en.wikibooks.org/wiki/Cg_Programming/Unity/Transparency

具體的說,本篇文章關於渲染透明物件,例如:透明的玻璃、塑料、織物等等(實際上是半透明的物件,他們不一定完全透明)。透過(半)透明的物件我們可以看到他們身後的顏色,其時是它們的顏色與它們身後的顏色進行了混合。

混合

在《Programmable Graphics Pipeline》章節中提到,片段著色器為每個片段(除非片段被擦除)計算 RGB 顏色值(在片段輸出引數使用語義詞 COLOR,包括紅、綠、藍、透明分量),片段的處理細節可以檢視《

Per-Fragment Operations》章節,其中一個操作是混合階段,主要用來合併片段的顏色(由片段輸出引數指定),這被稱為“source color”,與之相應的是已存在幀緩衝區的畫素顏色,這被成為“destination color”(因為幀緩衝區的顏色是混合結果)。

混合是一個固定階段,你可以通過混合公式對它進行配置但你無法對它程式設計,你可以通過公式像下面那樣來混合 RGBA 顏色值:

1 float4 result = SrcFactor * fragment_output + DstFactor * pixel_color;

其中 fragment_output 是通過片段著色器計算的 RGBA 顏色,pixel_color 是當前幀緩衝區的顏色,result 是混合結果(混合輸出階段),SrcFactor 和 DstFactor 是可配置的 RGBA 顏色(型別是 float4),並且片段顏色和幀顏色的各個分量分別相乘,SrcFactor 和 DstFactor 的值在 Unity ShaderLab 中可以用下面語法指定 :

1 Blend {code for SrcFactor} {code for DstFactor}
Code
Resulting Factor (SrcFactor or DstFactor)
One
float4(1.0, 1.0, 1.0, 1.0)
Zero
float4(0.0, 0.0, 0.0, 0.0)
SrcColor
fragment_output
SrcAlpha
fragment_output.aaaa
DstColor
pixel_color
DstAlpha
pixel_color.aaaa
OneMinusSrcColor
float4(1.0, 1.0, 1.0, 1.0) - fragment_output
OneMinusSrcAlpha
float4(1.0, 1.0, 1.0, 1.0) - fragment_output.aaaa
OneMinusDstColor
float4(1.0, 1.0, 1.0, 1.0) - pixel_color
OneMinusDstAlpha
float4(1.0, 1.0, 1.0, 1.0) - pixel_color.aaaa

由於 alpha 混合的流行,即使沒有采用 alpha 混合,顏色的 alpha 分量也通常被稱為不透明。此外,請注意計算機圖形學中透明度的常見計算公式為 1 - 不透明度。

預乘 alpha 混合

alpha 混合還有一個非常重要的公式,有時候片段輸出顏色已經預乘過顏色分量的 alpha 分量,在這種情況下,alpha 不應該被再次相乘,正確的混合是:

Blend One OneMinusSrcAlpha

這對應於:

1 float4 result = float4(1.0, 1.0, 1.0, 1.0) * fragment_output + (float4(1.0, 1.0, 1.0, 1.0) - fragment_output.aaaa) * pixel_color;

附加(Additive)混合

下面是另一種混合方式:

Blend One One

這對應於:

1 float4 result = float4(1.0, 1.0, 1.0, 1.0) * fragment_output + float4(1.0, 1.0, 1.0, 1.0) * pixel_color;

這只是給幀緩衝區的顏色新增片段輸出顏色,注意這兒 alpha 並沒有被使用,儘管如此,這個混合方式在處理一些透明效果時非常有用,比如,它經常被用在粒子系統中處理火或者透明物體發出的光。

Shader "Custom/Blending"
{
Properties
{
_Opacity("alpha opacity", Range(0.0,1.0)) = 0.3
}


SubShader //第一個 pass 使用前臉剔除來渲染背面(內部),第二個 pass 使用後臉剔除來渲染前面(外部)。
{//這個著色器適合凸起的網格(封閉網無凹痕,例如球體或者立方體)或者近似的網格。
Tags { "Queue" = "Transparent" }//在不透明物體已繪製之後繪製
Pass
{
Cull Front //第一個渲染通道僅背面
Zwrite off //不寫入深度緩衝區
Blend Zero SrcAlpha//乘法的混合,用於減少alpha值


CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float _Opacity;




struct vertexOutput
{
float4 pos : SV_POSITION;
float4 posInObjectCoords : TEXCOORD0;//測試使用,可以刪除
};

vertexOutput vert (float4 vertexPos:POSITION) 
{
vertexOutput output;
output.pos = mul(UNITY_MATRIX_MVP, vertexPos);
output.posInObjectCoords = vertexPos;
return output;
}

fixed4 frag (vertexOutput input) : COLOR
{
if (input.posInObjectCoords.y > 0.0)
{
discard;
}
return float4(1.0, 0.0, 0.0, _Opacity);
}
ENDCG
}


Pass
{
Cull Back //第一個渲染通道僅背面
Zwrite off
Blend Zero SrcAlpha 


CGPROGRAM
#pragma vertex vert
#pragma fragment frag


float _Opacity;


struct vertexOutput
{
float4 pos : SV_POSITION;
float4 posInObjectCoords : TEXCOORD0;
};




vertexOutput vert(float4 vertexPos:POSITION) 
{
vertexOutput output;
output.pos = mul(UNITY_MATRIX_MVP, vertexPos);
output.posInObjectCoords = vertexPos;
return output;
}


fixed4 frag(vertexOutput input) : COLOR
{
if (input.posInObjectCoords.y >0.0)
{
discard;
}
return float4(0.0, 1.0, 0.0, _Opacity);
}
ENDCG
}
}
}