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:
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
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.