MultiPass Shading - Shadow over geometry

Hello,
I am new to shader programming and tried to write a grass billboard shader for my procedural terrain.

A triplanar shader textures the terrain and as I tried to implement the geometry shader for the grass, I encountered the problem that I can’t multipass surface and geometry shaders…
So I rewrote my triplanar shader as vertex/fragment shader for the first pass and the grass generation as 2nd pass… BUT when I try to make shadows work I can choose between these two versions:

  1. 2nd Pass has LightMode = ForwardBase and receives the terrain shadows (OK!) even if the grass is covering an area with a shadow (NOT OK!)

  1. 2nd Pass has no LightMode tag and doesn’t receive any shadows of the terrain

I think I am doing something wrong… Can someone help? :slight_smile:

Relevant code:

    SubShader
    {
       Tags { "RenderType" = "Opaque" }
       // #### NORMAL GEOMETRY ####
       Pass
       {
           Tags{ "LightMode" = "ForwardBase"}
           ....
           #pragma multi_compile_fwdadd_fullshadows   
           ...
       }
       // #### GRASS ####
       Pass
       {
          Tags{ "LightMode" = "ForwardBase"}
          ...
          #pragma multi_compile_fwdbase
          ...
      }
    }

Anyone? :frowning:

You shader’s shadow caster pass is only rendering the terrain, so that’s the only thing that’ll receive shadows. The shadows for the main directional light in Unity is rendered as a prepass to a full screen texture using only the depth buffer for the scene, and subsequent objects simply sample from that texture if they receive shadows.

You need to write a custom shadowcaster pass for the grass, though I don’t know if it’ll render both shadow caster passes so you may need to write a custom one that renders the terrain geometry and the grass at the same time. I just posted in another thread about shadow casting and receiving in geometry shaders here:

The frame debugger might help you understand what’s happening here if you’re having problems getting your head around it. You should see it create a depth buffer from the camera, then a depth buffer from the directional light, then render the screen shadows, then render the actual scene using those already rendered shadows.

1 Like

Thank you :slight_smile: This should help.

Okay I used stuff from the other post you mentioned and now it works.

But my graphics card is dying :smile: Because I have a LOT of grass billboards and everyone is casting a shadow now.
I just want them to receive shadows but when I change the SHADOW_CASTER_… stuff to SHADOW_COLLECTOR_… everything is like before.
Does ShadowCollector even do something? Because when I comment the whole Pass out, the result is the same.

Shadow collector is a Unity 4.0 thing; in Unity 5.0 the shadow caster pass is used for both casting and receiving. If you don’t want it to receive shadows the usual solution is to turn off shadow casting on the object’s renderer component, but that won’t work for you. Instead you’ll have to test if the current depth pass is the camera depth or a shadow depth. Crazy enough there’s no 100% way to do this and even Unity’s own code uses something of a hack.

My suggestion if you want to disable shadow casting is do something like this in the pixel shader:

if (unity_LightShadowBias.z != 0.0) discard; // discard if shadow pass

Alternatively you could probably have a similar branch in the geometry shader, but I don’t remember if you can output nothing from a geometry shader with out it complaining. This would be preferable though as it means nothing even attempts to render.
Another strange but better-than-discard option if the geometry shader complains about having no output is output the position if all of the vertices behind the clip plane so they get rejected before rastorization. This is a trick Avalanche did for GPU culling in Just Cause 2.