Two and a half years ago I made http://nickithansen.dk/masking-and-clipping-textures-using-shaders-in-ngui/ which in the mean time has broken in various ways. Ankh, in the comments, was kind enough to remind me to do something about that, so here is a new version that works in the newest versions of Unity3D and NGUI.
Shader "Custom/MaskClipShader 1" { Properties { _MainTex ("Base (RGB), Alpha (A)", 2D) = "white" {} _AlphaTex ("MaskTexture", 2D) = "white" {} } SubShader { Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } Pass { Cull Off Lighting Off ZWrite Off Offset -1, -1 Fog { Mode Off } ColorMask RGB Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST; sampler2D _AlphaTex; float4 _ClipRange0 = float4(0.0, 0.0, 1.0, 1.0); float2 _ClipArgs0 = float2(1000.0, 1000.0); struct appdata_t { float4 vertex : SV_POSITION; half4 color : COLOR; float2 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; half4 color : COLOR; float2 texcoord : TEXCOORD0; float2 worldPos : TEXCOORD1; }; v2f vert (appdata_t v) { v2f o = (v2f)0; 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) : SV_Target { float2 factor = (float2(1.0, 1.0) - abs(IN.worldPos)) * _ClipArgs0; half4 col = tex2D(_MainTex, IN.texcoord) * IN.color; half4 maskAlpha = tex2D(_AlphaTex, IN.texcoord); col.a *= clamp(min(factor.x, factor.y), 0.0, 1.0); col.a *= maskAlpha.a; return col; } ENDCG } } }
To use it, you create a custom material for your texture and assign it to a UITexture inside your clipping panel as you would a normal texture or sprite. Be sure to use the “Custom/MaskClipShader” shader for the material, and there you go. It accounts for soft clipped edges as well.
And here’s the unclipped version, which only masks a UITexture
Shader "Custom/MaskClipShader" { Properties { _MainTex ("Base (RGB), Alpha (A)", 2D) = "white" {} _AlphaTex ("MaskTexture", 2D) = "white" {} } 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 } SetTexture [_AlphaTex] { Combine previous, texture } } } }
Thank you very much Nicki.
If you have a syntax error line 21, pay attention to the minus sign “-“, I replaced it with the one on my keyboard and the unclipped version works fine.
ditto for unclipped version. With clipped version get this compile error
Failed to create DX11 vertex declaration; something wrong with vertex shader input data? (hr=80070057)
Hmm, it’s been a while since I made this. I’ll take a look. 🙂
Ok so it seems when you copy/paste the code, it inserts a space between the ‘-‘ and the 1. That’s all that happens. Otherwise, it still works in Unity 5.5.1 and NGUI 3.11.
Is it possible to invert masking? I’m using Alpha 8 textures, so wrong areas masked.
Easiest thing is the invert the mask directly in the picture. 🙂
Yes, it is. But not an option. I have 4k pics, and they must remain this way. Doubling it to 8k in app is crazy:)
I have made a trick though, changed:
Blend SrcAlpha OneMinusSrcAlpha
to
Blend OneMinusSrcAlpha SrcAlpha
It kinda work. But it’s messing with my shadow on another image. Removing it and placing hard black border:)
Change the line
col.a *= maskAlpha.a;
to
col.a *= (1-maskAlpha.a);
Thanks a lot! That was easier than expected:)