Matrix Transformations in WebGL
In 3D graphics rendering, matrix transformations are used to convert vertices from one coordinate space to another. WebGL uses 4×4 matrices for various transformation operations.
Basic Transformation Matrices
1. Translation Matrix
Moves an object along the X, Y, and Z axes
shell| 1 0 0 tx | | 0 1 0 ty | | 0 0 1 tz | | 0 0 0 1 |
javascriptfunction createTranslationMatrix(tx, ty, tz) { return new Float32Array([ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1 ]); }
2. Scale Matrix
Scales an object along each axis
shell| sx 0 0 0 | | 0 sy 0 0 | | 0 0 sz 0 | | 0 0 0 1 |
3. Rotation Matrix
Rotation around X axis
shell| 1 0 0 0 | | 0 cosθ -sinθ 0 | | 0 sinθ cosθ 0 | | 0 0 0 1 |
Rotation around Y axis
shell| cosθ 0 sinθ 0 | | 0 1 0 0 | | -sinθ 0 cosθ 0 | | 0 0 0 1 |
Rotation around Z axis
shell| cosθ -sinθ 0 0 | | sinθ cosθ 0 0 | | 0 0 1 0 | | 0 0 0 1 |
MVP Matrix Explained
The MVP matrix is the product of three matrices used to transform vertices from model space to clip space:
MVP = P × V × M
M - Model Matrix
Purpose: Transforms vertices from model space (local space) to world space
javascript// Model matrix = Translation × Rotation × Scale const modelMatrix = mat4.create(); mat4.translate(modelMatrix, modelMatrix, [x, y, z]); mat4.rotateX(modelMatrix, modelMatrix, angleX); mat4.rotateY(modelMatrix, modelMatrix, angleY); mat4.scale(modelMatrix, modelMatrix, [sx, sy, sz]);
Use cases:
- Object position in the world
- Object rotation angles
- Object size scaling
V - View Matrix
Purpose: Transforms vertices from world space to camera space (view space)
javascript// Create view matrix using lookAt function const viewMatrix = mat4.create(); mat4.lookAt( viewMatrix, [0, 0, 5], // Camera position (eye) [0, 0, 0], // Target point to look at [0, 1, 0] // Up direction vector );
Essence of view matrix:
- Moves world coordinate origin to camera position
- Rotates coordinate system so camera faces -Z direction
- Camera is at origin, looking towards -Z axis
P - Projection Matrix
Purpose: Transforms vertices from camera space to clip space
Perspective Projection
Simulates human eye visual effect, objects appear smaller with distance
javascriptconst projectionMatrix = mat4.create(); mat4.perspective( projectionMatrix, Math.PI / 4, // Field of view (FOV) canvas.width / canvas.height, // Aspect ratio 0.1, // Near plane 100.0 // Far plane );
Orthographic Projection
Maintains object size, commonly used in 2D games or CAD software
javascriptmat4.ortho( projectionMatrix, -2, 2, // Left, Right -2, 2, // Bottom, Top 0.1, 100 // Near, Far );
Coordinate Space Transformation Flow
shellModel Space (Local Space) ↓ [Model Matrix M] World Space ↓ [View Matrix V] Camera Space (View Space) ↓ [Projection Matrix P] Clip Space ↓ [Perspective Division] Normalized Device Coordinates (NDC) ↓ [Viewport Transform] Screen Space
MVP Application in Vertex Shader
glsl// Vertex shader attribute vec3 a_position; attribute vec3 a_color; uniform mat4 u_modelMatrix; uniform mat4 u_viewMatrix; uniform mat4 u_projectionMatrix; varying vec3 v_color; void main() { // Method 1: Apply three matrices separately // vec4 worldPos = u_modelMatrix * vec4(a_position, 1.0); // vec4 viewPos = u_viewMatrix * worldPos; // gl_Position = u_projectionMatrix * viewPos; // Method 2: Use pre-computed MVP matrix (recommended) mat4 mvp = u_projectionMatrix * u_viewMatrix * u_modelMatrix; gl_Position = mvp * vec4(a_position, 1.0); v_color = a_color; }
Matrix Calculation in JavaScript
javascript// Using gl-matrix library import { mat4, vec3 } from 'gl-matrix'; class Camera { constructor() { this.projectionMatrix = mat4.create(); this.viewMatrix = mat4.create(); this.mvpMatrix = mat4.create(); } setPerspective(fov, aspect, near, far) { mat4.perspective(this.projectionMatrix, fov, aspect, near, far); } lookAt(eye, center, up) { mat4.lookAt(this.viewMatrix, eye, center, up); } getMVPMatrix(modelMatrix) { // MVP = P × V × M mat4.multiply(this.mvpMatrix, this.viewMatrix, modelMatrix); mat4.multiply(this.mvpMatrix, this.projectionMatrix, this.mvpMatrix); return this.mvpMatrix; } } // Usage example const camera = new Camera(); camera.setPerspective(Math.PI / 4, 16/9, 0.1, 100); camera.lookAt([0, 0, 5], [0, 0, 0], [0, 1, 0]); const modelMatrix = mat4.create(); mat4.translate(modelMatrix, modelMatrix, [1, 0, 0]); const mvp = camera.getMVPMatrix(modelMatrix); gl.uniformMatrix4fv(mvpLocation, false, mvp);
Common Issues and Considerations
1. Matrix Multiplication Order
Matrix multiplication is not commutative, order is crucial:
- Correct:
MVP = P × V × M, applied to vertex:MVP × vertex - Transformations applied first are on the right side of the multiplication chain
2. Row-major vs Column-major
- WebGL uses column-major matrix storage
- Third parameter
transposeofgl.uniformMatrix4fvmust befalse
3. Homogeneous Coordinates
Using 4D vectors (x, y, z, w):
- Vertex position:
w = 1 - Direction vector:
w = 0(not affected by translation)
4. Performance Optimization
- Pre-compute MVP matrix on CPU instead of multiplying separately in shader
- Use uniforms to pass pre-computed matrices