6.6 - A Matrix Code Library - Learn_webgl_matrix

Fundamental to all 3D computer graphics is the 4x4 matrix transform. In the original OpenGL API, all basic transformations were implemented for you in the library’s code. All you had to do was call the correct function in the correct order. WebGL was implemented for low power mobile devices with limited CPU and GPU functionality. Transformation matrix functionality was not included in the WebGL API. Therefore, you have to implement your own matrix operations in JavaScript. But it doesn’t make sense for individual programmers to “re-invent the wheel”. This lesson presents you with a JavaScript matrix library and explains how to use it.

WebGL Transformation Matrices

A WebGL, 4x4, transformation matrix is a 1D array of type Float32Array which contains 16 floating point values. The values represent a 2D array and are stored in column-major order. (Back in the 1960’s, Fortran stored 2-dimensional data in column-major order. That convention has propagated to various system still in use today, including OpenGL. Most modern programming languages use row-major order.)

The 4x4 transformation matrix:

0
4
8
12
1
5
9
13
2
6
10
14
3
7
11
15
Eq1

would be created in JavaScript code like this:

var matrix = new Float32Array([0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15]);
// Or
var m = new Float32Array(16);
m[0] =  0;  m[4] =  1;  m[ 8] =  2;  m[12] = 3;
m[1] =  4;  m[5] =  5;  m[ 9] =  6;  m[13] = 7;
m[2] =  8;  m[6] =  9;  m[10] = 10;  m[14] = 11;
m[3] = 12;  m[7] = 13;  m[11] = 14;  m[15] = 15;

In most cases the 2nd example above is used because it is easier to debug the code if you can visualize the data values as a 2D array.

Note: If you re-format the matrix library code you will lose the “multiple statements per line” formatting which helps to visualize the 4x4 matrices. It is recommended that you do not re-format this code file.

Design Decisions for a Matrix Library

A typical class definition defines a set of data and a set of functions that act on that data. One of the important ideas behind classes is the encapsulation and protection of a set of data values inside an instance of the class. We don’t really need data protection for our matrix library. What we need is encapsulation of the functionality of matrix operations so that we can minimize the creation and deletion of scratch arrays that are needed for matrix processing. Consider that an animation requires the rendering of a scene at least 30 times per second. If you are constantly creating new object instances every time you render, you will be creating a lot of objects. JavaScript does dynamic memory garbage collection, so many programmers simply ignore memory issues. But if you can minimize the creation of new objects for each rendering, your animations have the potential to run more smoothly.

The Learn_webgl_matrix Class

A class called Learn_webgl_matrix is defined in a file named Learn_webgl_matrix.js. It encapsulates the matrix functionality we need to produce WebGL renderings. A Learn_webgl_matrix object does not store a matrix. It encapsulates matrix functionality and the scratch arrays needed for that functionality. And, by separating matrix functionality from matrix data, the syntax of the code is simplified.

You will create one instance of the library and use it for your entire program. The library contains functions that:

  • create transforms,
  • set the values of a specific type of transform, and
  • perform matrix operations.

A transform is stored as a Float32Array. Four functions in an Learn_webgl_matrix object create and return new transforms and their names all start with create. These functions should not be called in your rendering code for every animation frame. They should be called once in your setup code to create any transforms you need during rendering. The four functions that create a new matrix transform are:

  • create(), which creates and returns a new 4x4 transformation matrix.
  • createOrthographic(), which creates a new orthographic projection transformation matrix.
  • createPerspective(), which creates a new perspective projection transformation matrix.
  • createFrustum(), which creates a new perspective projection transformation matrix.

Functions that set the values of a transformation matrix must send a transformation matrix as the first parameter. For example:

  • scale(M, sx, sy, sz) sets M to a scale transform.
  • translate(M, tx, ty, tz) sets M to a translation transform.
  • rotate(M, angle, x_axis, y_axis, z_axis) sets M to a rotation transform.

Functions that perform matrix calculations change the value of their first parameter, while leaving all of the other parameters unchanged. The parameters are ordered similar to assignment statements which always change their left-hand side variable, but leave all value on the right-hand-side of an assignment statement unchanged. For example:

  • multiply(R, A, B) sets R to the product of A times B. (R = A*B)

The function multiplySeries() will multiply any number of matrices together to produce a single transformation matrix. It uses variable arguments and will accept as many arguments as you send it. For example, m.multiplySeries(R,A,B,C,D,E) will calculate the matrix product of A*B*C*D*E and store the result in R. In equation format, it performs R = A*B*C*D*E;. The order of the multiplications is critical. If the transform R is applied to a set of vertices, the effect of R would be that

  1. transform E was applied to a vertex,
  2. then transform D was applied to the transformed vertex,
  3. then transform C was applied to the transformed vertex,
  4. then transform B was applied to the transformed vertex, and
  5. finally transform A was applied to the transformed vertex.

When you create a single transform from multiple transforms, you must always order the transformations from right to left.

The Learn_webgl_matrix Code

The demo below displays the Learn_webgl_matrix class. Review the code to get familiar with its matrix functionality. The implementation details of many of the functions will be discussed in future lessons. The code below is not editable. You might want to modify the code later, but for right now you just need to learn how to use the code.

Show: Code Canvas Run Info
./simple_transform_example/simple_transform_example.html

Demonstration of a JavaScript class to render a scene.

Please use a browser that supports "canvas"
Animate
Shader errors, Shader warnings, Javascript info
Open this webgl program in a new tab or window

HTML Code To Use Learn_webgl_matrix

The Learn_webgl_matrix class uses code from two other classes:

  • learn_webgl_point4.js, which defines a class for (x,y,z,w) points.
  • learn_webgl_vector3.js, which defines a class for <dx,dy,dz> vectors.

These files must be loaded into your browser along with the matrix library. To use the matrix library include <script> directives in your HTML file that look something like this:

<script src="../../lib/learn_webgl_point4.js"></script>
<script src="../../lib/learn_webgl_vector3.js"></script>
<script src="../../lib/learn_webgl_matrix.js"></script>

Change the file paths based on the relative location of your JavaScript code files to your HTML file. If the HTML and JavaScript files are in the same folder on the server, you can omit a file path.

Glossary

code library
a set of common functionality gathered into a single place. It is standard practice to put the functionality into a single class, or a group of classes.
column-major order
values in a 2-dimensional array are store in a 1D array and organized by columns. (All computer memory is 1-dimensional; multi-dimensional arrays are always stored in computer memory as 1D arrays in some agreed upon order.)
Next Section - 6.7 - Using Learn_webgl_matrix - A Robot Arm Base