Friday, December 6, 2013

Motion Blur In Unity Part 1: Overview

Welcome to my series on implementing motion blur in Unity. This is something I managed to create after days of trial and error, and I must say it's an incredibly nifty effect.
Before we get into the code, I'll start by talking about what I mean when I talk about motion blur, and how it works.

Motion Blur? Doesn't Unity Have That?

The answer is yes. Kind of. Not really.
Unity has a few motion blur effects. There's your traditional accumulation motion blur (which, despite the name, doesn't really look like motion blur - in the end, it ends up looking very dream-like), and a variety of so-called "camera motion blur" effects (none of which I could get working correctly) which try to simulate motion blur of the camera moving.
What it doesn't have is a special kind of motion blur employed in games you've likely poured hours into and not even noticed. I'm not sure what the technical term is (UDN refers to it as "per-object motion blur"), so I'll be referring to it as Screen Space Velocity Blur from this point on. This is not the technical term, but it makes for an easy term to remember (SSVB).
SSVB is used in a lot of games. Unreal Engine 3 features this technique, and therefore is used in nearly every Unreal game on the market. CryEngine also features this technique.
SSVB does two things: it produces realistic motion blur when the camera moves, and also features plausible per-object motion blur.

So How Does It Work?

SSVB works by rendering a velocity buffer. This velocity buffer contains screen-space velocity, rendered per pixel. In order to produce this velocity, the velocity buffer shader needs access to the model view of the current frame, and of the last frame. It then projects each vertex using both matrices, finds the displacement, and uses this as the velocity. The velocity is generally encoded in a floating-point buffer in the Red and Green channels (X and Y velocity).
Finally, the motion blur shader samples the velocity per-pixel. It uses this to step along a line, sampling pixels along the velocity vector. The final pixel output is the average of each sampled pixel.
There are a number of changes which can be made here, and which I implemented for performance. In Unreal, they render velocity to a half-resolution image, perform motion blur in half-resolution, and then blend the motion blurred image per-pixel with the full resolution image based on velocity magnitude (so areas which are motion blurred use the half-resolution image, while areas which are not blurred use the full resolution image)

It's a lot of work to set up in Unity, but it's definitely possible.
In the next post, we'll be deconstructing the many quirks of the model*view matrix in Unity, and creating a helper script to feed the current and last model*view matrices to our shader.

No comments:

Post a Comment