Mipmapping
The curse of texture magnification is blurring. There are not enough texels when the texture is blown up on a small display, so the texturing hardware interpolates new ones that smooth out the color transitions. Sometimes we have the opposite situation: the texture has a lot of texels that we are trying to fit on a very small display. This is minification.
Minification has a curse of its own. When there are more texels than fragments to display them, some texels may be squeezed out, and features of the texture will not be rendered. Such undersampling can be seen in this rendering of a checkerboard texture:
At the far center of the checkerboard, you can see what looks like a stretched row of checks. That row is actually several rows. They appear as one row because the complementary rows between them have been skipped over. Rotate the floor and you will find other distracting patterns on the horizon.
When a high frequency pattern is inadvertently reproduced at a lower frequency, we have aliasing. Changing the minification filter to linear doesn't fix aliasing artifacts. There are simply not enough fragments sampling the texture for it to be faithfully reproduced on the horizon of this checkerboard.
A graphics developer named Lance Williams proposed a fix for texture aliasing in 1983. He suggested providing a pyramid of different resolutions of a texture. Level 0 of the pyramid is the original texture. Level 1 is a version with half the dimensions. Level 2 is a version with a quarter of the dimensions. And so on. At the top of the pyramid is a 1×1 version of the texture. Generating the pyramid is easier if level 0 has dimensions that are powers of 2. Powers of 2 split in half cleanly.
The checkerboard has these four levels leading to the top of its pyramid:




The images are scaled up so that you can see them. All levels are a clean checkerboard pattern save for the very top 1x1 image, which blends the white and black into a single gray pixel.
The pyramid of images is called a mipmap. Mip- stands for multum in parvo, which is Latin for much in little. The word little refers to the fact that the extra resolutions increase the overall size of the texture by only a third.
We can generate and upload the other levels of a texture ourselves with texImage
, or we can let WebGL do it for us by calling generateMipmap
on the currently bound texture:
gl.generateMipmap(gl.TEXTURE_2D);
gl.generateMipmap(gl.TEXTURE_2D);
When a texel and pixel are about the same size, level 0 is used on a texel lookup. As the texels get smaller than the pixel, the lower-resolution levels are used. Try switching the mipmap filter in the renderer below. Which combination of minification filter and mipmap filter look most pleasing?
Setting the mipmap filter to nearest makes the texture lookup pull from the mipmap level closest to the pixel size. Linear makes the texture lookup blend the colors from two surrounding mipmap levels.
As we build the mipmap pyramid, the texels from the bigger level are blended together to form the smaller level. The blending is what makes the horizon gray. Mipmapping effectively prefilters the texture so that its details are smoothed out rather than lost altogether.
Adding mipmapping to a renderer requires just two steps. The first step we have already seen: we must upload the mipmap levels. The second step is to use a minification filter that makes the texturing hardware pull colors from the smaller resolution levels. With two kinds of interpolation between texels and three mipmap settings, a total of six different minification filters are available:
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
The controls in the render above let you examine each of these six possible minification filters.