You effectively need two shader caster passes, one for the base mesh and a second custom one for the outline that disables itself when casting shadows.
If you add a shadowcaster pass to the shader that uses the same surface offsetting code that the outline shader uses you’ll get it to show up in the depth, but disabling it from rendering in the shadows is a bit of a pain.
Unfortunately there’s no 100% way to test in the shadowcaster shader if it’s currently being rendered for the camera depth texture or a shadow map. Unity uses unity_LightShadowBias.z > 0.0
in their own code, but this humorously only works on directional lights as it’s zero for camera depth, spot lights, and point lights. Using unity_LightShadowBias.x > 0.0
is a little more reliable as long as you have at least a bias set on all of your lights, which you should. The unity_LightShadowBias.x
value is the light’s bias, and unity_LightShadowBias.z
is supposed to be the normal bias though as mentioned it appears to be disabled at least in 5.4.
Now if you add a custom shadowcaster pass to your shader the main model will no longer cast shadows or show up in the depth! The reason for this is the shadow caster pass for the main body was coming from the Fallback, but it sees a shadowcaster pass already exists in the shader and only the first one gets used. So now you can only choose to get the depth from the outline or depth and shadows from the body but not both!
So the answer is there is no solution, at least not with basic shaders alone. So now what?
You can split up the outline and main body into two separate objects and apply separate shaders on each. Has the benefit of you can just disable shadow casting on the outline mesh object. This is kind of clunky though.
You can use the deferred rendering path and write custom deferred toon shaders as in the deferred rendering path the depth really does come from if the shader has ZWrite on or off. But that’s not good for mobile or low end machines and you’re paying the heavy cost of the deferred pipeline.
You can use geometry shaders to double the geometry instead of doing it in two passes. This isn’t something I’m going to spend the time to implement.
You can double the geometry yourself in the model rather than rely on the shader. This is easily the best option, though it’d take some additional shader work to get the outlines to work the same it would still be possible. A bonus is now your objects use half the draw calls!
We can complain at Unity to let more than one shadow caster pass in a shader get used. Since this has been an issue for 5 years I doubt that’ll get changed any time soon.