Custom shader with clipping in NGUI

經常寫 2D Shader 的開發者可能都會遇到 NGUI clipping 問題: 自己寫的 shader 為什麼只要掛在一個 UIPanel 下(clipping 不是 none)就會失效?

簡單實驗一下 … 以 skew shader 為例, 新增一個 UIPanel, 再新增一個子物件 UITexture 並掛上 skew shader, 如下圖, 看起來 shader 是有效的
no clipping no clipping panel
現在把 UIPanel Clipping 設為 “Soft Clip", skew shader 與 soft clip 都失效了 …
clipping clipping panel

再嘗試看看 NGUI 內提供的 shader(在資料夾 NGUI/Resource/Shaders 下) 卻是成功運作的 ? 這篇文章提供了解答, NGUI 3.x 版本後為了結合 Clipping 使用, 每個 shader 都需要提供 clipping 化的 shader 腳本, 並以 1/2/3 … 名稱區隔, 代表使用到幾層 clipping, 仔細看 NGUI 內部的 shader 也是這麼做的 !
clipping shader name
目前 NGUI 內不只提供到 3 層 clipping 當然要加到 4/5/6 也是可行的 …

每一層 clipping 的 shader 腳本有些不同 (可參考 NGUI 提供的 shader), 但 shader 的主體內容還是不變的, 互相比對需要增加的內容到自己的 shader 並重新命名, 就能讓 shader 有效在 clipping 環境下運作囉 ! 以下是經過 1 層 clipping 修改後的效果 (先歪斜後 clipping)
skew with clipping

skew 程式碼參考 2D UI sprite shearing shader:

Shader "Unit/SpriteSkewShader"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0

        _HorizontalSkew ("Horizontal Skew", Float) = 0
        _VerticalSkew ("Vertical Skew", Float) = 0
    }
    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }
        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Blend One OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile DUMMY PIXELSNAP_ON
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
            };
            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                half2 texcoord  : TEXCOORD0;
            };

            sampler2D _MainTex;
            fixed4 _Color;
            float _HorizontalSkew;
            float _VerticalSkew;
            v2f vert(appdata_t IN)
            {
                v2f OUT;
                OUT.texcoord = IN.texcoord;
                OUT.color = IN.color * _Color;

                // Create a skew transformation matrix
                float h = _HorizontalSkew;
                float v = _VerticalSkew;
                float4x4 transformMatrix = float4x4(
                    1,h,0,0,
                    v,1,0,0,
                    0,0,1,0,
                    0,0,0,1);

                float4 skewedVertex = mul(transformMatrix, IN.vertex);
                OUT.vertex = mul(UNITY_MATRIX_MVP, skewedVertex);

                #ifdef PIXELSNAP_ON
                OUT.vertex = UnityPixelSnap (OUT.vertex);
                #endif
                return OUT;
            }
            fixed4 frag(v2f IN) : SV_Target
            {
                fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
                c.rgb *= c.a;
                return c;
            }
        ENDCG
        }
    }
}

經過小妹 1 層 clipping 修改後變成:

Shader "Hidden/Unit/SpriteSkewShader 1"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0

        _HorizontalSkew ("Horizontal Skew", Float) = 0
        _VerticalSkew ("Vertical Skew", Float) = 0
    }
    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }
        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Blend One OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile DUMMY PIXELSNAP_ON
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
            };
            struct v2f
            {
                float4 vertex   : POSITION;
                fixed4 color    : COLOR;
                half2 texcoord  : TEXCOORD0;
                float2 worldPos : TEXCOORD1;
            };

            sampler2D _MainTex;
            fixed4 _Color;
            float _HorizontalSkew;
            float _VerticalSkew;

            float4 _ClipRange0 = float4(0.0, 0.0, 1.0, 1.0);
            float2 _ClipArgs0 = float2(1000.0, 1000.0);

            v2f vert(appdata_t IN)
            {
                v2f OUT;
                OUT.texcoord = IN.texcoord;
                OUT.color = IN.color * _Color;
                // Create a skew transformation matrix
                float h = _HorizontalSkew;
                float v = _VerticalSkew;
                float4x4 transformMatrix = float4x4(
                    1,h,0,0,
                    v,1,0,0,
                    0,0,1,0,
                    0,0,0,1);

                float4 skewedVertex = mul(transformMatrix, IN.vertex);
                OUT.vertex = mul(UNITY_MATRIX_MVP, skewedVertex);

                // calculate new clipping range
                OUT.worldPos = skewedVertex.xy * _ClipRange0.zw + _ClipRange0.xy;

                #ifdef PIXELSNAP_ON
                OUT.vertex = UnityPixelSnap (OUT.vertex);
                #endif
                return OUT;
            }
            fixed4 frag(v2f IN) : COLOR
            {
            	// Softness factor
                float2 factor = (float2(1.0, 1.0) - abs(IN.worldPos)) * _ClipArgs0;

                fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
                c.a *= clamp( min(factor.x, factor.y), 0.0, 1.0);
                c.rgb *= c.a;
                return c;
            }
        ENDCG
        }
    }
}

給大家參考看看囉~ 😀

發表留言