Posterize & dither
Cut an image down to a few colors, and pattern the pixels so the steps between them still read as tones.
Cards
One live example to tweak, learn and copy.
How it works
Posterizing rounds every color to the nearest of a few levels. With four levels per channel a photograph turns into
flat patches, like a screen print or a poster, hence the name. Rounding alone makes hard stripes wherever a gradient
crosses from one level to the next: the same bandingBanding is the stripes a smooth gradient breaks into when stored with too few levels. Dithering adds tiny per-pixel noise before rounding, so the stripes become fine grain. Banding & dithering Banding is the stripes a smooth gradient breaks into when stored with too few levels. Dithering adds tiny per-pixel noise before rounding, so the stripes become fine grain.
Dithering turns those stripes back into tones. Before rounding, add a small offset that changes from pixel to pixel.
Where a color lies 30% of the way from one level to the next, about 30% of the pixels now round up, and from a normal
viewing distance the eye averages them back into the in-between tone. The offset can come from a
hashA function that scrambles its input into a value that looks random but is always the same for the same input. Shaders use it for per-pixel and per-cell randomness. Hash A function that scrambles its input into a value that looks random but is always the same for the same input. Shaders use it for per-pixel and per-cell randomness. Bayer matrix A small square of thresholds, tiled across the screen, ordered so that for any brightness the pixels that pass are spread as evenly as possible. It drives ordered dithering.h = fract(sin(dot(p, k)) × big) of the pixel position, which looks like grain, or from a small repeating
Bayer matrixA small square of thresholds, tiled across the screen, ordered so that for any brightness the pixels that pass are spread as evenly as possible. It drives ordered dithering.threshold = (M[y % 4][x % 4] + 0.5) / 16
Pushed to the limit, two colors and nothing else, the result is the 1-bit look: every pixel is ink or paper, and all the shading lives in the pattern. The Rendering page on banding uses the same trick invisibly, one 8-bit step at a time; here it is the style.
Further reading
- Relative luminance (opens in a new tab)Reference
- Blend modes (opens in a new tab)Reference
- Alpha compositing (opens in a new tab)Reference
- fract (opens in a new tab)Reference
- mod (opens in a new tab)Reference
- Patterns (opens in a new tab)Book
- Random (opens in a new tab)Book
- Hash Functions for GPU Rendering (opens in a new tab)Paper
- Colour banding (opens in a new tab)Reference
- Ordered dithering (opens in a new tab)Reference
- Framebuffers (opens in a new tab)Article
- Bloom (opens in a new tab)Article
- Custom post-processing (opens in a new tab)Docs
- Dither (opens in a new tab)Reference
- gl_FragCoord (opens in a new tab)Reference