Motion Blur is a quite excellent effect, but very hard to make. In order to obtain such an effect, the OpengGL developers recommend the use of the accumulation buffer. Basically, the accumulation buffer redraws the object n times using different alpha values. I have nothing against this method but when the scene is full of "hard-to-render" objects, it leads to a low FPS rate. In full scene motion blur, in order to obtain the effect, the scene must be drawn more times. The big problem comes from the accumulation buffer, it is not always supported on all the graphical cards. So how can this problem be passed?
A very good method that I will explain in the following lines is to render our scene into a texture. Why should this be useful? Easy, by rendering the object into a texture, we can easily access the precedent frame, and by accessing it, we can render it with a lower alpha value. Doing this in a recurrent mode, we can obtain the desired effect.
The only thing needed is a texture used for storing the precedent scene. The algorithm is simple now:
- draw the old scene (stored into the texture, which is a simple textured polygon) with a lower alpha (<1).
- draw the current scene.
- read into the texture the whole screen.
With this implementation, the effect is visible only outside the object, the object looks the same in the rest. But we all know that with motion blur, the objects appear blurry not just a simple trace surrounding the object. So how can we do this? Simple: first draw the scene then render the old scene. Doing this, the object appears blurry.
This method is not the best and not the worse, is just a method and I hope it will help many others because it helped me.
Using the code
The small demo shows how the effect works on a single object and on a whole scene. The single object is a textured cube and the whole scene is a vortex effect.
For each basic utility, there exists a distinct module. The core (main) module contains all the definitions that may be necessary in other modules. On the next level there are three modules:
glBasic (handles initializations and other GL things),
glDraw (handles all the GL drawing) and
keyboard (handles a keyboard management routine).
glDraw has relations with
motionblur (stores the procedure needed for rendering the motion blur - this is why all the application is built) and
tunnel (holds the vertex creation and handling).
glBasic has calls into texture module (texture handling). (Note - a module is physically represented by a C file, the code does not use OOP.)
The texture used for the motion blur is defined in the core (main) module and is exported in all the other modules. But the processing is made in the
motionblur module. There are three procedures:
int CreateMotionBlurTexture(int quality, int interpolation); - creates the motion blur texture and is recommended to be called into the
void RenderToMotionBlurTexture(bool FirstRenderTexture, int SceneFunc()); - "renders" the
SceneFunc() onto the motion blur texture together with the previous frame. The boolean flag specifies if the previous frame is rendered first or not (see the background point).
void ShowMotionBlurTexture(); - is like a flush procedure, it displays onto the screen the final result.
In order to make the effect more real, the blending is made with the following parameters:
GL_ONE_MINUS_SRC_ALPHA. Because the application uses alpha blending, the intensity of the effect can easily be changed by changing the previous frame alpha value.
In the demo application, the following keys are usable:
- 's' - for changing the rendered scene.
- 't' - for changing the
FirstRenderTexture flag that is passed to the
- 'w' - for wireframe rendering.
- 'm' - for the use of motion blur or not.
- press 'a' and then '+' or '-' to adjust the alpha intensity.
Note that the demo runs with GLUT.
Points of Interest
This method is very useful especially when doing full scene motion blur. If this method is used just for a single object then it is recommended to use masking.