Matrix Lab

In which you will add to your growing library of code an abstraction for 4x4 transformation matrices.

Vector4 and Matrix

Your first challenge is to create Vector4 and Matrix4 classes that you will use to perform transformations. Follow these steps to get them working:

Vector4

In the project, run npm install.
Define in vector.js a class named Vector4.
Define a constructor for Vector4 that zeroes out the vector.
Define Vector4.get, which accepts an index as a parameter and returns the component of the vector specified by the index.
Define Vector4.set, which accepts an index and a value as parameters. It sets the component specified by the index to the value.
Ensure that Vector4 passes the provided unit tests by running npm run test-vector.

Matrix4

Define in matrix.js a class named Matrix4.
Define a constructor for Matrix4 that allocates the matrix's elements as a Float32Array with 16 slots. The Float32Array class is part of JavaScript's standard library and handles any conversion required to go from JavaScript's floating-point type (which is a double) to a 4-byte floating point value that the GPU expects. See MDN to learn its interface.
Note that your Float32Array is a flat 16-element array, but you want to think of it as a 4x4 two-dimensional array. By the conventions of WebGL, the first four elements are the first column of the matrix. The next four are the second column. This ordering is called column major. Add a comment to show a 4x4 column major "map" of the matrix. You should be able to look at the map and figure out at which index of the array you can find an element at a given row and column.
Define Matrix4.get, which accepts a row and a column as parameters and returns the component of the matrix specified by the row and column.
Define Matrix4.set, which accepts a row, a column, and a value as parameters. It sets the component specified by the row and column to the value.
Define Matrix4.toBuffer to return the Float32Array. The ShaderProgram class calls this method when you set a matrix uniform.
Define Matrix4.identity, which is static. It returns the identity matrix. Multiplying a vector or matrix by the identity matrix is akin to multiplying a scalar number by 1. The identity matrix is essentially a scale matrix in which the scale factors are all 1.
Define Matrix4.scale, which is static. It accepts three parameters for the x-, y-, and z-factors. It returns a matrix that scales by the given factors.
Define Matrix4.translate, which is static. It accepts three parameters for the x-, y-, and z-offsets. It returns a matrix that translates by the given offsets.
Define Matrix4.rotateX, which is static. It accepts a number of degrees. It returns a matrix that rotates around the x-axis by the given number of degrees.
Define Matrix4.rotateY, which is static. It accepts a number of degrees. It returns a matrix that rotates around the y-axis by the given number of degrees.
Define Matrix4.rotateZ, which is static. It accepts a number of degrees. It returns a matrix that rotates around the z-axis by the given number of degrees.
Define Matrix4.multiplyVector. It accepts a Vector4 as a parameter. It returns the product of the matrix and vector as a new Vector4.
Define Matrix4.multiplyMatrix. It accepts a Matrix4 as a parameter. It returns the product of this matrix and the parameter matrix as a new Matrix4.
Ensure that all unit tests pass by running npm run test.
Show your passing tests to your instructor to receive credit.

Transforming Renderer

Your second challenge is to render a scene that renders two instances of an object: one untransformed and one transformed by your matrices. Follow these steps:

Start up a web server and verify that you can see the triangular donut at the center of the viewport.
Modify the vertex shader in main.js to accept a mat4 uniform. Transform the vertex position by this matrix.
Draw the donut once with this matrix set to the identity.
Draw the donut again with this matrix set to a composition of at least two transformations.
Show your functioning application to your instructor to receive credit.