WebGL Essentials

DOMMatrix API

Uniform storage qualifiers can be set not only for scalars but also for vectors and matrices. Desktop applications generally make use of an auxiliary math library to create matrix entries and load them into uniform variables declared in the vertex shader. The same functionality for Web applications is provided by the DOMMatrix API. DOM matrix functions are not restricted to WebGL only: they are helpful for both 2D and 3D contexts of the canvas element. Besides, the API is a convenient instrument for specifying CSS and SVG transforms in JavaScript.

In the previous article our demo code created an effect of infinite rotation of the triangle about the y axis. All matrix entries were defined in the vertex shader. Now we'll build the same scene, but this time two matrices will be defined with the help of the DOMMatrix interface.

The new approach requires modification of the vertex shader. It is a "lean" shader now: it only contains the GLSL code for the projection matrix. As for the model and view matrices, they are declared as uniform variables:

<script id="vertex-shader" type="x-shader/x-vertex">
 attribute vec3 position;
 attribute vec3 color;
 varying highp vec3 colour;

 mat4 projectionMatrix;
 uniform mat4 viewMatrix;
 uniform mat4 modelMatrix;

 // function declaration
 mat4 computeProjectionMatrix();

 void main() {
  projectionMatrix = computeProjectionMatrix();
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
  colour = color;
 }

 . . . function definition for computing projection matrix . . .

</script>

Two new global variables are declared in JavaScript: this is a DOMMatrix object and an angle of rotation.

var angle = 0.0;
var matrix = new DOMMatrix();

The prepareScene() code is modified, too. It calls two more functions among other preliminaries:

function prepareScene() {
 . . .
 computeViewMatrix();
 computeModelMatrix();
 renderScene();
}

We remember that the viewing transformation in our example must push the triangle three units down the z axis. The translate() method of the DOMMatrix post-multiplies the translation transformation on the current matrix and returns the view matrix. This is an immutable method: the global matrix variable will not change.

function computeViewMatrix() {
 var viewMatrix = matrix.translate(0.0, 0.0, -3.0);
 var elements = viewMatrix.toFloat32Array();
 gl.uniformMatrix4fv(gl.getUniformLocation(program, 'viewMatrix'), false, elements);
}

The uniformMatrix4fv() loads 4 sets of floating-point values into the uniform viewMatrix. The method is called just once: the view matrix remains the same for each animation frame.

The modeling transformation is based on the immutable rotateAxisAngle() function. The angle of rotation is expressed in degrees:

function computeModelMatrix() {
 var modelMatrix = matrix.rotateAxisAngle(0.0, 1.0, 0.0, angle);
 var elements = modelMatrix.toFloat32Array();
 gl.uniformMatrix4fv(gl.getUniformLocation(program, 'modelMatrix'), false, elements);
}

The renderScene() function updates the angle value with every single frame:

function renderScene() {
 gl.clear(gl.COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);
 gl.drawArrays(gl.TRIANGLES, 0, 3);
 angle = angle + 1.0;
 if (angle > 360.0) {
  angle = angle - 360.0;
 }
 computeModelMatrix();
 handle = requestAnimationFrame(renderScene);
}

rotation about the y axis: animation frames