轉載位址: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 顔色值:
| |
其中 fragment_output 是通過片段着色器計算的 RGBA 顔色,pixel_color 是目前幀緩沖區的顔色,result 是混合結果(混合輸出階段),SrcFactor 和 DstFactor 是可配置的 RGBA 顔色(類型是 float4),并且片段顔色和幀顔色的各個分量分别相乘,SrcFactor 和 DstFactor 的值在 Unity ShaderLab 中可以用下面文法指定 :
| |
比較常用的混合因子(factor)可以檢視下表,更詳細的混合因子(factor)可以檢視《Unity's ShaderLab reference about blending》:
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
這對應于:
| |
附加(Additive)混合
下面是另一種混合方式:
Blend One One
這對應于:
| |
這隻是給幀緩沖區的顔色添加片段輸出顔色,注意這兒 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
}
}
}