Wednesday 27 January 2016

Stencil Buffer....for 2D

This is a sort of follow up of the previous post.

Here we achieve the same effect, this time using sprites in a 2D environment.

When the character is behinds an object, it will be drawn in a single color, giving the impression that is placed behind that object.

Here is a picture of the effect:



The approach is the same: one shader for the tree, which works as a mask, and one for the character.

The shader mask:

//  previous code, properties ecc...

  Tags
        { 
            "Queue"="Transparent-10" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent" 
            "PreviewType"="Plane"
       
        }

        Cull Off    
        ZWrite Off
      
        Blend One OneMinusSrcAlpha

        Pass
        {

        Stencil
        {
        Ref 4
        Comp Always
        Pass replace
        }

// rest of the code for normal rendering...

The idea is the same awe have seen it in the previous post, the stencil buffer is given a value of 4 for each pass (draw call).

Then, we have the shader for the character. Just like the shader for the 3d model of the previous post, this shader consists of two passes: the first one returns a single color (_MaskedColor) whenever the sprite is drawn on those pixels which have the stencil buffer with the value 4 (Ref 4). In other words, whenever they are in contact with the tree.


//  previous code, properties ecc...

  Tags
        { 
            "Queue"="Transparent" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent" 
            "PreviewType"="Plane"
  
        }

        Cull Off     
        ZWrite Off
    
        Blend One OneMinusSrcAlpha

        Pass
        {

        ZWrite on
        Stencil
        {
        Ref 4
        Comp Equal
     
        }

// rest of the code, vertex funcion ecc...

 float4 frag(v2f v) : COLOR
            {
              return _MaskedColor;

            }

//rest of the code....

The second pass will draw the sprite normally, but we specify to do so when the stencil buffer is NOT 4 (Comp notequal).

//  previous code, properties ecc...

   Pass
        {

        Stencil
        {
        Ref 4
   Comp notequal
        }

// rest of the code, vertex funcion ecc...

 fixed4 frag(v2f  v) : SV_Target
            {
                fixed4 c = tex2D(_MainTex, v.texcoord) * v.color;
                c.rgb *= c.a;
                return c;

            }

//rest of the code....

The fragment function returns the texture and whatever color we assign to the variable _Color, just like your standard sprite shader.

A few important things to remember:

- In this particular case, the character is made of different sprites and it is not animated with sprite sheet. That means that every single sprite renderer of the objects that compose the character need a material with the shader we wrote.

- This method will work whenever the sorting layer of the masking object (in this case, the trees) are at a lower value compared to the character sorting layer. I'm currently looking to find a method that allows this effect to work regardless the sorting layer of the sprites involved. If you happen to know a good solution, please, drop a line down below :).

Example scene here.



Character sprite from: https://www.assetstore.unity3d.com/en/#!/content/42731

3 comments:

  1. Thanks! Could you post some source code so that we could get a good idea of how to implement this?

    ReplyDelete
    Replies
    1. Hello again, sorry for the delay. Below is the link to the project. It's very simple, you can see the shaders I used to create the effect. Let me know if you have any more questions.

      https://github.com/Paolo86/Stencil-Buffer-2D

      Delete
  2. Hi, sure, I will set up a small project an link it to you on Github when I have have a moment. Meanwhile, try to have a look at Sprite Masking, one of Unity's latest feature, it allows you to achieve this effect without having to put your hands on the shader.

    Unity doc -> https://docs.unity3d.com/Manual/class-SpriteMask.html

    ReplyDelete