(转)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;  
    ///   
    /// ngui对Sprite进行渲染时候调用  
    ///   
    /// The material.  
    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;    
            }    
        }    
    }  
  
    ///   
    /// 调用此方法可将Sprite变灰  
    ///   
    /// The material.  
    public void SetGray()    
    {  
        Material mat = new Material(Shader.Find("Custom/MaskGray2"));  
        mat.mainTexture = material.mainTexture;  
        GrayMaterial = mat;  
  
        RefreshPanel(gameObject);   
    }  
  
    ///   
    /// 隐藏按钮,setActive能不用尽量少用,效率问题。  
    ///   
    /// The material.  
    public void SetVisible(bool isVisible)  
    {  
        if (isVisible)  
        {  
            transform.localScale =  new Vector3(1,1,1);  
        }  
        else  
        {  
            transform.localScale = new Vector3(0,0,0);  
        }  
  
    }  
  
    ///   
    /// 将按钮置为禁止点击状态,false为禁用状态  
    ///   
    /// The material.  
    public  void SetEnabled(bool isEnabled)  
    {  
        if (isEnabled)  
        {  
            BoxCollider lisener = gameObject.GetComponent ();  
            if (lisener)  
            {  
                lisener.enabled = true;  
            }  
  
            SetNormal();  
        }  
        else  
        {  
            BoxCollider lisener = gameObject.GetComponent ();  
            if (lisener)  
            {  
  
                lisener.enabled = false;  
            }  
  
            SetGray();  
        }  
    }  
  
    ///   
    /// 将GrayMaterial置为null,此时会调用默认材质,刷新panel才会重绘Sprite  
    ///   
    /// The material.  
    public void SetNormal()  
    {  
        GrayMaterial = null;  
        RefreshPanel(gameObject);   
  
    }  
    ///刷新panel,重绘Sprite   
    void RefreshPanel(GameObject go)   
    {   
        if (panelObj == null)   
        {   
            panelObj = NGUITools.FindInParents(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,如下图:


(转)NGUI sprite 变灰shader_第1张图片

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被剪切的效果。
最终效果如下图:

(转)NGUI sprite 变灰shader_第2张图片

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

你可能感兴趣的:((转)NGUI sprite 变灰shader)