Mipmaps - WebGL Textures: Introduction to Mipmaps, Sub Images & Atlases (2015)

WebGL Textures: Introduction to Mipmaps, Sub Images & Atlases (2015)

Mipmaps

Mipmapped Bricks

This project demonstrates how to generate a series of mipmaps. We discuss the purpose of mipmaps. We explain the difference between various mipmap settings. We cover the WebGL settings LINEAR_MIPMAP_LINEAR,NEAREST_MIPMAP_NEAREST, NEAREST_MIPMAP_LINEAR, and LINEAR_MIPMAP_NEAREST.

The Mipmap project displays a texture representing bricks. The texture covers a total of ten square meshes in two columns of five meshes each column. The columns recede into the distance. A drop down menu at the top of the page displays WebGL minification settings, for mipmaps and non mipmap rendering. Select various settings from the menu to see the difference between settings. The difference appears most obvious on those meshes farthest from the viewport.

For example select LINEAR_MIPMAP_LINEAR, and study the brick texture mapped to the most distant meshes. Then select NEAREST_MIPMAP_NEAREST. The bricks on square meshes in the distance appear smoother with LINEAR_MIPMAP_LINEAR. The bricks on square meshes in the distance appear pixelated with NEAREST_MIPMAP_NEAREST.

What's a Mipmap?

Mipmaps represent a series of textures generated from a base texture. Some developers refer to a series of mipmap textures as a mip chain. Textures in the series represent mip levels, in decreasing dimensions. Mip levels correspond to the renderable area for a texture. As the size of the renderable area decreases, smaller textures from the mip chain display. Developers often interchange the terms mip level and level of detail (LOD), when referring to textures. The closest levels display the greatest detail. More distant levels display less detail.

Some minification filters use the mip chain when available. Minification filters determine how to select pixels from a texture when the render area's resolution is smaller than the texture's resolution. In other words minification filters instruct WebGL how to display the texture at a reduced size. Mipmap minification filters use a mip chain to determine how to display the texture.

With mipmaps the processor prepares a set of textures at a reduced size in advance. When the renderable surface area requires reduction in texture size, the processor selects from the set of prepared textures. Mipmaps can decrease processing required to display textures. The renderer doesn't need to reduce the size of a texture during rendering. The renderer processes color fragments based on the mip level and minification setting. Most hardware runs faster with a prepared mip chain. Without a mip chain the GPU processes more data in order to reduce the number of output colors from a larger texture.

Mipmapping decreases issues with minification. Without mipmapping under some scenarios, the processor might sample from too large of a texture. Processing the sample introduces artifacts. Artifacts refer to unwanted visible side effects from a rendering operation.

Mipmap Settings

Mipmap settings apply to minification filters not magnification filters. Magnification filters always select the largest available texture in a mip chain. Select minification filters from a set of WebGL constants. Minification constants which include the term MIPMAP, use mipmaps when available. For example LINEAR_MIPMAP_NEAREST is a minification filter for mipmaps. However with mipmapped minification filter settings we also need a mip chain. Later we'll demonstrate how to generate a mip chain with WebGL.

The drop down menu for this project includes WebGL minification options. The options for mipmaps correspond to the WebGL constants LINEAR_MIPMAP_LINEAR, NEAREST_MIPMAP_NEAREST, NEAREST_MIPMAP_LINEAR, andLINEAR_MIPMAP_NEAREST. The options for non mipmapped minification filters include LINEAR and NEAREST.

Each setting uses a different algorithm to display minified textures. The following list explains each minification option.

1. NEAREST: Take one color sample closest to the current texel.

2. LINEAR: Interpolate four color samples taken around the current texel.

3. NEAREST_MIPMAP_NEAREST: Take one sample closest to the current texel and closest to the current mip level.

4. NEAREST_MIPMAP_LINEAR: Take one sample from the two closest mip levels. Interpolate the two samples.

5. LINEAR_MIPMAP_NEAREST: Interpolate four color samples around the current texel, taken from the closest mip level.

6. LINEAR_MIPMAP_LINEAR: Interpolate four samples from the two closest mip levels.

The preceding list emphasizes the number of samples taken to produce a color. Algorithms produce color for fragments based on samples. Samples are color values taken from the currently active texture. Interpolation means blending the values taken. The more samples used to blend, the more processing resources required. Increase in processing, decreases rendering speed. In other words, apps may run slower when the filter requires more samples.

In general linear algorithms require more processing resources. Linear algorithms sample the texture from four locations. Additionally linear mipmap settings sample from two mip levels. Nearest algorithms require less processing resources. Nearest algorithms take one sample from the nearest texel, or nearest mip level.

How to Generate Mipmaps

WebGL mipmap textures must have dimensions in powers of two. In other words both width and height must equal some number d where 2n= d. However width and height can have different dimensions. For example acceptable dimensions include one image with width of 256 and height of 512. Both dimensions represent powers of two because 28 = 256 and 29 = 512.

To generate a mip chain from a texture call the WebGL API method generateMipmap() The next few sections cover the project's JavaScript in detail. We'll demonstrate how to change minification filter options then generate mipmaps.

Initialize the Mipmap Project

In a nutshell generating mipmaps is as easy as assigning a MIPMAP minification filter with the WebGL API method texParameteri(). Then call the WebGL API method generateMipmap(), to create a mip chain. The Mipmapsproject demonstrates how to create a mip chain and assign a minification filter. The next few sections cover the Mipmaps project in detail.

The JavaScript file GLMipMap.js defines the class GlMipMap which generates and displays mipmaps in response to selections from the drop down menu. The GLMipmap.js file initializes a set of indices identical to every project except the Two Meshes project. The mipmap textures are mapped to simple square plane meshes. Create an array of interleaved vertices and texels. The texels cover the square mesh from edge to edge. Vertices in the mesh range from -0.5 to +0.5. We reduced the size of the mesh in order to display ten meshes at once in the screen without scaling. The following listing includes the array of vertices and texels used with the mipmap project.

var aVertices = new Float32Array(

[

// left top

// X,Y,Z:

-0.5, 0.5, 0.0,

// S,T:

0.0,1.0,

// right top

// X,Y,Z:

0.5, 0.5, 0.0,

// S,T:

1.0, 1.0,

// right bottom

// X,Y,Z;

0.5, -0.5, 0.0,

// S,T:

1.0, 0.0,

// left bottom

// X,Y,Z:

-0.5, -0.5, 0.0,

// S,T:

0.0, 0.0,

]

);

Listing 26: Mipmaps Vertex Texel Array

Method getEntity() generates an array of ten GLEntity where the matrix for each entity includes a different translation. The render() method uses each matrix to display meshes in separate locations.

Method getEntity() modifies the matrix for each entity. One column of entities display to the left and another column to the right. The matrix for each entity receives a different set of X, Y, and Z coordinates. All ten entities share one texture and vertex buffer object. Method getEntities() fills and returns an array of GLEntity. The entire getEntities() method follows.

getEntities: function(sPath){

// Matrix index values

// translate

// along the X, Y, or Z

// axes respectively:

var nX = Number(12);

var nY = Number(13);

var nZ = Number(14);

var aEntity = new Array();

// X, Y, and Z

// translation

// per entity.

var fX = Number(0);

var fY = Number(0);

var fZ = Number(0);

// Y increments:

var aY = [6.8,3.2,1.0, 0.3,-0.3];

//Z increments:

var aZ = [-18,-10,-5,-3,-2];

// Increment j

// every other

// entity in

// the loop.

// Use j to

// assign identical

// Y and Z

// entries to

// each column.

var j = Number(0);

// Create ten

// entities

// with different

// matrices.

for (var i = 0; i < 10; i++){

var sP = sPath;

// Alternate columns.

// X translation

// either left or right.

if (i % 2 == 0){

fX = Number(0.6);

fY = aY[j];

fZ = aZ[j];

j++;

}

else {

fX = Number(-0.6);

}

// Only the first

// entity includes

// an active

// texture.

if (i > 0){

sP = null;

}

e = new GLEntity(sP,i);

// Assign X, Y, and Z

// translation.

// Location along

// the axes.

e.matrix[nX] = fX;

e.matrix[nY] = fY;

e.matrix[nZ] = fZ;

aEntity.push(e);

}

// Return the

// array of

// entity.

return aEntity;

},

Listing 27: Generate Array of GLEntity to Mipmap

Generate a Mip Chain

The Mipmap project includes an init() method which generates a mip chain. The controller calls init() after buffers and textures initialize. Method init() creates a mip chain with the WebGL method generateMipmap(). We only need to generate a mip chain once. However, we have to wait until the texture initializes to create the chain. The only parameter to init() is a reference to the controller GLControl class. The following listing includes the entire init() method.

init: function(controller){

var gl = controller.gl;

gl.generateMipmap(gl.TEXTURE_2D);

},

Listing 28: Create Mip Chain

WebGL API generateMipmap()

The WebGL API method generateMipmap() prepares a mip chain from the currently active texture. generateMipmap() generates and uploads a set of textures. The chain begins with the currently active texture. The active texture becomes the largest texture in the mip chain. The chain ends with a 1 x 1 dimensional texture. The only parameter is the texture target. This book's examples use 2 dimensional textures. Use the WebGL constant TEXTURE_2D. The only other option is a TEXTURE_CUBE_MAP. This book doesn't cover TEXTURE_CUBE_MAP mipmaps.

gl.generateMipmap

(

gl.TEXTURE_2D

);

Listing 29: WebGL API generateMipmap()

Mipmap Menu Selection

The following listing includes the Web page's declaration for the drop down menu. Add a change event listener to the following drop down menu. The event listener changes minification settings based on the menu selection.

<select class="menu" id="mSelect" >

<option>

gl.LINEAR_MIPMAP_LINEAR

</option>

<option>

gl.NEAREST_MIPMAP_NEAREST

</option>>

<option>

gl.NEAREST_MIPMAP_LINEAR

</option>

<option>

gl.LINEAR_MIPMAP_NEAREST

</option>

<option selected>

gl.NEAREST

</option>

<option>

gl.LINEAR

</option>

</select>

Listing 30: Minification Options Menu

The method addListener() adds a change event to the select menu from the Web page. The only parameter to addListener() is a reference to the current controller. First addListener() obtains a reference to the select element from the Web page by id. Then addListener() assigns selectFilter() as the change event listener. addListener() creates a property named controller on the menu. The following line assigns a reference to the controller, to the menu's new controller property.

menu.controller = controller.

When the click event triggers, the event object's currentTarget.controller property contains a reference to the controller. We need the controller to assign minification filters. See the addListener() method.

Change Minification Settings

The following diagram illustrates the calling sequence after the user selects a new menu item. The rectangle with light blue background represents a WebGL API method call to change the minification filter. For those with black and white displays, the WebGL API method has a gray background. selectFilter() retrieves the minification filter selected by the user from the menu, then calls method setMinification(). After setMinification() changes the minification setting, selectFilter() calls the controller's animOne() method to show one frame of the animation. The frame displays the new minification setting. See the selectFilter() source code.

Activity Diagram Select Mipmap Options

Diagram 10: Select and Show New Minification Filter

The parameters to setMinification() include a WebGLContext and a WebGL constant representing one of the minification settings. Method setMinification() calls the WebGL method texParameteri() to change the minification filter.

WebGL API texParameteri() Minification Filter

Parameters to texParameteri() tell WebGL how to render the currently active texture. Assign a minification filter to a two dimensional texture, with this call to texParameteri().

The first parameter represents the texture's target. WebGL includes two constants for texture targets, either TEXTURE_2D or TEXTURE_CUBE_MAP. We only cover two dimensional textures with this book. Look online or read our bookWebGL Skybox for details regarding TEXTURE_CUBE_MAP. For two dimensional minification filters pass TEXTURE_2D as the first parameter.

Parameters for texParameteri() include many options. This time we want to assign minification filters. Therefore pass the WebGL constant TEXTURE_MIN_FILTER as the second parameter.

When the second parameter equals TEXTURE_MIN_FILTER then the last parameter must equal a WebGL minification constant. The book's project passes a minification setting retrieved from the drop down menu of the Web page. All the drop down menu options correspond to WebGL minification constants.

gl.texParameteri

(

gl.TEXTURE_2D,

gl.TEXTURE_MIN_FILTER,

minFilter

);

Listing 31: WebGL API texParameteri() Minification Filter

See the setMinification() method.

Mipmap Summary

This project demonstrated how to generate a series of mipmaps. We discussed the purpose of mipmaps. We explained how minification settings affect display of mipmaps. We covered the WebGL minification settings LINEAR,NEAREST, LINEAR_MIPMAP_LINEAR, NEAREST_MIPMAP_NEAREST, NEAREST_MIPMAP_LINEAR, and LINEAR_MIPMAP_NEAREST.

We explained the JavaScript and WebGL source code for the Mipmaps project. The Mipmaps project includes a drop down menu with available WebGL minification settings. Select various settings from the menu to see the difference. The difference between minification selections appears most obvious on those meshes farthest from the viewport, especially when applied to mipmaps.

See the GLMipMap.js source code.