Motion blur without subframes

Built on his solved disc case by Inigo Quilez. Sources for this reference

Motion blur is normally bought by rendering the frame several times inside the shutter interval and averaging. For a shape translating in a straight line you do not have to. The coverage integral has a closed form, and it is a quadratic.

Left: crisp, no shutter. Right: exact analytic coverage. Both are one evaluation per pixel.

Why it is a quadratic

Work in the shape's own frame. Over the shutter interval the query point traces a straight ray, so the question "how long was this pixel inside the disc" becomes "for what range of t is |p - v t| < r". Expand that and it is an ordinary quadratic in t. Clamp the two roots to the shutter and the difference between them is the coverage.

float a = dot(v,v), b = dot(p,v), c = dot(p,p) - r*r;
float disc = b*b - a*c;
if (disc <= 0.0) return 0.0;          // the ray never entered the disc
float s = sqrt(disc);
return clamp((b+s)/a, 0,1) - clamp((b-s)/a, 0,1);

That is the whole thing. No loop, no accumulation buffer, no velocity texture, and it is exact rather than converging.

Shutter angle becomes a real dial

Because the travel term is just velocity times open-time, shutter angle drops out as a parameter you can author instead of a property of how many subframes you rendered. The film default is 180 degrees, which means the shutter is open for half the frame.

The same motion at 0, 90, 180 and 360 degree shutter.

The trap, and it is worth knowing before you ship

Blur spreads a fixed amount of light over more pixels, so a small bright object gets dimmer as it gets faster. A thin bright element smeared far enough can drop below whatever threshold your bloom uses and simply stop glowing, which reads as the effect breaking rather than as motion. On fast beats, shutter angle is a look decision with a brightness consequence, not a realism setting you turn on and forget.

Rules of thumb

  1. Solve in the shape's frame. The query point traces a ray and the algebra collapses.
  2. Clamp both roots to the shutter interval before subtracting, or you get coverage above 1.
  3. Guard the stationary case. dot(v,v) near zero divides by nothing.
  4. Blend to the crisp version below about a pixel of travel, so slow motion does not go soft.
  5. Watch small bright elements. Coverage falls as speed rises, and thin things can blur themselves out of the bloom entirely.

All 61 notes How to use them Credits