Attention: open in a new window. PDFPrint

Fun with OpenGLs Accumulator

As all modern 3D graphic cards provide a accumulator buffer I just decided to play around with it a little bit as one can create some really nice effects with it. As it name declares, the accumulation buffer can be used to accumulate rendered pictures. It allows some basic functions to write or add the current front or backbuffer (depends on which one is currently activated for drawing) to it while performing a scalar multiplication on the current color values. Which just means that you can multiply every pixel of the picture currently in your front or backbuffer and add it to the color values currently stored in the accumulator. This allows you to combine two (or more) pictures within the accumulation buffer. You also can write the data of the accumulator buffer back to your back or front buffer to show it on your screen.

 

 

Before we start I should mention that the accumulation buffer has not been designed for real time rendering which means that on most systems this buffer is pretty slow and would drop your frames per second to a very low value (just a few operations dropped my rate from 2000 fps to 25-30 fps). The accumulator has mainly been designed for non realtime operations like rendering single pictures. Using it for that purpose you can archive very amazing effects.

You might take a look at this picture:

The picture shows a rotating and moving cube blurred by the accumulator buffer.

The picture shows a rotating and moving cube. It has been added to the accumulator buffer after multiplying its current color values by 0.03. Afterwards the image was written back to the back buffer which is written to the accumulator with a multiplicator of 0.97. So every frame contains only 3% of its actual color values and is dominated by 97% of the color values of the previous frames. This causes in a effect that shows some very excessive motion blur.

The main idea of using the accumulator buffer is the fact that you can use it to blend two rendered images over each other. The accumulator is mainly controlled by three methods:

  1. glClear with the parameter GL_ACCUM_BUFFER_BIT to clear the accumulator buffer
  2. glClearAccum allows clearing a specific color from the accumulator (and the alpha value)
  3. void glAccum(GLenum op, GLfloat value); allows writing and returning the accumulator buffer

I will just concetrate on the glAccum-method. In most cases you should not use glClear on the accumulator as it is very slow and you will most likely clear the buffer to writing new image information to it. Writing the image data from the current buffer to the accumulator can be done using GL_LOAD. This replaces all color values within the accumulator buffer by the values from the current drawing buffer multiplied by the given value. So, if you current drawing buffer contains a full yellow picture and the value is 0.5 every pixelcolor [1.0, 1.0, 0.0] is multiplied with 0.5 and [0.5, 0.5, 0.0] is written to the accumulator buffer.

As I told before, you can also add all pixels of the current drawing buffer to the accumulator. This can be done using the GL_ACCUM method. The usage of the value equals the GL_LOAD case. All pixel color values are multiplied by this value before and then added to the accumulator.

You can also perform scalar addition or multiplication operations on the accumulator using GL_ADD or GL_MULT wich will add or multiply all color values by the given value.

GL_RETURN allows returning the data from the accumulator to the current drawing buffer. One interesting fact is that switching between the current drawing buffer using glDrawBuffer allows you accumulating information from the current front and the current back buffer.

So, how did I archive the effect shown in the picture?

I will only show the interesting stuff in this listing, but I will add a link to the full code can be downloaded here:

void render() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// do some animation stuff and draw the cube

glAccum(GL_ACCUM, 0.03);
glAccum(GL_RETURN, 1.0);
glAccum(GL_LOAD, 0.97);

// swap buffer
}

Before I start drawing, I clear the color buffer and the depth buffer. I will never clear the accumulator buffer at all as I want to use it for my motion blur. Now I render my scene which has just been removed as it is not interesting at this point.

After rendering my scene and before swapping my buffers I just add the current picture within my drawing buffer (which is my back buffer) to my accumulator after multiplying all color values with 0.03. This is done with

glAccum(GL_ACCUM, 0.03);

.

Afterwards I overwrite my drawing buffer with the current content of my accumulator buffer to draw the content of my accumulator the the screen. This is done by calling

glAccum(GL_RETURN, 1.0);

.

Before I swap my buffers I write my current picture back to my accumulator. For performance reasons I do not use

glClear(GL_ACCUM_BUFFER_BIT)

but overwrite my buffer directly using

glAccum(GL_LOAD, 0.97)

with 97% of all color values of the current drawing buffers.

Afterwards all buffers are ready to be swapped and the "cube" can be shown on the display. There is just one more thing to care about: You should carefully choose the value for the operations as all color values have to be less then 1.0. Otherwise you will archive undefined effects. As 0.97 + 0.03 = 1.0 my values will never rise over 1.0.

Now, just have some fun with it :)