【翻譯】第六章節:透明度(關於混合)
轉載地址:http://www.omuying.com/article/94.aspx
原文連結:http://en.wikibooks.org/wiki/Cg_Programming/Unity/Transparency
具體的說,本篇文章關於渲染透明物件,例如:透明的玻璃、塑料、織物等等(實際上是半透明的物件,他們不一定完全透明)。透過(半)透明的物件我們可以看到他們身後的顏色,其時是它們的顏色與它們身後的顏色進行了混合。
混合
在《Programmable Graphics Pipeline》章節中提到,片段著色器為每個片段(除非片段被擦除)計算
RGB 顏色值(在片段輸出引數使用語義詞 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
}
}
}