CSC 572 (Winter 2011) - Zoe Wood, PhD.
In traditional forward lit graphics engines, rendering a scene requires the developer pass each object in the to the graphics card where it is processed once per light and each light's contribution is blended into the final image. The issue with this method is that the complexity of lighting calculations becomes O(n*l), where n is the number of objects and l is the number of lights. Additionally, OpenGL traditionally only supports up to eight dynamic lights, which can become a limiting factor in many scenes.
A solution to this problem is deferred shading: a new graphics engine technique that performs all shading (i.e. lighting) calculations in image space, meaning that our original scene geometry is discarded but its data is stored per pixel. More specifically, for each object in the scene, we determine which pixels in the final image it will cover and store its geometry data at each of those pixels. This per-pixel data, stored in textures, is collectively called the G-buffer. The lighting calculations are deferred until all objects' data has been stored. At this point, each pixel's color is determined by using the G-buffer data as input to a lighting model that blends the contribution of each light into the final color. In this way, geometry is separated from lighting, and we can achieve lighting complexity of O(n+l), which allows us better flexibility in lighting calculations as many small lights are just as computationally intensive as a few big ones. Additionally, deferred shading combats some practical issues in implementation such as batching and post-process effects.
Strengths of Deferred Shading:
Disadvantages of Deferred Shading:
Two passes are required for this algorithm: a geometry pass and a lighting pass.
In the geometry pass, we render to a framebuffer object that uses three textures as multiple render targets (MRTs) for color, normal, and depth data. These MRTs are collectively called the G-Buffer. Scene geometry is rendered, but instead of drawing the geometry, a fragment shader writes data to the G-buffer.
The lighting pass renders directly to the standard color buffer with additive blending enabled, performs all lighting calculations in view space, and has two sub-passes. The first sub-pass is for ambient and directional light, where a fragment shader specific to those lighting models is attached. The inputs required by the shader are ambient light color intensity, directional light color intensity, directional light direction, and the G-buffer data. A fullscreen quad is rendered in order to shade every pixel.
The second sub-pass is for point lights. A point light shader is attached that requires the radius of the current point light being drawn and its color intensity. Each point light is rendered as a sphere using the same world coordinate frame, camera position, and look at vector as the original scene geometry. The point light position in view space is reconstructed by transforming the vector <0, 0, 0, 1> with the Model-View transformation. For each pixel, the view space position of the geometry is reconstructed by sampling the depth from the G-buffer, linearizing it (because the depth buffer does not store linear depth values), and multiplying it by the normalized vector from the camera to the light geometry at that pixel. The purpose of this is to reduce the memory storage and bandwidth requirements, as we no longer have to store view space positions in the G-buffer, because they are traditionally a bottleneck for deferred shading.
At this point, all required inputs have either been reconstructed or can be sampled from the G-buffer and the standard Lambertian diffuse shading is computed. However, as a final step, the shading is attenuated based on distance from the point light center, with full attenuation beyond the point light's specified radius.
Once both the geometry and lighting passes have completed, our scene is rendered to the back buffer and we can swap buffers to display.
These results were obtained on an Intel core i7 920 running at 3.5 GHz with 6GB of memory. The GPU is an ATI 5870 with 1 GB of on-board video memory. The coding was done using OpenGL 4.1 Compatibility Profile Context with GLSL 4.10.
There is currently an issue where shading near the edges of the screen is disappearing. I believe this is an issue with my reconstruction of view space geometry coordinates. Due to the limited development time, this will have to be resolved in the future. However, to definitively determine the cause, I plan on integrating the view space position of the scene geometry into the G-buffer. With this data available to my point light fragment shader, I will be able to determine if my reconstruction is accurate.
First and foremost, I am going to resolve the screen edge shading issue mentioned above. Beyond that, the engine needs to support rendering point lights in a more streamlined fashion. Currently, a "preDrawPointLight" function is called, the user renders her light geometry, and a "postDrawPointLight" function is invoked. I would rather a singular "drawPointLights" function exist with a parameter for a list of light objects with associated radii and colors. This would simplify the management of point lights greatly and simplify the user's code. Additionally, I would like to support more lighting options. Specifically, other lighting shapes, such as cylinders.
Demo Executable - unZip and run 'deferred_shading.exe' under Windows.
Source Code - unZip and open with Visual Studio 2008 or newer.
Commands:
J. Andersson. Parallel Graphics in Frostbite - Current & Future. Web, 2009. DICE. <"http://s09.idav.ucdavis.edu/talks/04-JAndersson-ParallelFrostbite-Siggraph09.pdf">
D. Filion and R. McNaughton. Starcraft II: Effects & Techniques. Web, 2008. Blizzard Entertainment. <"http://ati.amd.com/developer/siggraph08/chapter05-filion-starcraftii.pdf">.
S. Hargreaves. Deferred Shading. Web, 2004. Climax Brighton. <"http://read.pudn.com/downloads160/sourcecode/game/724029/DeferredShading.pdf">
S. Hargreaves and M. Harris. 6800 Leagues under the Sea: Deferred Shading. Web, 2004. NVIDIA. <"http://http.download.nvidia.com/developer/presentations/2004/6800_Leagues/6800_Leagues_Deferred_Shading.pdf">
A. Kaplanyan. CryENGINE 3: reaching the speed of light. Web, 2010. Crytek. <"http://www.crytek.com/cryengine/presentations/CryENGINE3-reaching-the-speed-of-light">
M. Lee. Pre-lighting in Resistance 2. Web, 2009. Insomniac Games. <"http://cmpmedia.vo.llnwd.net/o1/vault/gdc09/slides/gdc09_insomniac_prelighting.pdf">
I. A. Lobanchikov and H. Gruen. GSC Game World's S.T.A.L.K.E.R.: Clear Sky - a showcase for Direct3D 10.0/1. Web, 2009. Game Developers Conference '09. <"http://cmpmedia.vo.llnwd.net/o1/vault/gdc09/slides/100_Handout%202.pdf">
J. Moore and D. Jefferies. Rendering Techniques in Split/Second. Web, 2009. Blackrock Studio. <"http://www.disney.co.uk/cms_res/blackrockstudio/pdf/Rendering_Techniques_in_SplitSecond.pdf">
M. Valient. Deferred Rendering in Killzone 2. Web, 2007. Guerrila Games. <"http://www.guerrilla-games.com/publications/dr_kz2_rsx_dev07.pdf">
A big thanks to Matt Enright at Cadenza Interactive for all his help and advice.