Integrate the pattern over the pixel

Built on filtering procedural textures by Inigo Quilez. Sources for this reference

A pixel is not a point. It is an area, and the honest color for it is the average of the pattern across that area. Point sampling asks the pattern for one value and hopes. For anything periodic, you can just do the integral.

Left: point sampled. Right: box filtered. Same checker, same camera, moving so the aliasing has somewhere to crawl.

The left side is not merely noisy, it is wrong in a way that moves. As the checker's period falls below a pixel near the horizon, which value you get depends on exactly where the sample lands, so the pattern crawls and shimmers while the camera moves. The right side converges to a flat gray, which is the correct answer: when a pixel covers many cells, its average really is halfway between the two colors.

The trick is an antiderivative

A 1D square wave has a closed-form integral. The triangle wave is the antiderivative of the square wave, so the average of the pattern over any interval is one subtraction and one divide:

float tri(float x){ return abs(fract(x*0.5)*2.0 - 1.0); }

// average of the square wave across [p - w/2, p + w/2]
float boxWave(float p, float w){
    return (tri(p + 0.5*w) - tri(p - 0.5*w)) / w;
}

The 2D checker is the XOR of two of those, and XOR on values in 0 to 1 is written as a product so it stays continuous rather than snapping. That is the entire technique. Two fract calls per axis, no loop, no samples.

Where the footprint comes from

fwidth(g) is the pattern-space size of one pixel, and it is free: the GPU already computes derivatives across the quad it is shading. Point sampling has that number available and discards it. That is really all aliasing is here, throwing away the width you were handed.

It beats supersampling, and not by a little

Left: 16 samples per pixel. Middle: 64. Right: the analytic integral, at one sample.

Sixty-four samples per pixel still shimmers near the horizon, because the period keeps shrinking and no fixed sample count is ever enough. The analytic version costs one evaluation and is correct at every distance. Supersampling here is not a slower solution to the problem, it is a different and worse one.

Rules of thumb

  1. If the pattern is periodic and separable, it has a closed-form box integral. Use it.
  2. Get the footprint from fwidth, never a constant. A constant is wrong the moment anything moves.
  3. Guard the divide. As the footprint approaches zero the ratio is 0/0.
  4. If it converges to the right average at large footprints, it is correct. Check that first.
  5. Under domain repetition or a warp, the footprint has to be transformed too, or it is the wrong width.

All 61 notes How to use them Credits