GLSL built-in function
fwidth()
Returns how much a value changes between neighboring pixels. Using it as the smoothstep width gives edges exactly one pixel soft at any zoom level.
Syntax
float fwidth(float p)
vec2 fwidth(vec2 p)
vec3 fwidth(vec3 p)Parameters
- p
- The value to measure, such as a distance or coordinate.
Return value
abs(dFdx(p)) + abs(dFdy(p)): the change of p across one pixel.
Live example
Edit the code and the preview updates as you type.
How it works
The GPU shades pixels in small 2 x 2 blocks, so it can compare a value with its neighbors. fwidth(p) returns how much p changes from one pixel to the next.
That is exactly the width you want for anti-aliasing. If d is a distance, then smoothstep(0.0, fwidth(d), d) blends across about one pixel, regardless of how much the shape is scaled, zoomed or how large the canvas is.
In the example the grid zooms in and out. On the left the line width is a fixed 0.05 grid units, so lines become thick and blurry when zoomed in and thin and broken when zoomed out. On the right the width comes from fwidth, and lines stay one crisp pixel wide.
Typical uses
- Anti-aliased shapes and lines that look sharp at any size.
- Grids and wireframes with constant pixel width.
- Choosing detail levels: a large
fwidthmeans the pattern is too fine to see and can be faded out.
Common mistakes
- Missing the extension in WebGL 1. Put
#extension GL_OES_standard_derivatives : enableon the first line, beforeprecision. (WebGL 2 shaders do not need it.) - Calling it inside an
ifthat differs between neighboring pixels. Derivatives are only reliable when all four pixels of a 2 x 2 block take the same branch; computefwidthbefore branching.