Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commitdd348ac6c3

README.md

shutterBlur

The render passes behind the MotionBlur component and the motionBlur module.

Three compute passes after lighting.

mb_tilemax reduces the velocity buffer to one dominant velocity per 32x32 tile, already scaled by the shutter fraction and clamped to the longest blur allowed.

mb_neighbormax takes the dominant velocity across each tile's 3x3 neighbourhood. This is the pass that lets a moving object blur past its own silhouette: a static background pixel beside something fast has no velocity of its own, and a filter that reads only that pixel leaves it sharp, so the blur stops dead at the object's edge. Reading the neighbourhood tells the pixel which direction something nearby was travelling, so it can go looking for what swept over it. A diagonal neighbour counts only when it is travelling toward the tile — taking every diagonal is what puts a square halo around a fast object.

mb_gather reconstructs. Each tap carries a weight built from three separable cases (McGuire et al., A Reconstruction Filter for Plausible Motion Blur): the tap is in front of this pixel and its own blur is long enough to reach here; the tap is behind and this pixel's blur moved off it, revealing it; or both sit at a similar depth and are blurred together. Keeping the three apart is what leaves a motion boundary readable — one blended weight averages a sharp background into a moving foreground and the edge dissolves into mush.

Taps alternate between walking the neighbourhood's dominant velocity and this pixel's own. Both directions are needed: the first finds what swept over the pixel from elsewhere, the second finds the pixel's own smear. A pixel that moved less than a pixel has no direction of its own worth walking and uses the neighbourhood's for every tap. Tap positions are jittered per pixel by interleaved gradient noise so they land as noise rather than as banded copies of the moving object.

The centre pixel is weighted by how little it moved, so a nearly-static pixel keeps most of itself and a fast one is mostly made of its neighbours. A flat centre weight would outvote every tap and the blur would never appear.

The blur can never be longer than a tile: the neighbourhood search reaches one tile in each direction, so a velocity longer than that would have contributors the search never visits. That is the ceiling behind maxRadius.

Depth is linearised through the drawn camera's own inverse view-projection, so the passes are correct in offscreen captures and RTT cameras at their own resolutions. The tile targets are screen-sized at one texel per tile, so the grid follows a window resize instead of pinning to whatever the window was when the feature started.

Parameters arrive through the motion_blur_params buffer, packed by the motionBlur module.