Lab notes · Experiment 5
What is an SDF?
SDF = Signed Distance Field (or Function). For every pixel, the shape answers one question with one number:
- negative → inside
- zero → on the edge
- positive → outside
- how big → how far from the edge
That’s the whole idea. Drawing (step, smoothstep, mix into colour) is a separate step — the SDF itself is just the number.
A circle SDF is basically: distance from the centre, minus the radius. That subtract is what makes it signed.
Iteration 1 — signed field as a blend
Fed the signed distance straight into mix() as the blend amount. Still looks like a radial gradient — radius just shifts how strong the blend feels. Learned that having an SDF ≠ automatically having a filled shape.
Iteration 2 — disc + breathing glow
Threshold around zero (with smoothstep) turns the field into a disc. Animating the radius pulses size; animating the smoothstep edge width pulses glow while the disc stays put.
Also: 2 * uTime errors in GLSL — need to use a float instead of an int, e.g. 2.0. Softstep bands far from zero hide a “fake radius” inside the threshold numbers, which made the “does negative radius vanish?” thing confusing until we sorted that out.
Iteration 3 — box SDF + inner layer
A box is not length(abs(uv)) — that is still a circle. Recipe:
abs(uv)folds all quadrants together- subtract half-size
vec2(halfWidth, halfHeight)→ distance to each pair of edges max(x, y)combines them into one signed field
Centred UV only spans about ±0.5 on Y (and ± half-aspect on X after uv.x *= width/height). So 1.0 is not “full canvas” — use 0.5 * uResolution.x / uResolution.y to know where the left/right edges actually sit.
Painted a second, smaller box on top with a third colour. Gotcha: smoothstep on an SDF is 0 inside / 1 outside — as a layer mask that paints the background. Flip with 1.0 - smoothstep(...) so the inner fill lands inside the rect.
Stumbled into a nice edge by adding step into the mix amount (pushes past 1.0 → extrapolation), same family as Soft Halo’s hot rings.
Iteration 4 — mix distances to morph
This was the goal: mix(distCircle, distBox, morphAmount) blends two signed distances, so the silhouette melts circle ↔ square. Same mix as colour work — A and B are just shapes now.
Gotchas along the way:
- After aspect correction, a square needs equal half-sizes (
vec2(0.2, 0.2)). Scaling x byhalfScreenWidthmakes a rectangle again. - Half-screen width (
0.5 * width/height) is for canvas edges, not for sizing squares. Half-screen height is simply0.5with this UV setup (y isn’t stretched).
Final look kept the three-colour idea from iter 3: lilac→gold wash from the circle field as the base, then the morphed field as a cyan layer with soft glow + step hot rim (1.0 - smoothstep(...) + step(...)).