A question that showed up on Tasharen’s forum, where I happen to be a moderator, was this one:
(..) I have a panel that’s draggable and clipped, which displays a list of GameObjects, each one composed of usernames, avatars, and some other text.
The avatars are not square, they have an hexagonal mask. To achieve this, they are Texture widgets with a special shader I found here. (..) when they get clipped by the panel, they keep showing even outside the boundaries. Only when completely out of sight, they get hidden(..).
Source: http://www.tasharen.com/forum/index.php?topic=5621
First: the reason it gets disabled when its entirely outside the clip area is the way NGUI culls widgets by simply not drawing them. It’s not that the gameObject is disabled, but the UIPanel does not feed this widget into the UIDrawCall’s geometry which is the thing that gets drawn on screen.
The shader he used for the masking was obtained at http://www.zedia.net/2013/masking-textures-using-shaders-ngui/ who based the shader on the old non-clipping version of NGUIs builtin Transparent Alpha shader (it has since changed to not use the combine keyword).
This doesn’t work with the different clipping options that NGUI uses (Alpha Clipping, Soft Clipping) since the UIPanels change the shader used and also feed in the coordinates where it needs to be clipped. It’s very worth noting that the way the UIPanel chooses shaders is entirely based on the name of the shader. This means that when you make a new shader, you should make a similar named shader but with ” (AlphaClip)” added to it, so it’s used when alpha cliping is enabled.
// If clipping should be used, we need to find a replacement shader if (useClipping && mClipping != Clipping.None) { Shader shader = null; const string alpha = " (AlphaClip)"; const string soft = " (SoftClip)"; // Figure out the normal shader's name string shaderName = mSharedMat.shader.name; shaderName = shaderName.Replace(alpha, ""); shaderName = shaderName.Replace(soft, ""); // Try to find the new shader if (mClipping == Clipping.HardClip || mClipping == Clipping.AlphaClip) shader = Shader.Find(shaderName + alpha); else if (mClipping == Clipping.SoftClip) shader = Shader.Find(shaderName + soft);
Source: UIDrawCall.cs in NGUI.
Note also that the former HardClipping is entirely deprecated and just changes to be AlphaClip under the surface.
Here’s a shader that works with Alpha Clipping based on the Transparent Colored (AlphaClip) builtin shader in NGUI:
Shader "Custom/MaskClipShader (AlphaClip)" { 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 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; struct appdata_t { float4 vertex : POSITION; half4 color : COLOR; float2 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : POSITION; half4 color : COLOR; float2 texcoord : TEXCOORD0; float2 worldPos : TEXCOORD1; }; v2f vert (appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.color = v.color; o.texcoord = v.texcoord; o.worldPos = TRANSFORM_TEX(v.vertex.xy, _MainTex); return o; } half4 frag (v2f IN) : COLOR { // Sample the texture half4 col = tex2D(_MainTex, IN.texcoord) * IN.color; half4 a2 = tex2D(_AlphaTex, IN.texcoord); float2 factor = abs(IN.worldPos); float val = 1.0 - max(factor.x, factor.y); // Option 1: 'if' statement if (val < 0.0) col.a = 0.0; if (a2.a < col.a) col.a = a2.a; // Option 2: no 'if' statement -- may be faster on some devices //col.a *= ceil(clamp(val, 0.0, 1.0)); return col; } ENDCG } } }
You will have to use the non clipping shader that was provided on the other blog or make one based on the new version of the Transparent Colored shader in NGUI. This shader will get all sorts of weird if you use it in a non-clipping panel.
I use a custom Material which I put onto a UITexture. If you instantiate the material, you can feed it different mainTextures such as facebook images or something similar.
I hope this will be helpful to someone.
Nicki.
I am the one who did the original shader and I really thank you for this. I am new to shaders so when I did it I was surprised it even worked. This post is very informative and luckily for me in 2 days I will work on something which requires clipping and masking, so you just provided the way to do it. Thanks a lot!
Thank you for making the the first post. 🙂
I’m glad you can use it.
Hey again, I was reading the new shader I made for masking and I realized that all the variable names were one letter and I figured that that might not be helpful for someone willing to learn about shaders. I renamed most of the variables from what I could figure out, but I still have 2 that I don’t know what they mean. I was wondering if you could enlighten me. Those are appdata_t (what does the ‘t’ stands for?) and the v in the vert function (I assume it could be inputVertex ??).
Also, I see that there is a float4 _MainTex_ST defined in the CGPROGRAM but it is never used. Do you have any idea why that is there?
Thanks again
So you’re getting into some of the deeper magics of shaderlab. I’m by no means an expert, but I do know how to look up stuff. 😉
appdata_t is just a variable name, so you can change it to whatever. The name itself seems to be a leftover from somewhere – I honestly don’t know from where.
The MainTex_ST is a convention that Unity uses to apply texture tiling and offsets. Source: http://forum.unity3d.com/threads/11346-Displacing-vertex?p=79913&viewfull=1#post79913
Hi, is there a tutorial on how to use this shader?
I really want to learn more about this but don’t know where to start.
Hey Ray, I’m not entirely sure it will work anymore, since the alphaclip shader has been removed in favor of just using soft clipping with an edge of 0.
What you want to look into is how you can set up your own materials – there you can select the shader you want, which exposes those settings you see in the bottom picture.
In NGUI’s UITexture you can select your own material rather than texture, which makes it use whatever shader happens to be on your material.
Does that help you?
So I’m using NGUI and looking to create a custom shader that will display a texture, and apply a dynamically created alpha mask texture to it. Essentially, the end goal is to be able to draw on the texture in game with your finger and the spots where you touch will ‘erase’ the texture by modifying an alpha mask. I don’t really know where to start, and haven’t made any shaders myself in Unity yet. Any tips?
You can generate a texture with http://docs.unity3d.com/ScriptReference/Texture2D.SetPixel.html you just have to match your are to the texture coordinates.
In the shader you would simply have the visual texture in emission and your generated alpha mask connected to alpha. As you drag your finger on it, write the texture coordinates around your finger towards 0 so it gets see through.
I would recommend you invest in ShaderForge as it makes everything so much easier.
Hi, I used both of the shaders (masked and masked with soft clip). I have only one problem with clipped version. If i make transparent area of my atlas white then this shader doesnt work. Although the masked shader without clipping works. I am making transparent area white because when we compress a transparent texture in unity its more prone to artefacts where as if we fill transparent area with white its much better.
Any update for unity 5.3 please ?
I’ll take a look at it, Ankh.
http://nickithansen.dk/masking-and-clipping-textures-in-unity-5-4-ngui-3-9-8/
you are lovely life saver man!!!
thanks