由于最近比较忙,所以很多我在其它地方发布的博文都没有同步到这里。我会在后面慢慢重新补回来。对各位关注我博客的读者也表示抱歉!
版权所有,转载须注明出处!
喜欢火影、喜欢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即可。
下载测试工程:
版权声明:本文为博主原创文章,未经博主允许不得转载。