Wednesday, 7 July 2010

Shadows

A year ago I started working on shadows for the game. I had decided that it was essential to have them but as the game is a shooter they do not have to be perfect. They have to be good enough and fast.

Before you critisise that decision take a look at some of the AAA games. The quality of shadows varies considerably. Ghost Recon has near perfect shadows but Gears Of War only has good shadows cast from the characters. Some scenery does not cast shadows at all or only casts it on other static objects! If you play either game you will be happy with the result although in Ghost Recon just occasionally you may notice that the drone high up in the sky casts a shadow on the ground.

A year ago I knew nothing about shaders. My method was to take the Creators Club shadow sample and try to join it to the Creators Club skinning sample. It took me three months to work it all out. In the process I was learning about animation and about effect shaders.

The result was not good enough but I needed to move on and get more of the game created. I knew I would return to it. That time was this week.

I now know much more about shaders. I've re-written them many times to add the terrain texturing, decals with transparency and to make use of effect pools. Effect pools were the best improvement because I use the shared prefix which means I can set the parameters just once for the entire scene rather than once per mesh! [Edit: XNA 4.0 removed effect pools!  I had to add a lot of code back in!]

That also meant I now only had to edit one effect file which was shared by all of the draw calls for all objects static or animated.



The above is the finished result which I am pleased with.

That uses Parallel Split ShadowMaps (PSSM) with edge tap smoothing Percentage Closer Filtering (PCF).

A lot of the time was tweeking the various settings to get them to all work together. The split distances have to be just right, the number of samples for the PCF has to be just right and to get any speed I have to keep the shadow map sizes to 512x512. I use 4 parallel splits but I calculate them at different frames to minimise the impact on performance.



To get the shadows to overlap and cover the correct models as they move past the shadows it is necessary to draw the objects with the furthest away from the light source drawn first and then in order of the next closest and so on. That sort is done on the CPU not the GPU. The CPU on the Xbox 360 is poor compared to a PC so that sort has to be efficient.

Although the coding is all mine I can't claim the design. Many many clever people have come up with the maths formulea and put it in to code or articles. The NVidia developer site was essential reading but the final finishing touches was based on an XNA forum post. I'd like to thank everyone who has shared any shader or other code about shadows. I've probably read or looked at them all in the last year.

No comments: