Search Unity

Reading/Writing to the Stencil Buffer multiple times in the same shader

Discussion in 'Shaders' started by _eternal, Jan 8, 2019.

  1. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    304
    I've got a bit of a specific issue with my player character's shader. I'm trying to combine a couple of different stencil-based effects. Here's what I have:
    • A silhouette effect where certain objects can occlude the player and draw solid black pixels instead. The occluder writes a value to the stencil buffer, and the player checks this value and renders black pixels if necessary.
    • A masking effect where child objects of the player are only rendered if the player itself is visible. This is because some sprites are separate from the base sprite (e.g. eyes, items), but I want the whole character to be able to appear/disappear using a shader effect. This way, the eyes won't render if the base sprite is teleporting out and the top half of their body is cropped.
    Both of these effects work in isolation, but I can't figure out how to combine them (or if this is possible). The Occluder writes the value 4 to the stencil buffer, so I can do something like...

    Code (CSharp):
    1.  
    2. Pass
    3. {
    4.     Stencil
    5.     {
    6.         Ref 4
    7.         Comp Equal
    8.     }
    9.  
    10.     //Simple vert/frag shader to display the silhouette color instead of the sprite color
    11. }
    Below this, the surf shader continues like normal:

    Code (CSharp):
    1. Stencil
    2. {
    3.     Ref 5
    4.     Pass Replace
    5. }
    6.  
    7. CGPROGRAM
    8.     //The rest of the surf shader, which involves drawing the whole sprite and possibly modifying its colors
    9. ENDCG
    When I do this, I think the surf shader overwrites the silhouette drawn in the first pass, because I can't see the silhouette at all. However, if I switch the order around and put the silhouette pass at the end, the Stencil function of the surf shader overwrites the 4s in the buffer, so the silhouette pass never executes.

    I'm pretty new to shaders so I'm not sure if I'm approaching this the right way. I want to write the result of the surf shader to the stencil buffer, but I also want the result to be affected by the silhouette pass.
     
  2. Azkron

    Azkron

    Joined:
    Oct 23, 2016
    Posts:
    5
    I am also trying to figure this out. Did you find a solution for this ?
     
  3. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    304
    I... don't think so. It's really hard to visualize the sequence of execution in shader code, so trying to layer effects was too complicated.

    However, I can say that I fixed this specific problem by just creating the silhouette as a child object. I have a script that ensures that the silhouette's SpriteRenderer matches the character's SpriteRenderer in LateUpdate, so the two are always in sync. That way, the silhouette's SpriteRenderer can use its own material and shader without having to deal with the parent.