Bizarre order dependency with directional and projective lighting


I was surprised today to find a strange issue with my renderer.

The way the renderer works is that lights are added to the scene, and the renderer will apply the lights in an arbitrary order each frame (they’re inserted into a data structure that doesn’t guarantee any particular order, and the order will typically change every frame). This is all fine, because the light contributions are effectively summed with (GL_ONE, GL_ONE) additive blending, and addition is commutative, so the order that light contributions are applied makes no difference to the resulting image…

… Until today!

Using apitrace, I’ve stepped through the rendering of the scene. Here’s the state of the scene with no lights applied:

Here’s the scene after the projective light is applied:

Here’s the scene after the directional light is applied:

Fine. That’s the result I’d expect. Now let’s try applying the exact same lights in reverse order…

(continued in next post due to image limit)

First, the empty scene:




Why does the order that the lights are applied matter?

The render target is an ordinary RGBA8 texture, and blending is always enabled and the equation never changes from (GL_ONE, GL_ONE).

To clarify: The issue only occurs in scenes containing the combination of projective and directional lights. It doesn’t occur with spherical/point and projective lights, or spherical/point and directional lights.

Found it.

When a directional light is evaluated, it disables culling (as directional lights are implemented by rendering fullscreen quads). The code path for the projective light case forgot to turn front-face culling back on (as projective lights are rendered using frustum-shaped light volumes), so the lighting was applied twice.