iOS Development - Deferred Lighting
In photography and cinema, lighting is essential in conveying the emotion and atmosphere in a scene. Often this requires the use of many lights at once, which is computationally expensive when using a forward rendering approach. In order to support many lights of varying types (points, directional) displayed at once, we can de-couple the lighting calculations from the rest of the rendering calculations by using the deferred lighting approach.
In my implementation, my 1st pass renders into an intermediate buffer (g-buffer) consisting of a 24-bit normal and a scaled 8-bit specular exponent. The depth buffer is retained as well, enabling subsequent passes to re-create the world coordinates of each rendered pixel.
The lighting pass is executed for each light in the scene. A second g-buffer containing a 24-bit diffuse color (rgb) and 8-bit specular value is updated by each light. As an accumulation buffer is not available on iOS devices, a glBlendFunc(GL_ONE, GL_ONE)
call is used to enable additive alpha blending. Directional lights (representing the sun) are rendered as full screen quads with the 24-bit z-buffer and the 1st g-buffer as input textures. The point lights are rendered using 3-d sphere geometry, taking advantage of the z-buffer and area of the polygons to cull out the lighting calculations for pixels that will not be affected by each light. As the point light spheres begin to overlap, performance drops due to the fill rate limits of the PowerVR SGX GPU. The result is either a couple very large point lights or hundreds of small points lights can be used simultaneously with the same level of performance.
As Apple has not exposed the MRT (Multiple Render Targets) functionality of the PowerVR SGX GPU’s, it is necessary to execute the vertex shaders again for the 3rd rendering pass. During this pass, the z-buffer is already in a primed state, reducing the number of fragment shader executions to only the surfaces that have not been occluded by other geometry. At this phase, the normal mapping, diffuse mapping, and specular mapping is applied using the contents of the G-Buffer to modulate the light intensity.
A 4th pass is often necessary in some scenes, using a conventional forward-rendering approach. This is used to render semi-transparent (alpha) textures. These polygons must also be sorted from back to front to ensure that they are rendered correctly. As this is quite expensive, alpha transparent materials should be kept to a minimum when possible or additive blending modes be used to eliminate the need to sort polygons. An alternative is to use the “discard” instruction in GLSL to create “punch through” textures that are rendered in the 3rd pass for materials such as leaves and grass. The “discard” instruction reduces the effectiveness of the PowerVR tile-based rendering architecture; however, the impact is reduced by use of the z-buffer which has been primed with the previous passes.
Finally, a 5th pass is applied to perform color grading, depth of field, vignetting, and other post-processing effects.
When multiple coloured lights combined with normal and specular maps, the materials gain more depth and variation, while reducing the appearance of tiled textures. In addition to creating more immersive visuals, deferred lighting can improve gameplay. For example, characters can carry a torch while exploring dungeons and you can have armies launching hundreds of flaming arrows.
(Models used in test scene have been created by Dexsoft Games)