The Matrix
From specific to generic
We accept points as specific instances of vectors, either a 2D or a 3D vector. They are a specific instance, because vectors can be 1D, 2D, 3D, 4D .... nD.
A vector being a list of numbers, with however many dimensions, can still sit within a higher dimension space - we call that a matrix. In this sense we can consider a vector to be a specific instance of a matrix, that either has 4 rows * 1 column or 4 columns * 1 row. Naturally this is a 2d matrix, which if everything above made sense, it necesarily follows that a 2d matrix is just a specific instance of a matrix which can be n-dimensional.
As described above (but we won't dive into that) a matrix can be n dimensional, at most lets say it can be m*n*t (m rows, n columns, t transpositions), can go higher but not relevant in this context.
the vector is a specific instance of a matrix
The Core Idea
Modern 3D graphics is built on one core mathematical tool: the 4×4 transformation matrix. Every object in engines like Unity, Unreal, Blender, or WebGL is constantly transformed using them.
In 3D graphics, every point in space is represented as a column vector. Notice the extra coordinate at the bottom:
1# A 3D point is represented as a 4×1 column vector:2# v = [x, y, z, 1]^T3v = [4 [x],5 [y],6 [z],7 [1] # The w (homogeneous) coordinate!8]
The Structure of a 4×4 Matrix
A general 3D transformation matrix contains several different operations encoded into exactly 16 numbers. It is divided into logical blocks that each serve a distinct purpose:
| Section | Purpose |
|---|---|
| Upper-Left 3×3 | Rotation and Scaling |
| Right Column | Translation (Position) |
| Bottom Row | Homogeneous Coordinate Mechanics |
Why 4x4 Instead of 3x3?
A standard 3x3 matrix can rotate, scale, and shear space. However, it is mathematically impossible for a 3x3 matrix to translate (move) an object.
A 3x3 matrix multiplication always maps the origin vector [0, 0, 0] strictly to [0, 0, 0]. It cannot add standalone translation constants like +5 or -2.
[0, 0, 0]. Switching to 4x4 mode allows translation to occur because the homogeneous coordinate w = 1 activates the translation column!Identity:
1 in ordinary arithmetic.1# The Identity Matrix (I):2I = [3 [1.0, 0.0, 0.0, 0.0], # Basis X vector4 [0.0, 1.0, 0.0, 0.0], # Basis Y vector5 [0.0, 0.0, 1.0, 0.0], # Basis Z vector6 [0.0, 0.0, 0.0, 1.0] # Origin offset7]
Translation(Vector3d):
t_x, t_y, and t_z.1# Translation Matrix:2T = [3 [1.0, 0.0, 0.0, tx ],4 [0.0, 1.0, 0.0, ty ],5 [0.0, 0.0, 1.0, tz ],6 [0.0, 0.0, 0.0, 1.0]7]8# Applied to v = [x, y, z, 1]^T:9# v_new = [x + tx, y + ty, z + tz, 1]^T
w = 1 ensures the translation factor is added. If applied to a pure directional vector (where w = 0), the translation is ignored because directions are position-independent!Scale(Vector3d):
s_x, s_y, and s_z.1# Scaling Matrix:2S = [3 [sx , 0.0, 0.0, 0.0],4 [0.0, sy , 0.0, 0.0],5 [0.0, 0.0, sz , 0.0],6 [0.0, 0.0, 0.0, 1.0]7]8# Applied to v = [x, y, z, 1]^T:9# v_new = [sx*x, sy*y, sz*z, 1]^T
•
s > 1: stretches the object along that axis.•
0 < s < 1: squashes the object.•
s < 0: mirrors/flips the object across that plane! Try dragging any slider below zero.Determinant & Mirroring:
1def GetDeterminant(self) -> float:2 """Calculates the determinant of the 4x4 matrix using Laplace expansion."""3 m00, m01, m02, m03 = self.m00, self.m01, self.m02, self.m034 m10, m11, m12, m13 = self.m10, self.m11, self.m12, self.m135 m20, m21, m22, m23 = self.m20, self.m21, self.m22, self.m236 m30, m31, m32, m33 = self.m30, self.m31, self.m32, self.m3378 d2_01_01 = m20 * m31 - m21 * m309 d2_01_02 = m20 * m32 - m22 * m3010 d2_01_03 = m20 * m33 - m23 * m3011 d2_01_12 = m21 * m32 - m22 * m3112 d2_01_13 = m21 * m33 - m23 * m3113 d2_01_23 = m22 * m33 - m23 * m321415 minor0 = m11 * d2_01_23 - m12 * d2_01_13 + m13 * d2_01_1216 minor1 = m10 * d2_01_23 - m12 * d2_01_03 + m13 * d2_01_0217 minor2 = m10 * d2_01_13 - m11 * d2_01_03 + m13 * d2_01_0118 minor3 = m10 * d2_01_12 - m11 * d2_01_02 + m12 * d2_01_011920 return m00 * minor0 - m01 * minor1 + m02 * minor2 - m03 * minor3
Mirroring geometry is just scaling by -1 across an axis. However, this flips the matrix determinant to negative, which means mesh faces will render inside-out (normals are inverted).
Rotation(Vector3d, float):
1# Rotation Matrices for axes X, Y, and Z:2# Angle in radians: a34# Rotate X:5Rx = [6 [1.0, 0.0, 0.0, 0.0],7 [0.0, cos(a), -sin(a), 0.0],8 [0.0, sin(a), cos(a), 0.0],9 [0.0, 0.0, 0.0, 1.0]10]1112# Rotate Y:13Ry = [14 [ cos(a), 0.0, sin(a), 0.0],15 [ 0.0, 1.0, 0.0, 0.0],16 [-sin(a), 0.0, cos(a), 0.0],17 [ 0.0, 0.0, 0.0, 1.0]18]1920# Rotate Z:21Rz = [22 [cos(a), -sin(a), 0.0, 0.0],23 [sin(a), cos(a), 0.0, 0.0],24 [0.0, 0.0, 1.0, 0.0],25 [0.0, 0.0, 0.0, 1.0]26]
| Axis | Behavior |
|---|---|
| X-Axis | X coordinate remains fixed; Y and Z rotate. |
| Y-Axis | Y coordinate remains fixed; X and Z rotate. |
| Z-Axis | Z coordinate remains fixed; X and Y rotate. |
LookAt(Eye, Target, Up):
1def LookAt(eye: 'Point3d', target: 'Point3d', up: 'Vector3d') -> 'Matrix4x4':2 # 1. Forward Vector (Z)3 forward = (target - eye).Unitize()45 # 2. Right Vector (X) = Cross Product of Up and Forward6 right = Vector3d.CrossProduct(up, forward).Unitize()78 # 3. True Up Vector (Y) = Cross Product of Forward and Right9 true_up = Vector3d.CrossProduct(forward, right)1011 # Build rotation matrix from these 3 basis vectors12 return Matrix4x4([13 right.X, true_up.X, forward.X, eye.X,14 right.Y, true_up.Y, forward.Y, eye.Y,15 right.Z, true_up.Z, forward.Z, eye.Z,16 0, 0, 0, 117 ])
Multiply(Matrix4x4, Matrix4x4):
1# Matrix multiplication order goes RIGHT to LEFT:2# v_new = T * R * S * v3# 1. Scale first (S)4# 2. Rotate second (R)5# 3. Translate last (T)
• Rotate then Translate (0): Spins the box in place, then pushes it out. The box stays close.
• Translate then Rotate (1): Pushes the box out, then rotates around the origin, causing it to orbit along a large arc!
Decompose(Matrix4x4):
1def Decompose(self) -> tuple['Vector3d', 'Quaternion', 'Vector3d']:2 """Extracts Translation, Rotation, and Scale from a 4x4 matrix."""34 # 1. Translation is easily extracted from the 4th column5 translation = Vector3d(self.m03, self.m13, self.m23)67 # 2. Scale is the magnitude of the 3 basis vectors (columns)8 scaleX = Vector3d(self.m00, self.m10, self.m20).Length9 scaleY = Vector3d(self.m01, self.m11, self.m21).Length10 scaleZ = Vector3d(self.m02, self.m12, self.m22).Length11 scale = Vector3d(scaleX, scaleY, scaleZ)1213 # 3. Rotation is what's left after removing scale from the 3x314 # Usually returned as a Quaternion or Euler angles15 rotation = ExtractRotation(self)1617 return translation, rotation, scale
Invert(Matrix4x4):
- Local Space: Object's own origin (model-relative).
- World Space: Scene-wide origin (all models combined).
- View Space: Relative to camera lens position.
- Screen Space: Flattened 2D screen coordinates.
1# The standard vertex pipeline:2# MVP = Projection * View * Model3# v_screen = MVP * v_local
What a Matrix Really Represents
A matrix does not simply “move individual points.” Instead, a matrix transforms the coordinate system itself.
When you apply a matrix to an object, you are warping, rotating, and scaling the entire fabric of space. The object's local coordinates remain unchanged — they only appear to deform because the space they sit in is mathematically reshaped.