The Quest for Shadows
Cosmopolis has a very large dynamic world. Players can modify terrain and building placement at runtime, in addition to day/night cycles. This brings up a plethora of issues in regards to shading and shadowing. Most video games use precomputed global illumination lightmaps to make the lighting look great at the cost of a single texture lookup. Unfortunately for us (well, fortunately for me as I enjoy attempting to solve this problem immensely) we must make things look pretty at runtime.
Starting with shadows, there are a number of issues that I have run into and I just wanted to prevent people from doing the same mistakes, so here are a few tips:
- All shadow tech demos/examples generally have a tiny scene to show off their shadowing technique.
- Don’t be fooled into thinking that it could scale to fit your 8km view distance scene (or even 150m view distance).
- Most shadow tech demos/examples have a static/hardcoded positional light.
- If you have a sunlight (directional with infinite position) you run into a new set of problems.
- The light view matrix must be placed somewhere… How do you determine this point? CameraPosition + (-LightDirection * 10000) seems like a good idea, but if you do that you have no resolution in your depth map. CameraPosition + (-LightDirection * 100) seems like the obvious answer to that, but that creates a parallax effect as the camera moves.
- If you have a sunlight (directional with infinite position) you run into a new set of problems.
- Screen Space Shadow Maps are an interesting idea, but blurring them is a terrible idea.
- Viewed up close the “pixels” of your shadow map are way too big on your screen to be blurred together
- Viewed far away the shadows will bleed into nearby objects that are not supposed to have shadow at all
With that in mind, I have mixed together PSSM (Parallel Split Shadow Maps) and SSSM (Screen Space Shadow Maps) with acceptable results (for now). PSSM is used to position 3 “light cameras” based on the position and rotation of the player camera, each at a different distance. The first covering the immediate surroundings and last covering about 250m view distance. To avoid the hard shadow edges I render a screen space shadow maps using PCF (Percentage Close Filtering) and then use the results of that map as an input to the objects that can receive shadows.
I render a depth map every other frame as opposed to rendering every depth map (remember there are 3) every frame. They are scaled to cover more than exactly the player’s view frustum to afford some leniency. I do however have to create the SSSM every frame, with a pretty expensive pixel shader, which is probably what I’ll try to tweak in the future.
Here are the results:
And here you can see the 3 depth maps rendered on the screen (top) and the SSSM results in the middle-left:

