My scene has a directional light. It uses deferred rendering and cascaded shadow maps.
I’ve been working on a custom grass/foliage shader to mimic (very poorly :p) the translucency/forward scattering seen from on the side of the grass facing away from the directional light.
To really get the most out of this effect, I want the blades of grass between the light source and the blade you are viewing to occlude/dampen any forward scattering that I would otherwise apply. It make sense, right? The front of the blade is in shadow, so the back of the blade shouldn’t transmit as much light.
Now, implementation wise, I could render the scene from the lights point of view and store the depths and blah blah blah, shadow maps - Unity already does this for me. I was curious to see what Unity’s shadow map looked like, so I hopped into the Frame Debugger…
The top image is the final output.Light is pointing into the camera. The shading you see on the grass blades is due to my custom translucency surface shader and the issue is there are no shadows on the back side of the blades!
The bottom picture shows the shadow map, and interestingly it has the data I want in it! It is showing the shadows on the back sides of the grass blades.
Is this expected behavior? Is the shadow gather phase discarding shadows on surfaces facing away from the light source… and is that expected? Is there a way I can disable it without having to roll my own shadow gathering?
The shadow gathering just uses the pixel position, no concept of facing, so shadows showing up on surfaces facing away is totally expected. In normal use the shadows are multiplied on top of the lighting calculations that are done later, and which do (normally) use the surface normal and light direction to prevent faces on the back from being lit, so there’s no reason to do that work when doing the shadow gathering.
To clarify, are you saying that if the pixel is not lit, i.e. pixel faces away from the light, then no shadow is applied?
That makes sense. It’s what I see in the images above, and while this behavior maybe wanted normally, I actually would like the shadows applied to the unlit faces here (or at least the unlit surfaces I care about, e.g. grass).
Not sure what the best way to tackle this in Unity would be. Here’s an idea: I noticed the shadow render passes happen after the deferred pass. If I could re-order the render passes so that the deferred lighting happened after the shadow cascades were rendered (and gathered), then I could sample the shadow map and apply the correct effect during the grass material’s surface shader.
Effectively, yes. Technically it is still applied, but only to the light from which the shadow would be cast from. Other lights, like ambient lighting or point lights, would ignore the directional light shadow, just as the shadows from a point light or spot light won’t affect the directional light.
Don’t think of them as unlit. You do actually want them to be lit, just not using the default shading model.
Not possible. The shadow cascades, like all lighting and shadows in deferred, are rendered onto the textures that the deferred pass create. With out the deferred pass there’s nothing for the shadows to be cast onto.
There’s a few ways to go about what you’re trying to do.
Surface normal manipulation. Change the surface direction to always point towards the light. This will mess up specular lighting and fresnel, so your specular would need to be black. I believe the main light direction is still accessible during the deferred pass, but if it’s not then either you’d need to set it via a script, or just dont use this technique. It also will mess with lighting from other lights. A frequent alternative is just have the surface normal direction be straight up in world space.
Don’t use the deferred rendering path. The default deferred rendering path can only render objects using the Standard shading model. If you use forward rendering path instead you can use whatever shading model you want.
Don’t use Unity’s built in deferred rendering path. If you use something like the UBER - Standard Shader Ultra asset, it has an option to slightly modify the shader used for deferred lighting to add support for translucent lighting.
Don’t use a deferred shader. Yes, I know I’ve said don’t use deferred 3 times now… and this is actually kind of the same as option 2. You can render objects using the forward rendering path even when you’ve set the engine to use the deferred pass. Anything transparent must use forward rendering, but you can also have opaque lit objects using forward rendering as long as they don’t have a deferred pass defined in their shader. Depending on how you’re authoring your shader it’s as “easy” as defining a custom lighting function for a surface shader (and using exclude_path:deferred, and not using Fallback "Diffuse"), or just not having a "LightMode"="Deferred" pass in your vertex fragment shader (and also not using Fallback "Diffuse"). If you’re using Shader Forge I suspect using custom lighting there would also work.
I ended up flipping the surface normal. It was the easiest approach, and I had already been zero’ing out the specular and smoothness for the pixels facing away from the light to get a more convincing translucency effect.