Sprite masking

Hi all,

Coming from an HTML5 background, 2D masking was very simple:

alt text

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.

3 Answers

3

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.

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/Manual/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.

Brilliant, thanks, I got it working :)

thehen2, could you post your fully created solution?

Could someone post the final shader code? Shader coding is a little over my head.

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?

Not sure if i should have started a new thread. But how can i accomplish SOURCE-IN?

Yes, please start a new question.