Module 04

Shapes with signed distance fields

What "signed" actually buys you

d(x) > 0, outside d(x) < 0 the shape
One dimension, for clarity: negative inside the shape, positive outside, exactly zero right at the edge. In 2D it's the same idea with a plane instead of a line.

A signed distance function takes a point and returns one number: how far that point is from the shape's edge. Negative means inside, positive means outside, exactly zero means you're standing right on the boundary. That sign is the whole point — it turns "is this pixel inside the shape" from a pile of special-case comparisons into one number you can threshold, blend, or combine with other SDFs.

A circle's SDF is almost embarrassingly simple: length(p) - radius. A box takes a bit more (credit to Inigo Quilez, who's done more to popularize practical 2D/3D SDFs than anyone): length(max(abs(p) - halfSize, 0.0)) + min(max(d.x, d.y), 0.0) — don't worry about deriving it, just recognize the shape: distance outside the box, plus a correction so points inside still come out negative.

Anti-aliasing against pixel width, not a magic number

Module 01 used a hard step() edge, which is aliased — jagged, "stairstepped" pixels along the boundary. The fix isn't picking a fixed blur amount; it's smoothstep-ing across exactly one pixel's width, whatever that happens to be at the current zoom and resolution. GLSL ES 3.0 gives you fwidth(d) for free — it estimates how fast d changes from one pixel to its neighbor, which is exactly the blur width you want:

float aa = fwidth(d); float shape = 1.0 - smoothstep(-aa, aa, d);

Zoom in, zoom out, resize the canvas — the edge stays exactly one pixel soft, never more, never less.

Transform the space, not the shape

This is the idea that trips up almost everyone the first time, so it gets its own callout: to rotate, mirror, or repeat a shape, you don't touch the SDF function at all — you transform p before handing it to the SDF. p = abs(p) mirrors across both axes through the origin. p = mod(p, cellSize) - cellSize * 0.5 repeats the same shape into an infinite grid of cells, for free, because every cell now sees a copy of the same local coordinate. You're never drawing more than one shape — you're changing what "here" means before you ask "am I inside it."

Predict the output

At a point sitting exactly on a shape's edge, what does its signed distance value equal?