[Shader] cropping NGUI UISprite and UITexture, nguiuisprite
Due to the recent busy schedule, many blog posts I posted elsewhere have not been synchronized here. I will try again later. Sorry for the readers who followed my blog!
All rights reserved. The source must be indicated for reprinting!
Those who like Firefox, Java, unity3D, and game development can join the Q group in muye village:
379076227
0. You can chat about Shader for two days at home during the Spring Festival this year. But he has a deep liking for Shader. Attracted by its charm.
But what we usually do is the development of the server and client, which is logically oriented. So we haven't touched Shader for a long time.
However, someone discussed in A group yesterday that NGUI cannot crop Sprite. For example, a square is displayed as a circle. For example:
This should be quite common. Maybe you will say that art can help you cut the circle directly. Sometimes, sometimes. When will it not work? When you use square shape in some parts of the game, and round shape in some parts. At this time, no art can help you cut. Otherwise, there will be no more than two resources.
It is recommended that you already know how to use NGUI to create an atlas and use its UISprite and UITexture.
The testing environment is as follows:
System: Win7 X64 engine: Unity3D V4.3.3
Plug-in: NGUI 3.5.7
1. Start
As a person who has studied Shader for two days, I think it should be hard for me. As a result, I immediately joined the U3D Project panel. Create a Shader.
2. Write the first version of Shader. Double-click the Shader we created above. This is for NGUI. Then I named our Shader unwritable/Transparent Colored Mask according to NGUI's Shader.
The Shader code is as follows:
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 } } }}
The main code for cropping is:
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;}
I believe it is easy for everyone to understand. Here we multiply the Alpha channel value of the Mask texture with that of the original image.
How to use it.
Create a UItexture.
Select a material. Use the Shader above. Set a Mask.
The Mask image is
We can see that the Alpha channel contains a white circle.
Remember to set the import settings for this Mask image as follows:
You can see the running effect:
3. Cheers and celebrate? Everything looks quite smooth. But can this Shader work on UISprite?
Let's try it.
Create a gallery at will. Then add a UISprite,
Then modify the material of this gallery and use our Shader.
Amount... The effect is as follows... Not right
4. Stop and think about it. Is this NGUI bug... Ah !!! Ah !!!!!
No, I have to think about it.
.........
1 minute has passed.
Why is the formula col. a = col. a * tex2D (_ Mask, I. texcoord). a incorrect effect on Sprite.
Is the range of I. texcoord not 0 ~ 1.
In this case, it seems a bit reasonable. Because NGUI makes the image to be used into an image gallery. Therefore, only a small area in the gallery is displayed on the Mesh of the UI each time.
So, I only need to remap the range of I. texcoord to 0 ~ 1. Then it is used to take the color above the Mask. Isn't it OK?
I immediately started to be witty.
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 } } }}
Okay. Then how to use this Shader. We need another script to set the shader parameter.
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); }}
You only need to attach this script to UISprite.
It can be found that it is normal now. NGUI gallery material becomes
Okay. We can really celebrate this time ~~
The whole effect is actually only the Shader and ScaleTexcoord. cs above.
Download the test project: