(轉)NGUI sprite 變灰shader

感謝原作者的成果
本文轉自:http://blog.csdn.net/konglingbin66/article/details/51880153

1.初衷

最近做一個裝備的滾動條,需要將因為金錢不足不能購買的裝備置灰,原來置灰是使用texture+shader,現在是使用sprite+shader,但是NGUI原有的sprite不具備添加shader的能力。為什么要用sprite,這樣可以減少drawcall,提高一些效率。

2.置灰shader

shader就是在片段階段時通過float grey = dot(col.rgb, float3(0.299, 0.587, 0.114)); 這句語句來實現灰化的,就是將頂點的像素與一個值進行點乘,來影響每個頂點的像素來呈現出整體灰化的效果。下面是參考網上大神給出的灰化shader代碼:

Shader "Custom/MaskGray2" {  
    Properties  
    {  
        _MainTex ("Base (RGB), Alpha (A)", 2D) = "black" {}  
    }  
  
    SubShader  
    {  
        LOD 200  
  
        Tags  
        {  
            "Queue" = "Transparent"  
            "IgnoreProjector" = "True"  
            "RenderType" = "Transparent"  
        }  
  
        Pass  
        {  
            Cull Off  
            Lighting Off  
            ZWrite Off  
            Fog { Mode Off }  
            Offset -1, -1  
            Blend SrcAlpha OneMinusSrcAlpha  
  
            CGPROGRAM  
            #pragma vertex vert  
            #pragma fragment frag             
            #include "UnityCG.cginc"  
  
            sampler2D _MainTex;  
            float4 _MainTex_ST;  
  
            struct appdata_t  
            {  
                float4 vertex : POSITION;  
                float2 texcoord : TEXCOORD0;  
                fixed4 color : COLOR;  
            };  
  
            struct v2f  
            {  
                float4 vertex : SV_POSITION;  
                half2 texcoord : TEXCOORD0;  
                fixed4 color : COLOR;  
            };  
  
            v2f o;  
  
            v2f vert (appdata_t v)  
            {  
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);  
                o.texcoord = v.texcoord;  
                o.color = v.color;  
  
                return o;  
            }  
  
            fixed4 frag (v2f i) : COLOR  
            {  
                fixed4 col;     
                col = tex2D(_MainTex, i.texcoord);     
                col.rgb = dot(col.rgb, fixed3(.222,.707,.071));    
  
                return col;    
            }  
  
            ENDCG  
        }  
    }  
}  

這個shader里面核心代碼只有一句 col.rgb = dot(col.rgb, fixed3(.222,.707,.071));
3.給UISprite換材質

要給單獨的UISprite更換材質,才不會影響通圖集中的其他圖片。

using UnityEngine;  
using System.Collections;  
using System;  
  
  
public class UISprite_shader:UISprite  
{  
    protected UIPanel panelObj = null;  
    protected Material GrayMaterial;  
    /// <summary>  
    /// ngui對Sprite進行渲染時候調用  
    /// </summary>  
    /// <value>The material.</value>  
    public override Material material    
    {    
        get    
        {    
            Material mat = base.material;    
  
            if (mat == null)    
            {    
                mat = (atlas != null) ? atlas.spriteMaterial : null;    
            }    
  
            if (GrayMaterial !=null)    
            {    
                return GrayMaterial;    
            }    
            else    
            {    
                return mat;    
            }    
        }    
    }  
  
    /// <summary>  
    /// 調用此方法可將Sprite變灰  
    /// </summary>  
    /// <value>The material.</value>  
    public void SetGray()    
    {  
        Material mat = new Material(Shader.Find("Custom/MaskGray2"));  
        mat.mainTexture = material.mainTexture;  
        GrayMaterial = mat;  
  
        RefreshPanel(gameObject);   
    }  
  
    /// <summary>  
    /// 隱藏按鈕,setActive能不用盡量少用,效率問題。  
    /// </summary>  
    /// <value>The material.</value>  
    public void SetVisible(bool isVisible)  
    {  
        if (isVisible)  
        {  
            transform.localScale =  new Vector3(1,1,1);  
        }  
        else  
        {  
            transform.localScale = new Vector3(0,0,0);  
        }  
  
    }  
  
    /// <summary>  
    /// 將按鈕置為禁止點擊狀態,false為禁用狀態  
    /// </summary>  
    /// <value>The material.</value>  
    public  void SetEnabled(bool isEnabled)  
    {  
        if (isEnabled)  
        {  
            BoxCollider lisener = gameObject.GetComponent<BoxCollider> ();  
            if (lisener)  
            {  
                lisener.enabled = true;  
            }  
  
            SetNormal();  
        }  
        else  
        {  
            BoxCollider lisener = gameObject.GetComponent<BoxCollider> ();  
            if (lisener)  
            {  
  
                lisener.enabled = false;  
            }  
  
            SetGray();  
        }  
    }  
  
    /// <summary>  
    /// 將GrayMaterial置為null,此時會調用默認材質,刷新panel才會重繪Sprite  
    /// </summary>  
    /// <value>The material.</value>  
    public void SetNormal()  
    {  
        GrayMaterial = null;  
        RefreshPanel(gameObject);   
  
    }  
    ///刷新panel,重繪Sprite   
    void RefreshPanel(GameObject go)   
    {   
        if (panelObj == null)   
        {   
            panelObj = NGUITools.FindInParents<UIPanel>(go);   
        }  
  
        if (panelObj != null)    
        {    
            panelObj.enabled = false;    
            panelObj.enabled = true;    
        }    
    }  
      
}  

在SetGray()中,動態的創建了一個material并且賦值給Sprite,然后刷新panel時,在重繪這個Sprite時候,會調用material,這個時候,會返回我們創建好的GrayMaterial,在我們需要將Sprite恢復正常時候,僅需將我們的GrayMaterial置為null就行了。Shader "Custom/MaskGray2" 算是shader的目錄吧,我個人理解啊,當給材質指定shader的時候,就是按照這個菜單來的。
我們實現功能的時候使用UISprite_shader,而不是原來的UISprite,如下圖:


4.在ScrollView中添加clip shader
置灰之后的圖片可以看到當灰色裝備在ScrollView中,并且選中softClip選項時,灰色UISprite不會被剪裁,會超出邊界。這是因為剪切也是shader實現的,但是該shader并不知道如何剪裁置灰的圖片(我的個人理解啊)。NGUI的渲染都是通過UIDrawCall類進行的,通過斷點發現(其實是別人發現的),當ScrollView進行遮罩時會在UIDrawCall的CreateMaterial()函數內進行動態換Shader操作:

if (panel != null && panel.clipping == Clipping.TextureMask)  
        {  
            mTextureClip = true;  
            shader = Shader.Find("Hidden/" + shaderName + textureClip);  
        }  
        else if (mClipCount != 0)  
        {  
            shader = Shader.Find("Hidden/" + shaderName + " " + mClipCount);  
            if (shader == null) shader = Shader.Find(shaderName + " " + mClipCount);  
  
            // Legacy functionality  
            if (shader == null && mClipCount == 1)  
            {  
                mLegacyShader = true;  
                shader = Shader.Find(shaderName + soft);  
            }  
        }  
        else shader = Shader.Find(shaderName);  

通過上述代碼可知,當為SoftClip狀態下時,NGUI會自動給Sprite尋找名字為”Hidden/” + shaderName + ” ” + mClipCount的shader,顯然,在Normal狀態下,此時shader會變為NGUI自帶的”Hidden/Unlit/Transparent Colored 1”,進入該shader后,我們會發現在frag()函數內有這么句代碼col.a *= clamp( min(factor.x, factor.y), 0.0, 1.0);問題找到了,原來ScrollView是通過句代碼來實現遮罩的,那么當我們將shader換成我們自己的shader時,首先在SoftClip下找不到一個叫”Hidden/MaskGray2 1”的shader進行替換,這時NGUI會強行換成默認狀態的shader,因此,這就是導致我們上述問題的關鍵。
我的shader路徑名是Shader "Custom/MaskGray2 1",匹配UIDrawcall中的CreateMaterial中的語句:

if (shader == null) shader = Shader.Find(shaderName + " " + mClipCount);

也可以是“Hidden/Custom/MaskGray2 1”,匹配上語句:

shader = Shader.Find("Hidden/" + shaderName + " " + mClipCount);

Shader "Custom/MaskGray2 1"  
{  
    Properties  
    {  
        _MainTex ("Base (RGB), Alpha (A)", 2D) = "black" {}  
        _CutoffTex ("Cutoff (RGB), Alpha (A)", 2D) = "white" {}  
    }  
  
    SubShader  
    {  
        LOD 200  
  
        Tags  
        {  
            "Queue" = "Transparent"  
            "IgnoreProjector" = "True"  
            "RenderType" = "Transparent"  
        }  
          
        Pass  
        {  
            Cull Off  
            Lighting Off  
            ZWrite Off  
            Offset -1, -1  
            Fog { Mode Off }  
            ColorMask RGB  
            AlphaTest Greater .01  
            Blend SrcAlpha OneMinusSrcAlpha  
  
            CGPROGRAM  
            #pragma vertex vert  
            #pragma fragment frag  
  
            #include "UnityCG.cginc"  
  
            sampler2D _MainTex;  
            sampler2D _CutoffTex;  
            float4 _ClipRange0 = float4(0.0, 0.0, 1.0, 1.0);  
            float2 _ClipArgs0 = float2(1000.0, 1000.0);  
  
            struct appdata_t  
            {  
                float4 vertex : POSITION;  
                half4 color : COLOR;  
                float2 texcoord : TEXCOORD0;  
            };  
  
            struct v2f  
            {  
                float4 vertex : POSITION;  
                half4 color : COLOR;  
                float2 texcoord : TEXCOORD0;  
                float2 worldPos : TEXCOORD1;  
            };  
  
            v2f vert (appdata_t v)  
            {  
                v2f o;  
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);  
                o.color = v.color;  
                o.texcoord = v.texcoord;  
                o.worldPos = v.vertex.xy * _ClipRange0.zw + _ClipRange0.xy;  
                return o;  
            }  
  
            half4 frag (v2f IN) : COLOR  
            {  
                // Softness factor  
                float2 factor = (float2(1.0, 1.0) - abs(IN.worldPos)) * _ClipArgs0;  
              
                // Sample the texture  
                half4 col = tex2D(_MainTex, IN.texcoord) * IN.color;  
                half4 alpha = tex2D(_CutoffTex, IN.texcoord);  
                col = fixed4(col.rgb,alpha.a * col.a);  
                col.rgb = dot(col.rgb, fixed3(.222,.707,.071));  
                col.a *= clamp( min(factor.x, factor.y), 0.0, 1.0);  
                return col;  
            }  
            ENDCG  
        }  
    }  
      
    SubShader  
    {  
        LOD 100  
  
        Tags  
        {  
            "Queue" = "Transparent"  
            "IgnoreProjector" = "True"  
            "RenderType" = "Transparent"  
        }  
          
        Pass  
        {  
            Cull Off  
            Lighting Off  
            ZWrite Off  
            Fog { Mode Off }  
            ColorMask RGB  
            AlphaTest Greater .01  
            Blend SrcAlpha OneMinusSrcAlpha  
            ColorMaterial AmbientAndDiffuse  
              
            SetTexture [_MainTex]  
            {  
                Combine Texture * Primary  
            }  
        }  
    }  
}  

上面這個shader就是把Shader "HIDDEN/Unlit/Transparent Colored 1"拷貝過來,這個是scrollView選中softClip之后的默認shader,然后在這個shader的frag語句中發現一條col.a *= clamp( min(factor.x, factor.y), 0.0, 1.0);,然后我們添加一條置灰的語句col = fixed4(col.rgb,alpha.a * col.a);,即可實現置灰UISprite被剪切的效果。
最終效果如下圖:

參考:http://blog.csdn.NET/lixiang9166/article/details/46851887

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容