SDF Flow
SDF to flowmap via Jump Flooding
Quick Start
Loading...
Source
Loading...
Documentation
sdf-flow
Converts a binary shape (black/white image) into a flowmap texture using signed distance fields and the Jump Flooding Algorithm. The output encodes flow direction and strength — sample it from a particle system or shader to make things flow around shapes.
Quick Start
import { createSdfFlow } from './gpu-modules/sdf-flow/sdf-flow';
const flow = createSdfFlow(device);
const flowmap = device.createTexture({
size: [512, 512],
format: 'rgba8unorm',
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
});
// Source must be a GPUTexture with TEXTURE_BINDING usage
flow.render(shapeTexture, flowmap, {
bevelWidth: 16,
threshold: 128
});
// flowmap now contains the result — bind it in your pipeline
flow.destroy();
Output Format
The output is an rgba8unorm texture:
- R — Flow direction X (0.5 = no flow, 0 = left, 1 = right)
- G — Flow direction Y (0.5 = no flow, 0 = up, 1 = down)
- B — 0.5 (neutral)
- A — Flow strength (0 = no flow, 1 = max flow)
Values are premultiplied by alpha, so transparent areas are (0, 0, 0, 0).
API
createSdfFlow(device)
Returns { render, destroy }. No options — dimensions are derived from the source texture. The renderer auto-resizes internal JFA buffers if the source texture dimensions change.
render(source, target, params?)
source—GPUTexturecontaining the shape (must haveTEXTURE_BINDINGusage)target—GPUTextureto write the flowmap into (must haveSTORAGE_BINDINGusage, formatrgba8unorm)params.bevelWidth— Pixel radius of the flow falloff zone. Default16.params.threshold— Brightness threshold (0–255) to binarize the input. Default128.params.smoothing— Central-difference step radius. Higher = smoother gradients. Default1.params.invert— Swap inside/outside. Defaultfalse.
How It Works
- Threshold — Binarize the input texture into inside/outside regions, seeding two JFA textures.
- Jump Flooding — Run JFA separately for inside and outside seeds. Each pixel finds its nearest boundary pixel in O(log N) passes.
- SDF + Gradient — Compute the signed distance (outside distance minus inside distance), apply smoothstep bevel, then derive flow direction via central differences.
How to Modify
- Change the output format: Edit the
storageTextureformat in the bind group layout and thetexture_storage_2ddeclaration inflowmap.wgsl. - Adjust the bevel curve: The
height_atfunction inflowmap.wgsluses a smoothstep. Replace with a linear ramp or custom curve. - Use as a distance field only: Modify
flowmap.wgslto output the raw SDF value instead of the gradient. Storesdf_at(coords)directly. - Multiple shapes: Render multiple shapes into the source texture before passing it to
render.
Further Reading
Rationale
Flowmaps tell particles, fluids, or UV animations which direction to move. Generating them from a shape is a common need: water flowing around rocks, wind deflected by buildings, UI particles avoiding text. The standard approach is to compute a signed distance field and take its gradient — but doing this on the GPU at interactive rates requires a parallel distance transform algorithm.
This module implements the full pipeline: threshold → JFA (parallel distance transform) → SDF → gradient → flow encoding. The output is a standard flowmap texture you can sample from any shader.
Original Research
Rong & Tan (2006) — Jump Flooding in GPU with Applications to Voronoi Diagram and Distance Transform — The original JFA paper. Describes the O(log N) parallel algorithm for computing nearest-seed maps on the GPU. https://dl.acm.org/doi/10.1145/1124772.1124848
Felzenszwalb & Huttenlocher (2012) — Distance Transforms of Sampled Functions — The CPU reference algorithm (separable 1D passes). Useful for understanding the problem JFA solves in parallel. https://cs.brown.edu/people/pfelzens/dt/
Existing Implementations
- Shadertoy: Jump Flooding Algorithm — Interactive JFA implementations for reference. https://www.shadertoy.com/results?query=jump+flood
Further Learning
Inigo Quilez: 2D Distance Functions — Comprehensive reference for SDF primitives and operations. Useful if you want to generate SDFs analytically instead of from a bitmap. https://iquilezles.org/articles/distfunctions2d/
Ben Golus: The SDF of a Box — Deep dive into SDF math and edge cases, relevant to understanding the distance field this module produces. https://bgolus.medium.com/the-sdf-of-a-box-c083e1e1c568