1. 程式人生 > >【ShaderLab學習】AlphaTest & AlphaBlend理解[1]

【ShaderLab學習】AlphaTest & AlphaBlend理解[1]

AlphaTest & AlphaBlend

前言

  • 透明度測試:它採用一種“霸道極端”的機制,只要一個片元的透明度不滿足條件(通常是小於某個閾值),那麼它對應的片元就會被捨棄。被捨棄的片元將不會再進行任何處理,也不會對顏色緩衝產生任何影響;否則,就會按照普通的不透明物體的處理方式來處理它,即進行深度測試深度寫入。也就是說,透明度測試是不需要關閉深度寫入的,它和其他不透明物體最大的不同就是它會根據透明度來捨棄一些片元。雖然簡單,但是它產生的效果也很極端,要麼完全透明,即看不到,要麼完全不透明。

  • 透明度混合:這種方法可以得到真正的半透明效果。它會使用當前片元的透明度作為混合因子,與已經儲存在顏色緩衝中的顏色值進行混合,得到新的顏色。但是,透明度混合需要關閉深度寫入,這使得我們要非常小心物體的渲染順序。需要注意的是,透明度混合只關閉了深度寫入,但沒有關閉深度測試。這意味著,當使用透明度混合渲染一個片元時,還是會比較它的深度值與當前深度緩衝中的深度值,如果它的深度值距離攝像機更遠,那麼就不會再進行混合操作了。這一點決定了,當一個不透明物體出現在一個透明物體的前面,而我們先渲染了不透明物體,它仍然可以正常地遮擋住透明物體。也就是說,對於透明度混合來說,深度緩衝是隻讀的。

Alpha Test

官方文件

採用一種比較極端的機制,只要一個片元的透明度不滿足某個條件(通常是小於某閾值),就直接捨棄該片元。否則就會按照普通的不透明物體來處理,進行深度測試深度寫入

語義:

  • AlphaTest Off 不測試,全渲染

  • AlphaTest Comparison AlphaValue[0-1] 通過比較運算子得出是否渲染

Comparison Desc
Greater Only render pixels whose alpha is greater than AlphaValue.
GEqual Only render pixels whose alpha is greater than or equal to AlphaValue.
Less Only render pixels whose alpha value is less than AlphaValue.
LEqual Only render pixels whose alpha value is less than or equal to from AlphaValue.
Equal Only render pixels whose alpha value equals AlphaValue.
NotEqual Only render pixels whose alpha value differs from AlphaValue.
Always Render all pixels. This is functionally equivalent to AlphaTest Off.
Never Don’t render any pixels.

Surface Shader 示例:

Shader "Simple Alpha Test" {
    Properties {···}
    SubShader {
        Pass {
            AlphaTest Greater 0.5
            ···
        }
    }
}
Shader "Cutoff Alpha" {
    Properties {
        _Cutoff ("Alpha cutoff", Range (0,1)) = 0.5
    }
    SubShader {
        Pass {
            AlphaTest Greater [_Cutoff]
           ···
        }
    }
}

Vextex & Fragment Shader 示例:

第一種

和Surface Shader中一樣的語義,作用也相同。

第二種

在片元著色器中使用clip函式,clip函式是CG中的一個函式,定義如下:

函式: void clip(float4 x);void clip(float3 x);void clip(float2 x);void clip(float1 x);void clip(float x); **引數:**裁剪時使用的標量或者向量條件。 **描述:**如果給定引數的任何一個分量是負數,就會捨棄當前畫素的輸出顏色。等同於以下的程式碼:

void clip(float4 x)
{
    if(any(x < 0))
    {
        discard;
    }
}
Shader "Custom/l2xin/T_AlphaTest"
{
    Properties 
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Cutoff("Alhpa Cutoff", Range(0,1)) = 0.5
    }
    
    SubShader
    {
        Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
        
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            
            CGPROGRAM

            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "Lighting.cginc"
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _Cutoff;            
            
            struct a2v{
                float4 vertex : POSITION;
                float4 texcoord: TEXCOORD0;
            };
            
            struct v2f{
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
            
            v2f vert(a2v v){
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }
            
            fixed4 frag(v2f i) :SV_Target{
                fixed4 texColor = tex2D(_MainTex, i.uv);
                //AlphaTest通過判斷clip函式的引數,如果小於0本次fragment discard.
                clip(texColor.a - _Cutoff);
                return texColor;
            }
        
            ENDCG
        }
    }
    FallBack "Diffuse"
}

驗證結果

原始圖片:

取自馮樂樂女神的書

_Cutoff設定為0.65:

_Cutoff=0.65

問題

AlphaTest得到的透明效果很極端,要麼完全透明,要麼完全不透明,就像在不透明的物體上挖了洞。而且,在邊緣處效果參差不齊,因為邊界處紋理的透明度變化的精度問題導致有鋸齒,為了得到更加平滑的透明效果,考慮使用透明度混合AlphaBlend.

參考