Monday 25 January 2016

Stencil Buffer Shader for special effects

The goal is to be able to see objects behind other specific object. In this little project in particular, I wanted to be able to see my character when it was behind some wall, in order to be able to move it in the direction I wanted him to.

This is an image of the effect:


In order to achieve this, we need to use two shaders: one for the walls, one for the character.

The purpose of the shader applied to the walls is to allow the special effect to work only on certain objects (walls), just in case I wanted some walls to completely obstruct the view.

Both shaders are fairly simple, they react to light (multiple lights as well), however, they don't cast shadows.

The walls shader simply uses a stencil buffer, like so:

Pass
        {

        Stencil
        {
        Ref 4
        Comp always
        Pass replace
        }


// rest of the code for rendering

}

This lets the gpu know the all the pixels used to draw the object with this shader are given the value 4 in the stencil buffer.

Then, we have the character shader. I wrote two draw calls: one that renders the character normally and the other that renders a single color, which is the white color we see when the character is behind the wall.

The first pass goes like this:
    Pass
        {
        Tags{"Queue" = "Geometry" "RenderType"="Opaque"}

        ZWrite off
        ZTest Always
        Blend One OneMinusSrcAlpha

       
 Stencil
        {
        Ref 4
        Comp equal
        }




fixed4 frag (v2f i) : SV_Target
            {
                
// sample the texture

                
// apply fog

                return _MaskedColor;
     
       }


}

This always draws a white color (or whatever color the variable _MaskedColor is set to) for each pixel of the character model. Notice how the fragment function simply returns a color
(_MaskedColor) which, in our case, is white. It is possible change the color in the inspector of the material.

The second pass:

        Pass
        {
        Tags{"LightMode" = "ForwardBase"}
        ZWrite on
        ZTest LEqual
       
// rest of the code for texture and lighting rendering
        }


Basically, the gpu will render the texture and lighting color whenever the object is in front of other object (ZTest LEqual), overriding the white color of the previous pass.

It is very important to respect the order of the passes.

You can try the effect in the scene here.













No comments:

Post a Comment