Search Unity

It was bright and sunny morning. It must have been some time last fall, when we finally got the message we had all been waiting for: a Challenger has arrived!

Granted, it was still an early draft; bald, clean-shaven, unskinned and without proper materials set up – but we were still excited to finally have him in the project. “Somebody puh-lease slap some materials on him and put this bad boy into the scene!”

And we did. And it was awesome. Except… something didn’t quite look right. “Uhm.. is this guy really set up to receive dynamic shadows?”. He was. But not quite the kind we were expecting.


Most of him didn’t actually seem to receive any shadow whatsoever, and what we did identify as shadowed was very weird and jagged looking.

The Problem

A few quick shader hacks later, and the ugly truth revealed itself; not only was half the character missing shadows altogether; what little was there was indeed looking blocky and buggy.


‘Why was this happening?’, you might wonder at this point. After all, doesn’t Unity 5 sport this brand new and shiny soft-shadow filtering algorithm? It does, and it looks great. It so happened, though, that some of our scenes had view distances as far as 3,000 meters, and we’d decided we wanted shadows cast from and onto every single pixel in the view frustum. Now, naturally we had tweaked the cascade splits and shadow biases as best we could, and the shots generally looked really good both near the camera and far, far away.

What we hadn’t really tested properly until now was adding a very detailed character, very close to the camera in such a large-scene setup. Not only did we lack the resolution to produce soft, shadowy goodness on the character; the depth bias required for the scene to look good was so large that it pushed half the character out of shadow. Turns out casting soft shadows from a tiny leather strap, onto a piece or armour 1cm away, isn’t quite the same case as having a medium sized rock cast soft, stable shadows onto the ground. Who’d have thunk, right?

So we needed a solution to this predicament. We could have moved the first cascade really, really, really close to the camera, but that would have cost us a full cascade on the scenery. It would also only have worked in the scenes where the characters were really, really, really close to the camera, which would have solved enough of our problematic shots.

The Solution

Instead, we decided to apply a bit of old-school technology to the problem. “What if we just explicitly render an additional shadow map focused on the character?”. Said and done. Two hundred lines of code later, the engine was generating these for us to play with:


At this point, we were able to generate enough data to apply pretty much any kind of fancy schmancy shadow filtering we felt like. We didn’t really have a great deal of time to spend fine tuning the best possible filtering, though, so we decided to go for a simple distance-aware sampling scheme similar to Nvidia’s PCSS[1].

Although not present in the shots shown here, we also had an option for capturing data from shadow casters outside the character’s focus area; e.g. to still have the static world cast shadows onto these dynamic characters. Such casters were projected onto the near-plane of the shadow rendering camera, ensuring they would always have the maximum blocker-to-receiver distance in the soft-shadow filtering scheme.

The only problem remaining at this point was how to integrate this nicely into the rendering pipeline. After some pondering and head-scratching, it turned out there was a very simple way to override the shadow functions used by nearly all common Unity shaders. After a few iterations, we eventually simplified it to only requiring two additional lines of code to add unique shadow support to any shader:

#include "UniqueShadow_ShadowSample.cginc"

Note that the include has to go before any other engine includes for the override to work correctly. Obviously, this is slightly misleading as we just hid the actual override complexity behind an include file, so for anyone else looking to do something similar, here’s essentially what it boils down to:

#include "AutoLight.cginc"

The conditions in our case are whether unique shadows are enabled, and whether we’re currently rendering a directional light or not. This second condition allows the feature to co-exist peacefully with other types of shadow casting light sources.


So after all this hard work, did we end up with satisfactory results? Here’s the same debug view again, this time toggling unique shadows on and off:


Old-school tech for the win!

In Summary

One aspect to keep in mind is that – like most other rendering features – adding more shadow maps to your project doesn’t come for free. The shadow maps take up additional video memory, and there’s extra draw calls required to render into them, as well as increased bandwidth usage and computation power required to use them in your shaders.

For The Blacksmith, we set the system up so that we could dynamically toggle unique shadows on and off depending on how close to the camera the actors needed to be. Thus, we only paid the extra rendering cost in the shots where the characters occupied a large portion of the screen. For a game where the player might never get very close to the camera in normal gameplay, one could imagine only enabling this feature for close-ups in selected cut-scenes.

To better demonstrate this feature in isolation, we’ve put together a small demo project which you can get from the Asset Store. There’s a very basic scene included, meant to illustrate the problem case of having fine character detail near the camera in a large outdoors environment. Even with the first cascade covering only 1% of the total shadow distance, there’s a fairly radical difference between the uniquely shadowed challenger on the left, and the cascade shadowed challenger on the right.



Comments are closed.

  1. Rubén García

    July 17, 2015 at 1:44 pm

    Anyway you could add a way to control Unique Shadow strenght or sync it with the directional light shadow strenght?

  2. Awesome! I’ve been curious about doing this recently, thanks for the fancy schmancy stuff =)

  3. Manuel Kugelmann

    June 27, 2015 at 3:10 pm

    Nice post!

    Guess I should update my Unity3d 4 spotlight cascades from 2013. Back then I had to solve a similar problem with spotlights for

    I solved the core problem with cascades (multiple blended shadow maps) for spotlights:

    To increase shadow map resolution for wide spotlights I intersected the spotlight frustum with the camera frustum to minimize the needed shadow map frustum. For lookup into the cookie texture I used the original frustum.

    The still remaining problems with shadow map bias could be resolved by integrating per light directional occlusion / screen space ray stepping to the shadowing calculation:

    Technically I had to repurpose some undocumented and thus not stable parts of the Unity3d 4 rendering pipeline. I used the bias setting of regular Unity3d lights to index into a data texture where all the additional info for this light resided (like the original frustum for the cookie, etc.). Aras was a big help to get some things sorted out and I like to think that some of my wishes back then influenced some Unity 5 features – but probably it’s just common sense that the features were done this way …

    My current projects are not that rendering heavy and I’m not yet up to date with Unity5 rendering. I would be grateful for any hints on how to get my work from 2013 done best with Unity 5…