Masking and clipping textures in Unity 5.4, NGUI 3.9.8

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.

uitexture custommaterial

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
      }
    }
  }
}

11 thoughts on “Masking and clipping textures in Unity 5.4, NGUI 3.9.8

  1. 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.

  2. 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)

    1. 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.

      1. 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:)

Leave a Reply

Your email address will not be published. Required fields are marked *