You are looking for a technique called deferred shading. The basic premise is to reduce the number of lighting calculations done on a render while avoiding the expensive sorting used in the reverse painter's algorithm. The complexity of the whole procedure is O(number of objects + number of light sources)
. It takes (n+1)
steps, where n
is the number of light sources.
The first step renders each object to an intermediate buffer called the g-buffer. This wide buffer stores the depth, world-space normals, albedo (color), and other material parameters; all per-pixel. It is a quite cheap shader because it really just does vertex transformation and texture reads.
The second step runs once per light source and adds to a buffer called the la-buffer (light accumulation). The shader reads in the data for each pixel from the g-buffer and performs lighting calculations for the corresponding pixel in the la-buffer. The la-buffer is then either used directly as the output or run through a post-processing step. This step can be rendered with light geometry (sphere for point light, cone for spotlight, full-screen for ambient light) to avoid doing unnecessary light calculations.
The advantages of deferred rendering are that it scales much better to scenes with many dynamic light sources and that it only needs to do at worst one light calculation per pixel per light. However, it uses up a lot of memory for the g-buffer and is dependent on the fill rate of the GPU. The good news is that this problem will disappear as hardware gets faster and has more memory. It is also more difficult to implement transparency, but there is a method published to work around that problem. It also constrains you to essentially one lighting equation per light source, but this is generally a non-issue.
Here is an image describing the basic pipeline.
