Sunday, 21 September 2008

Accumulation buffers

Shadow mapping is working correctly, but only one (spot!) light at a time.

Nature is very different, so engine has to be changed a bit. How can one sum the contributions of several different lights, placed around the scene? Accumulation buffers can do the trick! These supplementary buffers will sum the RGB values of our different takes from any single light and return the final composite bitmap.

This screenshot shows a typical application of accumulation buffers: motion blur. With a very minimal modification of original dev-cpp's GLUT example we can achieve this interesting effect.

In pseudocode:

for (;;) {
glClear (GL_COLOR_BUFFER_BIT | GL_ACCUM_BUFFER_BIT)
const range = 10
for i=1 to range do {
render(i);
glAccum(GL_ACCUM, 1.0f/range)
}
glAccum(GL_RETURN, 1)
swapBuffers
}


Three brief comments.

First, the range means "how many different takes we wanna use for motion blur overlaps". This example is not optimized in any way and renders 10 times the scene for each pass.

Second, the render is bound to the i variable. The meaning is that we want to simulate movement, so it makes no sense to render 10 times the same static scene. In the example, I did the objects rotate "i degrees".

Third, the accumulation command takes a floating point value, which tells how much of the RGBA values we want to sum up in the buffer. Given that these values are clamped in the [0,1] range, and we're going to sum 10 shots, we can set these values in a way that the final count is 1: 10*(1/10) = 1.

The same philosophy shall work for multiple lights: we sum up the n contributions of n lights.