[Shader]對NGUI的UISprite和UITexture進行裁剪,nguiuisprite
由於最近比較忙,所以很多我在其它地方發布的博文都沒有同步到這裡。我會在後面慢慢重新補回來。對各位關注我部落格的讀者也表示抱歉!
著作權,轉載須註明出處!
喜歡火影、喜歡Java、喜歡unity3D、喜歡遊戲開發的都可以加入木葉村Q群:
379076227
0、隨便聊本人真正學習Shader的時間莫過於今年春節在家的兩天時間,雖然短短兩天。但是已經深深喜歡上Shader。深受其魅力吸引。
但是平常主要做的還是服務端和用戶端的開發,偏邏輯向。所以好久也沒碰Shader了。
但是昨天在一個群裡有人討論NGUI不能對Sprite進行裁剪。比如把一個方形的,顯示成一個圓形的。如:
這個應該是挺常見的,或許你會說,美術直接幫你裁成圓的不就可以嗎。有時候可以,有時候不行。什麼時候不行呢?當你在遊戲中有些地方使用方形的,有些地方使用圓形的。這時候就不能讓美術幫你裁了。不然不就有兩份資源了。
本文讀者最好已經知道怎麼使用NGUI建立圖集,使用它的UISprite和UITexture。
本文編寫測試環境為:
系統:Win7 X64引擎:Unity3D V4.3.3
外掛程式:NGUI 3.5.7
1、開始動手
作為一個學習過兩天Shader的人,我覺得,這應該難不倒我。因此,我立馬在U3D的Project面板中劈裡啪啦一陣狂搞。建立一個Shader。
2、編寫第一版Shader。雙擊我們上面建立的Shader。因為這個是給NGUI用的。然後我就依照NGUI的Shader命名,給我們的Shader命名為:Unlit/Transparent Colored Mask
Shader代碼如下:
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)); return o; } fixed4 frag (v2f i) : COLOR { fixed4 col; col = tex2D(_MainTex, i.texcoord) * i.color; col.a = col.a * tex2D(_Mask, i.texcoord).a; return col; } 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 } } }}主要實現裁剪的代碼為:
fixed4 frag (v2f i) : COLOR{ fixed4 col; col = tex2D(_MainTex, i.texcoord) * i.color; col.a = col.a * tex2D(_Mask, i.texcoord).a; return col;}相信大家很容易就看懂了,這裡是把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了嗎?
機智的我立馬動起手來。
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 { 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; 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)); return o; } fixed4 frag (v2f i) : COLOR { fixed4 col; 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; return col; } 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 } } }}
好了。那麼怎麼使用這個Shader。我們需要多一個指令碼來設定這個shader的參數。
using UnityEngine;using System.Collections;[ExecuteInEditMode]public class ScaleTexcoord : 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即可。
下載測試工程: