- Home /
Sprite masking
Hi all,
Coming from an HTML5 background, 2D masking was very simple:
In Unity I want to create something similar to the destination-out effect, where a sprite is subtracted from other objects on the sorting layer.
I created the following shader which subtracts from every sorting layer in front of the object, but I just want it to subtract from it's current sorting layer.
Shader "Custom/MaskTest" {
Properties
{
_MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
_Cutoff ("Base Alpha cutoff", Range (0,.9)) = .5
}
SubShader {
Tags {"Queue" = "Transparent"}
Offset 0, -1
ColorMask 0
ZWrite On
Pass
{
AlphaTest Greater [_Cutoff]
SetTexture [_MainTex] {
combine texture * primary, texture
}
}
}
}
Is this the correct approach? Any help would be appreciated.
Answer by Bezzy · Sep 09, 2014 at 01:38 PM
Your shader looks about right.
It's the "Queue" you want to play with. And you'll need another standard sprite shader which draws later than the DepthMask shader. You'll use this for any sprite you want the mask to "block" (as well as place that sprite "behind" the masked area)
Objects you want to show "through" the mask should be on "Queue"="Transparent" The Mask itself should be at "Queue"="Transparent+1" Objects you want to be "blocked" by the mask should be on "Queue" = "Transparent+2"
So, the order of drawing is such:
Firstly, things that aren't affected by the mask at all are drawn to the screen, (when "Queue"="Transparent") Then, the mask is drawn. It occupies depth where your depth texture's alpha value are above "cutoff". (when "Queue"="Transparent+1") Then, the sprites affected by the mask are drawn after. If these sprites are physically occluded (i.e. behind) the mask, then so long as they have a ZTest LEqual on their shader (which happens to be the default if not specified), the mask will block.
What the mask has essentially done is "sealed" or "baked" any existing colours on the screen to its depth. When subsequent things are drawn, later in the queue, they will still have to check against the depth.
I wish this were simpler. I'm so, so sorry.
Thanks very much for the reply!
$$anonymous$$oving the mask and the masked object into their own queues makes a lot of sense, but unfortunately I'm struggling to get it to work.
I duplicated the default sprite shader and changed the queue to "Queue"="Transparent+2":
Shader "Custom/Sprites/Diffuse-$$anonymous$$asked"
{
Properties
{
[PerRendererData] _$$anonymous$$ainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[$$anonymous$$aterialToggle] PixelSnap ("Pixel snap", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent+2"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
Lighting Off
ZWrite Off
Fog { $$anonymous$$ode Off }
Blend One One$$anonymous$$inusSrcAlpha
CGPROGRA$$anonymous$$
#pragma surface surf Lambert vertex:vert
#pragma multi_compile DU$$anonymous$$$$anonymous$$Y PIXELSNAP_ON
sampler2D _$$anonymous$$ainTex;
fixed4 _Color;
struct Input
{
float2 uv_$$anonymous$$ainTex;
fixed4 color;
};
void vert (inout appdata_full v, out Input o)
{
#if defined(PIXELSNAP_ON) && !defined(SHADER_API_FLASH)
v.vertex = UnityPixelSnap (v.vertex);
#endif
v.normal = float3(0,0,-1);
UNITY_INITIALIZE_OUTPUT(Input, o);
o.color = v.color * _Color;
}
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D(_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex) * IN.color;
o.Albedo = c.rgb * c.a;
o.Alpha = c.a;
}
ENDCG
}
Fallback "Transparent/VertexLit"
}
Then I modified my existing shader to "Queue" = "Transparent+1":
Shader "Custom/$$anonymous$$askTest" {
Properties
{
_$$anonymous$$ainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
_Cutoff ("Base Alpha cutoff", Range (0,.9)) = .5
}
SubShader {
Tags {"Queue" = "Transparent+1"}
Offset 0, -1
Color$$anonymous$$ask 0
ZWrite On
Pass
{
AlphaTest Greater [_Cutoff]
SetTexture [_$$anonymous$$ainTex] {
combine texture * primary, texture
}
}
}
}
Unfortunately this is not having any effect. Looking at it, is "Offset 0, -1" overriding the queue anyway? Without the offset I can't seem to get any masking effect whatsoever though :/
Hunch: Don't use #pragma surface surf for anything UI releated. There are lots of extra render passes with that system which may well affect the z buffer.
Stick to using for non-lit stuff. #pragma vert vert #pragma frag frag
e.g. http://docs.unity3d.com/$$anonymous$$anual/ShaderTut2.html
Also, yes, Offset directly messes with depth, and gives inconsistent results across different graphics cards, so it's best to avoid it for anything other than fighting z fighting for things that absolutely have to be flat ontop of one another.
@thehen2 would you be so kind as to share your code for that if you still have it?
Could someone post the final shader code? Shader coding is a little over my head.
Answer by polinaihoj · Jun 16, 2015 at 05:39 AM
i was wondering what your guys' input might be on my problem that's also to do with masking.
i'm working on a game to teach hand washing to kids where i have two hand shaped sprites with random bits of dirt that get generated on them that then need to be scrubbed off.
my problem is that sometimes the bits of dirt generate and peek out a little outside the bounds of the hands, and it looks sloppy. i want to somehow use masking (although this might not be the right approach) so that any of the bits of dirt that peek out over the boundary of the hand sprites get masked by the canvas, or otherwise don't appear.
any suggestions?
Answer by SoloSebo · Sep 16, 2015 at 12:31 PM
Not sure if i should have started a new thread. But how can i accomplish SOURCE-IN?