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

### Texture Atlas: Two Meshes

The third texture atlas project demonstrates how to display *multiple meshes* mapped with different images. The images use one texture atlas. The meshes share one vertex buffer object. Efficiently display unique meshes and textures while ** sharing one** buffer and texture. Interleave vertices and texels within one vertex buffer object. While rendering the scene, call the WebGL API method

**drawElements()**for each mesh, with different parameters. This technique provides the appearance of multiple entities with different meshes and maps.

The JavaScript file GLTwoMesh.js defines the **GLTwoMesh** class with supporting methods and instance variables. This project displays a square and a triangle. The square requires four vertices with texels. The triangle requires only three vertices with texels. Tap the Play button to run the animation. The square rotates around the Y axis. The triangle rotates around the X axis. The **render()** method uploads a matrix with Y rotation values for the square, and a matrix with X rotation values for the triangle. The graphic for the texture atlas follows.

Diagram 5: Texture Atlas for Two Meshes

Texels for Two Meshes

The following graphic demonstrates the texels prepared to display both meshes. S and T values for texels appear within square brackets. Arrows point to dots representing texel locations. The black outline demonstrates which portions of the atlas render to the display screen. We don't need to render the white area on both sides of the triangle. Neither do we need to draw more than three vertices for the triangle. We only need three texels and three vertices for the triangle mesh.

Diagram 6: Texels for Two Meshes

Vertices for Two Meshes

The following graphic demonstrates preparing vertices to display both meshes. We manually scaled each mesh down by 50%. The X and Y coordinates for ** each mesh** range between

**-0.5**and

**+0.5**. The meshes would naturally overlap. However the constructor moves the matrix for the square mesh left and the triangle mesh right.

**X**marks the center of each mesh at the origin

**(0,0,0)**. Rotation matrices simply rotate around the origin. The gray vertex coordinates define the triangle. The black vertex coordinates define the square.

Diagram 7: Vertices for Two Meshes

Vertex Texel Array for Two Meshes

Place values from the two previous graphics, in an array of alternating vertices and texels. The following JavaScript array includes four vertices and texels to display a square. After the square, three vertices and texels describe the shape of a triangle. The comments associate indices with each vertex texel set. We need seven indices for the element array.

**var aVertices = new Float32Array(**

**[**

**//index 0**

**-0.5, 0.5, 0.0,**

**0.0, 1.0,**

**//index 1**

**0.5, 0.5, 0.0,**

**0.5, 1.0,**

**//index 2**

**0.5, -0.5, 0.0,**

**0.5, 0.0,**

**//index 3**

**-0.5, -0.5, 0.0,**

**0.0, 0.0,**

**// index 4**

**0.0, 0.5, 0.0,**

**0.75, 1.0,**

**//index 5**

**0.5, -0.5, 0.0,**

**1.0, 0.0,**

**//index 6**

**-0.5, -0.5, 0.0,**

**0.5, 0.0,**

**]**

**);**

Listing 15: Array for Two Meshes

Element Array for Two Meshes

We'll need an index element array with enough entries for both meshes. The following listing demonstrates an array of indices for this project. Notice the first six entries in the element array point to the first four entries from the preceding vertex texel array. The last three entries in the element array point to the last three entries from the vertex texel array. When rendering we'll need to remember six elements provide the shape of the square, and three elements provide the shape of the triangle. Additionally we'll calculate the offset for drawing the triangle, based on the elements which draw the square. In other words, determine the distance from the start of the element array to the start of indices which form the triangle's mesh.

**var aIndices = new Uint16Array([**

**// The square**

**// plane's**

**// vertices**

**// and textures.**

** 3,2,0,**

** 0,2,1, **

**// The triangle's**

**// vertices**

**// and textures.**

** 6,5,4**

**]);**

Listing 16: Texture Atlas: Two Meshes Index Element Array

Move Individual Meshes

The supporting file GLEntity.js declares functionality to display one entity. Some entities include separate textures. Each entity includes a 4 x 4 matrix representing transformation. Change values in the matrix to move or rotate a mesh. This section describes how to initialize each matrix in order to move the mesh, when rendering.

The twelfth, thirteenth, and fourteenth elements in a 4 x 4 matrix provide translation. Modify values at those index locations, to move a mesh with the matrix. Change the twelfth element to move vertices along the X axis, left or right. Change the thirteenth element to move vertices along the Y axis, up or down. Change the fourteenth element to move vertices along the Z axis, away from or toward the view port. The following diagram represents a 4 x 4 matrix. The entries marked **Tx, Ty**, and **Tz** indicate translation along the X, Y, or Z axis.

Diagram 8: Matrix Translation

The **GLTwoMesh** constructor instantiates two **GLEntity**, adds them to an array, then passes the array to the **GLControl** constructor.

The **GLEntity** constructor includes two parameters. The first parameter is a **String** representing the path to an image file for use as a texture. The **String** may point to an image file or equal **null**. The second parameter represents the texture unit associated with the entity. However if no image data is available, then the previous entity's texture remains the active texture unit. We only need one **GLEntity** with texture data, to render a mesh. We can use the **matrix**property from other **GLEntity** in the list.

In this case one **GLEntity** maintains an active texture and a matrix with rotation around the Y axis. A second **GLEntity** maintains a matrix with rotation around the X axis.

Use the **matrix** to move each mesh along both the X and Y axes, during rendering. The following listing creates a new **GLEntity** then adds the entity to an array. The parameter **s** represents a path to the image file provided by the **GLTwoMesh** constructor. The parameter **0** becomes the **idx** property of the first entity. The entity's **matrix** receives values to move a mesh ** left** and up.

**// Array to store**

**// GLEntity.**

**var aIm = new Array();**

**// New GLEntity**

**// 's' is an**

**// image file path.**

**// '0' is the**

**// texture unit**

**// for this entity.**

**var n = new GLEntity(s,0);**

**// Assign matrix values**

**// to move the entity**

**// to the left.**

**n.matrix[12] = -0.45;**

**// Assign matrix values**

**// to move the entity**

**// up one unit.**

**n.matrix[13] = 1;**

**// Add the entity**

**// to the array.**

**aIm.push(n);**

Listing 17: First Entity of Two Meshes

The following listing creates a new **GLEntity**. The parameter **null** indicates this entity doesn't maintain a texture from an image file. Modify entries in the entity's **matrix** to move a mesh ** right** and up.

**// New GLEntity**

**// 'null' indicates**

**// this entity**

**// doesn't maintain**

**// a texture.**

**var n = new GLEntity(null,1);**

**// Assign matrix values**

**// to move the entity**

**// to the right.**

**n.matrix[12] = 0.6;**

**// Assign matrix values**

**// to move the entity**

**// up one unit.**

**n.matrix[13] = 1;**

**// Add the entity**

**// to the array.**

**aIm.push(n);**

Listing 18: Second Entity of Two Meshes

The Texture Atlas: Two Meshes project has completed initialization. See the *GLTwoMesh constructor*. We can now render the meshes.

Draw Two Meshes

Class **GLTwoMesh** includes a **render()** method to display both meshes. The **render()** method follows the same sequence for each entity. First obtain a reference to the entity's matrix. Second provide rotation values for the matrix. Third upload the rotated matrix to the vertex shader with the WebGL method **uniformMatrix4fv()**. Fourth draw the mesh with the WebGL method **drawElements()**.

Prepare the Square's Matrix

The following listing demonstrates providing rotation values for the square's matrix. The book WebGL Textures & Vertices: Beginner's Guide describes matrix rotation with the method **matrixRotationY()**. The controller's instance variable named **nRad** maintains rotation values in radians. The end of each animation frame increases the value for **nRad**.

**var matrix = controller.aEntities[0].matrix;**

**matrix = controller.matrixRotationY**

**(**

** matrix,**

** controller.nRad**

**);**

Listing 19: Rotate the Square's Matrix

Next upload the matrix to the vertex shader's uniform named **um4_matrix**. The controller's instance variable named **uMatrixTransform** contains the location of **um4_matrix**.

**gl.uniformMatrix4fv**

**(**

** controller.uMatrixTransform,**

** false,**

** newFloat32Array(matrix)**

**);**

Listing 20: Upload the Square's Matrix

Draw the Square

Draw the square with the WebGL method **drawElements()**. Method **drawElements()** signals WebGL to process attributes indirectly pointed to with the element array buffer. The first six entries in the index buffer for this project point to vertices and texels for the square. The controller uploads the index array as an element array buffer. Therefore draw just the first six entries assigned to the element array buffer. The ** second** parameter to

**drawElements()**tells WebGL

**many entries from the element array buffer to draw. Pass**

*how***6**to the second parameter.

WebGL method **drawElements()** last parameter is the ** offset from the start of the array**. In other words, define where in Bytes the indices for the square begin. The square begins at the first entry. Therefore pass

**0**as the last parameter. The following listing draws the square to the canvas.

**gl.drawElements**

**(**

** gl.TRIANGLES,**

** 6,**

** gl.UNSIGNED_SHORT,**

** 0**

**);**

Listing 21: Draw the Square

Prepare the Triangle's Matrix

The **render()** method rotates the first entity around the Y axis and the second entity around the X axis. Separate rotations highlight the activity of each mesh as a unique entity. We haven't covered X axis rotation yet.

Rotate Around the X Axis

The GLControl class includes a method named **matrixRotationX()**, which modifies values in a matrix to provide mesh rotation around the X axis. The following graphic illustrates rotating a square plane around the X axis.

Diagram 9: Rotate Around the X Axis

The following matrix rotation method demonstrates modifications to a 4 x 4 matrix, which provide rotation around the X axis. The parameter **m** is a JavaScript array of 16 entries. The array represents a 4 x 4 matrix. The parameter **x**is a number representing the amount of rotation to apply, in radians. Assign the cosine of the angle to the fifth and tenth entries of the array. Assign the negative of the sine of the angle to the sixth entry, and the sine of the angle to the ninth entry. Then return a matrix with the new values. The following method was modified from a function licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License.

**matrixRotationX: function (m,x){ **

** var c = Math.cos(x);**

** var s = Math.sin(x);**

** return [**

** m[0], m[1], m[2], m[3],**

** m[4], c, -s, m[7],**

** m[8], s, c, m[11],**

** m[12], m[13],m[14],m[15],**

** ];**

**}**

Listing 22: Method matrixRotationX()

The following listing demonstrates providing rotation values for the triangle's matrix. The controller's instance variable named **nRad** maintains rotation values in radians. At the end of each animation frame, method **render()**increases the value for **nRad**.

**var matrix = controller.aEntities[1].matrix;**

**matrix = controller.matrixRotationX**

**(**

** matrix,**

** controller.nRad**

**);**

Listing 23: Rotate the Triangle's Matrix

Next upload the matrix to the vertex shader's uniform named **um4_matrix**. The controller's instance variable named **uMatrixTransform** contains the location of **um4_matrix**.

**gl.uniformMatrix4fv**

**(**

** controller.uMatrixTransform,**

** false,**

** new Float32Array(matrix)**

**);**

Listing 24: Upload the Triangle's Matrix

Draw the Triangle

Draw the triangle with the WebGL method **drawElements()**. Method **drawElements()** signals WebGL to process attributes indirectly pointed to with the element array buffer. The last three entries in the index buffer for this project point to vertices and texels for the triangle. The controller uploads the index array as an element array buffer. Therefore draw just the last three entries assigned to the element array buffer. The ** second** parameter to

**drawElements()**tells WebGL

**many entries from the element array buffer to draw. Pass**

*how***3**to the second parameter.

WebGL method **drawElements()** last parameter is the ** offset from the start of the array**. In other words, define where in Bytes the indices for the triangle begin. The triangle begins at the seventh entry in the element array buffer. The element array buffer includes

**those which define the triangle. To find the offset location for the triangle indices, multiply the number of array entries**

*six entries before***the triangle entries, times the size in Bytes for each entry. Each entry in the element array buffer is of type**

*preceding***UNSIGNED_SHORT**. The number of Bytes per

**UNSIGNED_SHORT**equals

**2**. The last parameter equals

**12**because

**6**entries times

**2**Bytes per entry, equals

**12**.

**6 * 2 = 12**

The following listing demonstrates calling **drawElements()** to display the triangle.

**gl.drawElements**

**(**

** gl.TRIANGLES,**

** 3,**

** gl.UNSIGNED_SHORT,**

** 12**

**);**

Listing 25: Draw the Triangle

Now method **render()** has drawn the square and triangle separately. For each frame increment **nRad** to animate rotation for the meshes. The controller's **nRad** property contains the current rotation in radians. The controller's **N_RAD**property contains a number representing a constant amount of rotation per frame. Increment the controller's **nRad** property by **N_RAD** units. The following line increments rotation.

**controller.nRad += controller.N_RAD;**

See the *render()* method defined for the Texture Atlas: Two Meshes project.

Summary Texture Atlas: Two Meshes

The third texture atlas project demonstrated how to display *multiple meshes* mapped with different images. The images use one texture atlas. The meshes share one vertex buffer object. Efficiently display unique meshes and textures while ** sharing one** buffer and texture. Interleave vertices and texels within one vertex buffer object. While rendering the scene, call the WebGL API method

**drawElements()**for each mesh, with different parameters. This technique provides the appearance of multiple entities with different meshes and maps.

See the JavaScript file for the *Texture Atlas: Two Meshes* project.