[Shader]对NGUI的UISprite和UITexture进行裁剪

来源:互联网 发布:java获取时间毫秒数 编辑:程序博客网 时间:2024/05/15 23:43
0、随便聊
本人真正学习Shader的时间莫过于今年春节在家的两天时间,虽然短短两天。但是已经深深喜欢上Shader。深受其魅力吸引。

但是平常主要做的还是服务端和客户端的开发,偏逻辑向。所以好久也没碰Shader了。
但是昨天在一个群里有人讨论NGUI不能对Sprite进行裁剪。比如把一个方形的,显示成一个圆形的。如下图:
 

这个应该是挺常见的,或许你会说,美术直接帮你裁成圆的不就可以吗。有时候可以,有时候不行。什么时候不行呢?当你在游戏中有些地方使用方形的,有些地方使用圆形的。这时候就不能让美术帮你裁了。不然不就有两份资源了。
最终效果图
 

1、开始动手
本文编写测试环境为:
系统:Win7 X64引擎:unity3D V4.3.3
插件:NGUI 3.5.7
作为一个学习过两天Shader的人,我觉得,这应该难不倒我。因此,我立马在U3D的Project面板中噼里啪啦一阵狂搞。创建一个Shader。
 


2、编写第一版Shader。
双击我们上面创建的Shader。因为这个是给NGUI用的。然后我就依照NGUI的Shader命名,给我们的Shader命名为:Unlit/Transparent Colored Mask
Shader代码如下:
[Bash shell] 纯文本查看 复制代码
?
 
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
Shader"Unlit/Transparent Colored Mask"
{
        Properties
        {
                _MainTex ("Base (RGB), Alpha (A)", 2D) = "black"{}
                _Mask ("Mask Alpha (A)", 2D) = "white"{}
        }
         
        SubShader
        {
                LOD 100
 
                Tags
                {
                        "Queue"= "Transparent"
                        "IgnoreProjector"= "True"
                        "RenderType"= "Transparent"
                }
                 
                Cull Off
                Lighting Off
                ZWrite Off
                Fog { Mode Off }
                Offset -1, -1
                Blend SrcAlpha OneMinusSrcAlpha
 
                Pass
                {
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                                 
                        #include "UnityCG.cginc"
         
                        struct appdata_t
                        {
                                float4 vertex : POSITION;
                                float2 texcoord : TEXCOORD0;
                                fixed4 color : COLOR;
                        };
         
                        struct v2f
                        {
                                float4 vertex : SV_POSITION;
                                half2 texcoord : TEXCOORD0;
                                fixed4 color : COLOR;
                                fixed gray : TEXCOORD1;
                        };
         
                        sampler2D _MainTex;
                        sampler2D _Mask;
                        float4 _MainTex_ST;
                        float4 _Mask_ST;
                                 
                        v2f vert (appdata_t v)
                        {
                                v2f o;
                                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                                o.texcoord = v.texcoord;
                                o.color = v.color;
                                o.gray = dot(v.color, fixed4(1,1,1,0));
                                returno;
                        }
                                 
                        fixed4 frag (v2f i) : COLOR
                        {
                            fixed4 col;
                                 
                                col = tex2D(_MainTex, i.texcoord) * i.color;
                                col.a = col.a * tex2D(_Mask, i.texcoord).a;
                                returncol;
                        }
                        ENDCG
                }
        }
 
        SubShader
        {
                LOD 100
 
                Tags
                {
                        "Queue"= "Transparent"
                        "IgnoreProjector"= "True"
                        "RenderType"= "Transparent"
                }
                 
                Pass
                {
                        Cull Off
                        Lighting Off
                        ZWrite Off
                        Fog { Mode Off }
                        Offset -1, -1
                        ColorMask RGB
                        AlphaTest Greater .01
                        Blend SrcAlpha OneMinusSrcAlpha
                        ColorMaterial AmbientAndDiffuse
                         
                        SetTexture [_MainTex]
                        {
                                Combine Texture * Primary
                        }
                }
        }
}


主要实现裁剪的代码为:
[AppleScript] 纯文本查看 复制代码
?
 
1
2
3
4
5
6
7
fixed4frag (v2f i): COLOR
{
    fixed4col;
         
        col=tex2D(_MainTex,i.texcoord)* i.color;
        col.a=col.a *tex2D(_Mask,i.texcoord).a;
        returncol;
}


相信大家很容易就看懂了,这里是把Mask贴图的Alpha通道的值和原图片的进行相乘。
怎么用呢。
新建一个UItexture。
 
然后选择一个材质。用上我们上面的Shader。然后设置一个Mask。
 

这个Mask图片为
 

可以看到Alpha通道里面是一个白色的圆圈。
记得这个Mask图片的导入设置如下:
 



那么可以看看运行效果:
 



3、欢呼,庆祝?
貌似一切都挺顺利的。但是这个Shader能否对UISprite起效果呢?
我们来试试。
随便搞个图集。
 

然后加个UISprite,


然后修改这个图集的材质使用我们的Shader。
 

额。。。效果不太对。。。

4、停一停想一想
难道这是NGUI的bug。。。啊!!!啊!!!!!
不行,我要想想看
。。。。。。。。。
1分钟过去了。
为什么col.a = col.a * tex2D(_Mask, i.texcoord).a这个公式对Sprite的效果是错误的呢。
难道i.texcoord的范围不是0~1.
这么一想,倒好像也有点道理。因为NGUI把要用到的图片做成了图集。因此,每次只是取图集中的一小个区域显示到UI的Mesh上。
那么,我只要把i.texcoord的范围重新映射到0~1。然后用于取Mask上面的颜色,不就OK了吗?
机智的我立马动起手来。
[AppleScript] 纯文本查看 复制代码
?
 
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
Shader"Unlit/Transparent Colored Mask"
{
        Properties
        {
                _MainTex("Base (RGB), Alpha (A)",2D)= "black" {}
                _Mask("Mask Alpha (A)",2D)= "white" {}
                _WidthRate("Sprite.width/Atlas.width",float)= 1
                _HeightRate("Sprite.height/Atlas.height",float)= 1
                _XOffset("offsetX",float)= 0
                _XOffset("offsetY",float)= 0
        }
         
        SubShader
        {
                LOD100
 
                Tags
                {
                        "Queue"= "Transparent"
                        "IgnoreProjector"= "True"
                        "RenderType"= "Transparent"
                }
                 
                Cull Off
                Lighting Off
                ZWrite Off
                Fog{Mode Off }
                Offset-1,-1
                Blend SrcAlpha OneMinusSrcAlpha
 
                Pass
                {
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                                 
                        #include "UnityCG.cginc"
         
                        struct appdata_t
                        {
                                float4vertex :POSITION;
                                float2texcoord :TEXCOORD0;
                                fixed4color :COLOR;
                        };
         
                        struct v2f
                        {
                                float4vertex :SV_POSITION;
                                half2texcoord :TEXCOORD0;
                                fixed4color :COLOR;
                                fixed gray :TEXCOORD1;
                        };
         
                        sampler2D _MainTex;
                        sampler2D _Mask;
                        float4_MainTex_ST;
                        float4_Mask_ST;
                        float _WidthRate;
                        float _HeightRate;
                        float _XOffset;
                        float _YOffset;
                                 
                        v2f vert (appdata_t v)
                        {
                                v2f o;
                                o.vertex=mul(UNITY_MATRIX_MVP,v.vertex);
                                o.texcoord=v.texcoord;
                                o.color=v.color;
                                o.gray=dot(v.color,fixed4(1,1,1,0));
                                returno;
                        }
                                 
                        fixed4frag (v2f i): COLOR
                        {
                            fixed4col;
                                 
                                col=tex2D(_MainTex,i.texcoord)* i.color;
                                col.a=col.a *tex2D(_Mask,float2((i.texcoord.x-_XOffset)/_WidthRate,(i.texcoord.y-(1-_YOffset))/_HeightRate)).a;
                                returncol;
                        }
                        ENDCG
                }
        }
 
        SubShader
        {
                LOD100
 
                Tags
                {
                        "Queue"= "Transparent"
                        "IgnoreProjector"= "True"
                        "RenderType"= "Transparent"
                }
                 
                Pass
                {
                        Cull Off
                        Lighting Off
                        ZWrite Off
                        Fog{Mode Off }
                        Offset-1,-1
                        ColorMask RGB
                        AlphaTest Greater .01
                        Blend SrcAlpha OneMinusSrcAlpha
                        ColorMaterial AmbientAndDiffuse
                         
                        SetTexture [_MainTex]
                        {
                                Combine Texture *Primary
                        }
                }
        }
}


好了。那么怎么使用这个Shader。我们需要多一个脚本来设置这个shader的参数。
[AppleScript] 纯文本查看 复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
usingUnityEngine;
usingSystem.Collections;
 
[ExecuteInEditMode]
publicclassScaleTexcoord :MonoBehaviour
{
    private float wr;
    private float hr;
    private float offX;
    private float offY;
    private UISprite s;
    void Awake()
    {
        s=GetComponent<UISprite>();
 
        wr=s.GetAtlasSprite().width*1.0f/s.atlas.spriteMaterial.mainTexture.width;
        offX=s.GetAtlasSprite().x*1.0f/s.atlas.spriteMaterial.mainTexture.width;
 
        hr=s.GetAtlasSprite().height*1.0f/s.atlas.spriteMaterial.mainTexture.height;
        offY=(s.GetAtlasSprite().y+s.GetAtlasSprite().height)* 1.0f/s.atlas.spriteMaterial.mainTexture.height;
    }
 
    public void Update()
    {
        s.atlas.spriteMaterial.SetFloat("_WidthRate",wr);
        s.atlas.spriteMaterial.SetFloat("_HeightRate",hr);
        s.atlas.spriteMaterial.SetFloat("_XOffset",offX);
        s.atlas.spriteMaterial.SetFloat("_YOffset",offY);
    }
}

只要把这个脚本附在UISprite上即可。
 
可以发现现在正常了。NGUI图集的材质变成了
 
好了。这次真的可以好好庆祝下啦~~



整个效果其实只用上面的Shader和那个ScaleTexcoord.cs即可。
0 0