All guides

Anti-Aliased SDF Outlines with fwidth

A distance field measures geometry units while a screen displays pixels. Scaling changes how many pixels represent one distance unit, so a fixed smoothstep width varies in apparent thickness. fwidth estimates the change across nearby fragments, allowing a transition of roughly one pixel.

Fix the problem and environment

A distance field measures geometry units while a screen displays pixels. Scaling changes how many pixels represent one distance unit, so a fixed smoothstep width varies in apparent thickness. fwidth estimates the change across nearby fragments, allowing a transition of roughly one pixel.

The controlling code

float d=length(p)-radius;
float pixel=max(fwidth(d),0.00001);
float fill=1.0-smoothstep(-pixel,pixel,d);
float outline=1.0-smoothstep(pixel,2.0*pixel,abs(d));

Verify in order

Move radius in the outline example and compare fixed-threshold and derivative halves. Pause, multiply transition width by 0.5 and 2, and inspect pixel coverage.

Scope and common mistakes

Derivatives are fragment-stage operations. WebGL 1 needs OES_standard_derivatives. Compute them before non-uniform branches rather than inside divergent control flow.

Continue experimenting

Reference

Official documentation

Run the related examples