Motion Blur

Motion Blur

Rate This
  • Comments 12

An interesting challenge in game programming is how to make things seem fast. I've spent a great deal of my career working on this particular problem, and the solutions are relevant for more than just racing games. It is all too common to get a character moving around, get the controls feeling good, and then think "hmm, this feels kinda, well, sluggish..."

In reality, our sensation of speed comes from many things. We feel the wind on our face. We feel the vibration of the ground rushing past beneath us. We see the parallax as the world hurtles by, and those little balancing tubes in our ears pick up even the slightest change in our inertia. In a game, all that is missing. We aren't truly moving, and our brain knows it. The motion sensors in our heads are not easy to fool!

Sometimes people try to fix a feeling of sluggishness by simply making their game move faster. That may work, but as often as not you will end up with a game that is technically faster, and therefore more twitchy and harder to play, but which still feels sluggish because the speed indicators our brains rely on are still missing.

By far the most important visual indicator is motion blur. Our eyes are built to recognize motion, not still images. We exploit their tendency to detect motion by displaying a series of still images in rapid succession, relying on our eyes to interpret this as a continuous motion. If you think about it this is really kind of a bogus thing to do, though. In reality we would see a continually moving object, not a series of still frames.

Many people don't realize that movies and TV handle animation in a fundamentally different way to games. Even though both are displayed on the same physical output device, the way they encode their frames of animation is radically different.

When a game renders a frame of graphics output, it takes a snapshot of the position of each object at one exact moment in time. When a camera records a frame of a movie, on the other hand, the shutter opens up for a period of time, letting light fall onto the film for the duration of the exposure. If objects are moving, their positions are averaged over the course of the frame. This creates a smooth, natural motion blur, with a sensation of speed and fluid movement that is usually lacking from computer graphics.

Let's look at a practical example. Consider my cat, moving to the right. Frame #1:

Frame #2:

Frame #3:

A game would render exactly those three images, and display them in sequence. If I did this quickly enough the cat would appear to be moving, but if my framerate was poor you would see this as a series of three independent images.

A movie, on the other hand, would record just a single image containing a blurred average of all the positions the cat has passed through:

This difference is the main reason why movies look good displayed at only 24 frames per second, while games require 60 to achieve a similar visual quality.

So how can we get motion blur into our games?

There are various rendering tricks that can be used to approximate a motion blur effect for specific objects, but ideally we would like a more general purpose solution.

Probably the best way is to run at a ridiculously high framerate (say 500 or 1000 fps), drawing each frame to a separate rendertarget, and then average all the resulting images to produce a smooth blur. That can look great, but isn't practical for most games (although if you are doing a simple 2D sprite game on Xbox, you might actually have enough rendering power to afford something like this).

A more practical approach is to cheat. Don't bother rendering any extra frames: just store the ones you have already drawn, and blend some amount of the previous frames in with the current one. If you look at a screenshot, the result is pretty silly:

But in motion this technique can look great. You really need to be running at 60 frames per second for this to work, though: the stepping looks stupidly obvious at lower framerates.

Here's how to implement this cheap fake motion blur with the XNA Framework:

  • Choose a backbuffer format that does not contain an alpha channel, such as SurfaceFormat.Bgr32 (there are ways to make this technique work even with alpha in your backbuffer, but that will complicate things)
  • In LoadGraphicsContent, create a feedback texture the same size and format as your backbuffer, using ResourceUsage.ResolveTarget and ResourceManagementMode.Manual
  • Each frame:
    • Render your main scene as usual
    • Use a fullscreen sprite to draw your feedback texture over the top of the backbuffer
      • Pass "new Color(255, 255, 255, blurAmount)" as the SpriteBatch color parameter: zero alpha will give no motion blur, 200 a lot, and it will get ridiculous if you go above around 240
    • Call ResolveBackBuffer to update your feedback texture with this latest image
      • If you are on Xbox, this will have the side effect of clearing your backbuffer, so you must use another fullscreen sprite (this time fully opaque) to draw the contents of the feedback texture back over the backbuffer
    • Now draw any things that you don't want to be motion blurred, such as UI overlays
    • Done!

This technique was one of the main sources of the speed sensation in MotoGP. I linked it to the camera velocity, so the blur would only kick in when you were tearing down a long straight in top gear.

For a really trippy effect, try doing a slight scale or rotation as part of the first fullscreen draw call.

  • Excellent tips for implementing such effects. I've seen motion blur done in pixel shaders before, but do they base the code on this same theory?

  • "A more practical approach is to cheat. Don't bother rendering any extra frames: just store the ones you have already drawn, and blend some amount of the previous frames in with the current one ..."

    For my never-finished-Warm-up entry I used that trick -sort of since it was even a cheaper one, not for the whole scene objects, but only for the main ball and you know what? it looked good! (with a nice trail like a comet).

    The difference is the technique you have explained is that you just need one feedback texture ... with the one I used I needed to hold the last 4 positions of the ball and re-render alphablended based on those positions. Since I only wanted the motion feeling for the ball I forgave myself for using this dirty cheap little trick ... behave!

  • I done it, similar way.

    1. Standard start - render scene to backbuffer.

    2. Mix current scene with downsampled last frame(if it's first frame, do not mix) on RT.

    3. Downsample scene(new RT)... and keep it for next frame.

    4. result of point 2, to backbuffer.

    It was fairly easy, so I started to play with mix formula. Normally, you will have something like that in PS:

    finalColor = currentColor * (1 - blurPower) + lastColor * blurPower;

    blurPower keeps in between 0 and 1. So it controls how much of last frame will be seen on current frame.

    It works great... but we can do a bit more with that. By using some simple pow() we can get another halo effect. Hmm... What do I mean? Depending on intensity of currentColor apply more blur... lighter the color = more motion blur. We can do that, like that:

    blurPower = currentColor;

    finalColor = currentColor * (1 - blurPower) + lastColor * blurPower;

    It's simple... and not enough effective... we will get, middle blur, with middle intensity.

    We are looking for mid intensity = low blur relationship. Square give us just that. To make it more tweakable use pow() function.

    So we got:

    blurPower =

    pow(currentcolor, blurColorDynamicsMultiplier);

    finalColor = currentColor * (1 - blurPower) + lastColor * blurPower;

    so...

    "multiplier = 1" - linear curve

    "multiplier > 1" - "low start, high end" curve

    "multiplier < 1" - "high start, low end" curve

    Shawn, you already wrote very good articles about curves. :)

    All right... let's just sum my words with last formula.

    You / We want to keep low motion blur till some high intensity (we want to have low blur on all, and high blur on highlights). We will use threshold (break point, or whatever)to separate interesting dynamics range... and hmm, enough:

    threshold; // less than 1

    blurPower;

    blurColorDynamicsMultiplier;

    morePower = 0;

    if(currentColor > threshold)

    {

     colorInGivenRange =            //color value

       (currentColor - threshold) / //relational  

       (1 - threshold);             //to our

                                    //upper range

     morePower =

     pow(colorInGivenRange,           blurColorDynamicsMultiplier);

    }

    blurPower =

    pow(currentcolor, blurColorDynamicsMultiplier) + morePower;

    finalColor = currentColor * (1 - blurPower) + lastColor * blurPower;

    I am sorry Shawn for such a ..yhym.. tutorial in comments (just a moment of concentration on subject). If you feel it's somewhat improper just delete it. :)

  • Interesting.

  • And, with small bugs in last example. Hmm, maybe I will rewrite it heavily, and send it to ziggyware for contest. maybe... ^^

  • Only four posts in the whole of August! I do apologize. I have clearly been slacking :-) Continuing on

  • Cops And Robbers: An XNA framework game demo

  • Ok, I'm done talking about speed effects. Before I go, here are a couple of external links on the subject.

  • I've done something similar in my game prior to reading this entry but I was wondering what would happen if these things moved too fast on the screen. Let's say for example frame 1 its on the far left side of the screen and frame 2 its on the far right side of the screen. Would this method still produce nice results?

  • Thanks, Shawn! With a few modification, this effect works great with XNA 3.1.

  • Has anyone found an XNA 4.0 compatible sample of this technique?

  • Hi shawn could you tell us how to implement this in speed effect using xna 4.0 please thanks.

Page 1 of 1 (12 items)
Leave a Comment
  • Please add 1 and 5 and type the answer here:
  • Post