SSAO seems like a must these days, especially if you want a game that has fully dynamic content. The benefits to the overall look of the game may be subtle, but they are nonetheless substantial. So right from the start of my project, I have been determined to integrate this technology into my renderer.
My current test hardware is crappy, there is no denying that. My development platform is about six years old, and has an AGP GeForce 6800 GT GPU. Needless to say, this severely limited the variety of techniques I could try. Still, I didn't want technical limitations to cost me quality, and needed something that would provide such at a reasonable performance cost.
Keeping those restrictions in mind, here are the criteria I sought:
- Normals influence occlusion
- Handles self-occlusion
- Eliminates "halos"
- Looks decent without blurring
- Doesn't use branching
- Requires few samples
After much research and experimentaion, I settled on an approach developed by nullsquared (gamedev, ogre3d), which meets all my criteria beautifully. For the most part it follows the typical steps of any SSAO implementation, but differs in how it determines when a sample is occluded. Since I only vaguely understand how it works and don't care to explain it, I will refer you to read about his implementation.
For the test scene, the geometry was illuminated using one hemisphere light + six point lights. In order to get the best results, I do the ambient pass first, then apply SSAO to the light buffer via multiplicative blending. Then, I proceed to add the point lights on top of the ambient contributions. All calculations are handled in linear space, and receive color correction before being rendered to the back-buffer.
The nature of my deferred lighting renderer allows me to apply SSAO correctly to the ambient lighting. Most games would incorrectly apply it to the final rendered image as a post-process. While this can look good enough, it is not exactly correct since it affects all lighting (direct/indirect, diffuse/specular/reflection, etc).
So here are the results of this setup:
Figure 1. 1, SSAO; 2, SSAO & Ambient; 3, SSAO & lighting; 4, lighting; 5, difference
My tests showed that a scene of about 180,000 polygons rendered at 1280 x 720 ran at roughly 20fps, while the same scene rendered at 800x600 ran at 30fps. This was without any optimizations, such as using downsampled normals/depth and render targets for the SSAO. Plus, I haven't added a smart blur to the SSAO contributions yet, partly because the result look good enough as is.
In the future, I will be look at options for reducing the cost, such as using even fewer samples, and/or downsampled buffers. This will necessitate blurring, in order to cover up the pixelation of the occlusion, as well as good upsampling. These are areas which can also stand to benefit from optimizations tricks. ;)