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.