Command Palette

Search for a command to run...

Hectal
Course outline
Topic 6.3Intermediate ~20 min · step 3 of 7

Filtering and Mipmaps

In one line

A screen pixel rarely covers exactly one texel. Filtering decides how texels are blended when the picture is magnified or shrunk. Mipmaps and anisotropy keep a far floor from shimmering or turning to mush.

0/7 · 0%

Think of it like this

Reading a poster from across a room. Close up you can read every letter. From far away, many letters fall inside one spot of your eye and blur together into grey. A smart printer could make a small copy for far viewing, so each spot of the eye gets one clean grey, and not a random letter that flickers when you move your head.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

magnification
One texel covers more than one pixel: the picture is close and enlarged.
minification
More than one texel falls inside one pixel: the picture is far and shrunk.
mipmap
One of a chain of smaller, pre-averaged copies of a texture, each half the size in width and height.
shimmer
Flicker of far detail when the camera moves, because each pixel reads a different single texel every frame.
anisotropic filtering
Taking several samples along the stretched direction of a surface seen at a low angle, so it stays sharp.

Step by step

01See the shimmer cause

In the first example the left strip has no mipmaps. Far away, each pixel reads one texel of a fine checker: the result is a noisy pattern, which flickers as the camera moves.

02Use the default

The middle strip uses the default mipmaps. The noise is gone, replaced by an even grey: each pixel now reads the average of many squares. That is correct, but blurry far away.

03Add anisotropy

The right strip adds anisotropy = 16. The checker stays visible further down the strip before it turns grey, because the GPU samples along the long side.

04Watch the levels

The second example paints each mip level a colour. The floor shows bands (seen in a screenshot): orange close by (level 0), then yellow, green, teal, blue, violet, and white at the horizon (level 6, 1 × 1).

Try it yourself

  1. 1

    Blend the levels

    In the second example change LinearMipmapNearestFilter to LinearMipmapLinearFilter. The hard bands melt into a smooth rainbow: trilinear filtering blends the two nearest levels.

  2. 2

    Turn anisotropy off

    In the first example set t.anisotropy = 16 to 1. The right strip now looks like the middle one: a grey blur where it was crisp. Which value is best is a trade of sharpness for texture reads.

Code & diagrams

Try it: interactive

UV viewer: filtering

Pick the plane and set Repeat 4. Switch on NearestFilter for blocky pixels, then switch mipmaps off and on and watch the memory line (a third more with mipmaps).

Shimmer, mipmaps and anisotropy New tab

Left: no mipmaps. Middle: the default. Right: anisotropy 16. The numbers 1006 and 1008 are the constants LinearFilter and LinearMipmapLinearFilter. A still picture cannot show flicker: look at the left strip while the page scrolls or run it in a window you resize.

idle

Console

Run the scene to see its console.

Expected console output

no mipmaps (Linear)        | minFilter: 1006 | generateMipmaps: false | anisotropy: 1
mipmaps (the default)      | minFilter: 1008 | generateMipmaps: true | anisotropy: 1
mipmaps + anisotropy 16    | minFilter: 1008 | generateMipmaps: true | anisotropy: 16
Seeing the mip levels New tab

A custom chain, one colour per level: a DataTexture with mipmaps set by hand. LinearMipmapNearestFilter picks one level per pixel, so the bands have hard edges. This is the same chain three.js builds for you, with the averaged picture instead of a colour.

idle

Console

Run the scene to see its console.

Expected console output

levels: 64x64, 32x32, 16x16, 8x8, 4x4, 2x2, 1x1

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Switch off mipmaps on a far floor

In the first example set the middle strip's setup to (t) => { t.generateMipmaps = false; t.minFilter = THREE.LinearFilter; }, the same as the left.

terminal
$ Run
── what you'll see ──
mipmaps (the default) | minFilter: 1006 | generateMipmaps: false | anisotropy: 1
Both left strips show the noisy, flickering pattern in the distance, and the status bar's numbers do not change: shimmer is a quality problem, not a speed problem.

Myth vs fact

Myth

Mipmaps are only for speed.

Fact

Their main job is image quality: they stop far-away shimmer. They cost about a third more memory, and they make far texture reads cheaper because small levels fit the GPU's cache.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The GPU chooses the mip level from how fast the UVs change between neighbouring pixels (screen-space derivatives). This is why the level is per pixel, not per object, and why a custom shader that changes UVs wildly can pick the wrong level (Phase 12).

  • ▸

    Mipmaps are built by the GPU (generateMipmap) for images; a DataTexture or compressed texture (KTX2) can bring its own chain in texture.mipmaps, as the second example does. KTX2 files normally carry their mipmaps inside.

Remember this

  1. 1

    The problem this solves: a 1024-pixel floor viewed from far away has hundreds of texels under one screen pixel. If the GPU reads only one of them, the pixel shows a random texel, and when the camera moves it flickers: shimmer. If the floor is seen up close, one texel covers many pixels and looks blocky or blurry. Filtering settings choose how to cope.

  2. 2

    Magnification means one texel is bigger than a pixel (you are close). magFilter is LinearFilter (the default: blend the four nearest texels, smooth) or NearestFilter (take one texel: hard squares, the look of pixel art). Minification means many texels fit in a pixel (you are far). minFilter is where the real choices live.

  3. 3

    Mipmaps are pre-shrunk copies. For a 1024 × 1024 picture, three.js builds 512, 256, 128... down to 1 × 1: 11 levels (floor(log2(1024)) + 1). Each level is a quarter of the one before, so the whole chain costs about one third more memory (Topic 6.6). The GPU picks the level whose texels are about pixel size, so far surfaces read from a small, pre-averaged picture. generateMipmaps (default true) builds them when the texture is uploaded.

  4. 4

    The six filters. The default LinearMipmapLinearFilter (trilinear) blends two neighbouring levels and four texels in each: smooth. LinearMipmapNearestFilter picks the nearest level, so you can see a hard line where the level changes. NearestMipmapNearestFilter and NearestMipmapLinearFilter do the same with one texel per level (blocky). LinearFilter and NearestFilter ignore mipmaps: cheap, but far surfaces shimmer. The second example paints each level a colour so you can see the GPU choosing.

  5. 5

    Anisotropy fixes the grazing angle. A floor seen at a low angle is squeezed: each pixel covers a long thin patch of texels. Plain mipmaps pick a level for the longer side, and everything blurs. texture.anisotropy = 16 lets the GPU take several samples along the long side: sharp far floors for more texture reads. The number is a request; the GPU's limit is renderer.capabilities.getMaxAnisotropy() (often 16, and some devices allow less). three.js clamps it for you.

  6. 6

    Non-power-of-two sizes work. A 300 × 200 picture gets mipmaps and RepeatWrapping in WebGL 2, which r186 requires. Old advice to resize to 256 or 512 is out of date for WebGL 2 (and wastes memory when it enlarges a picture).

Explain it without notes

01

Why does a far floor flicker when the camera moves, and what is the fix?

02

What does anisotropic filtering add that mipmaps do not?

Practice

01

A road texture looks blurry in the distance but sharp near the camera. Which one setting do you change, and what does it cost?

02

How many mip levels does a 2048 × 2048 texture have?

Done when you can

  • Say when a texture is magnified and when it is minified

  • Explain what a mip chain is and what it costs

  • Pick between Nearest, Linear and the mipmap filters for a floor and for pixel art

  • Say what anisotropy fixes