Matrices and Transformations
Learn about the fundamental concepts of matrices and transformations in the context of graphics (and physics) programming.
Overview
In Step 3 "Vectors, Points and Spaces" you learned the conceptual difference between vectors, points, and spaces.
Now we take the next major step: understanding matrices — the mathematical machinery that moves objects through space, rotates them, scales them, and ultimately projects them onto the screen.
This tutorial explains:
- What 4×4 matrices represent
- Why we use homogeneous coordinates
- How translation, rotation, and scale are encoded
- How model, view, and projection matrices work
- How transformations compose into the MVP pipeline
- How these concepts appear in btm_framework
By the end, you’ll understand the transformation pipeline used in every rendering engine and physics simulation.
1. Why 4×4 Matrices?
In 3D graphics and physics, we use 4×4 matrices because they allow us to represent:
- Translation
- Rotation
- Scale
- Perspective projection
All within a single unified structure.
This is possible thanks to homogeneous coordinates, where a point is represented as:
\[\left(x,y,z,1\right)\ \]
and a vector as:
\[\left(x,y,z,0\right)\ \]
The extra component (w) allows translation to be expressed as matrix multiplication — something impossible with 3×3 matrices.
2. Affine Transformations
An affine transformation matrix looks like this:
\[\left[\begin{matrix}R&T\\0&1\end{matrix}\right]\]
Where:
- \(R\) is a 3×3 rotation/scale matrix
- \(T\) is a translation vector
- The bottom row ensures homogeneous behavior
This structure is the backbone of all transformations.
3. Translation, Rotation, and Scale
Translation
Moves a point in space:
\[T\left(x,y,z\right)\]
In matrix form:
\[\left[\begin{matrix}1&0&0&t_x\\0&1&0&t_y\\0&0&1&t_z\\0&0&0&1\end{matrix}\right]\]
Rotation
Rotates around an axis.
For example, rotation around the Z axis:
\[\left[\begin{matrix}\cos\theta & -\sin\theta & 0 & 0\\ \sin\theta & \cos\theta & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 1\end{matrix}\right]\]
Scale
Uniform or non uniform scaling:
\[\left[\begin{matrix}s_x & 0 & 0 & 0\\ 0 & s_y & 0 & 0\\ 0 & 0 & s_z & 0\\ 0 & 0 & 0 & 1\end{matrix}\right]\]
4. Model, View, Projection
Every vertex in a 3D scene goes through a sequence of transformations:
Model Matrix (M)
Transforms from model space → world space.
It positions, rotates, and scales the object in the scene.
View Matrix (V)
Transforms from world space → camera space.
It represents the camera’s position and orientation.
Projection Matrix (P)
Transforms from camera space → clip space.
It applies perspective or orthographic projection.
5. The Model View Projection (MVP) Pipeline
The final transformation applied to a point is:
\[ MVP = P \cdot V \cdot M \]
And the vertex is transformed as:
\[ p_{clip} = MVP \cdot p_{model} \]
This is the heart of all rendering pipelines.
6. Why Order Matters
Matrix multiplication is not commutative:
\[ A \cdot B \neq B \cdot A \]
This means:
- rotating then translating ≠ translating then rotating
- scaling then rotating ≠ rotating then scaling
Understanding this prevents 90% of transformation bugs.
7. Spaces Revisited
Each matrix moves data into a new space:
- Model Matrix: model space → world space
- View Matrix: world space → camera space
- Projection Matrix: camera space → clip space
After clip space, the GPU performs:
- perspective divide
- viewport transform
- rasterization
But those come later.
8. Practical Example
We can see how all these concepts apply in practice. Everything is covered in the "matrices_transformations" example in the BeforeTheMesh repository.
In that example, we create a simple scene with a rotating cube and a camera orbiting around it. The cube's model matrix is updated every frame to apply rotation, while the view matrix is set to position the camera. The projection matrix is configured for perspective projection. By examining the code, you can see how these matrices are constructed and combined to render the scene correctly.
void calculate_sample_mvp()
{
// calculate a sample Model-View-Projection (MVP) matrix for rendering an object.
// This is just an example to show how the transformations work.
btm::fmat4 translation = btm::Translation(0.0f, 0.0f, -5.0f); // translate the object 5 units into the screen
btm::fmat4 rotation = btm::Rotation(0, 0, 0); // no rotation for now, but you could set this to rotate the object around its axes
btm::fmat4 scale = btm::Scale(1.0f, 1.0f, 1.0f); // no scaling for now, but you could set this to make the object larger or smaller
btm::fmat4 model = translation * rotation * scale; // the model matrix transforms the object from its local model space to world space
// sample setup for the camera's view and projection matrices.
// In a real application, these would be computed based on the camera's parameters and the viewport size.
btm::fvec3 cameraPos(0, 0, 20); // position the camera 20 units away from the origin along the z-axis
btm::fvec3 cameraTarget(0, 0, 0); // look at the origin where the object is located
btm::fvec3 upVector(0, 1, 0); // define the up direction for the camera (positive y-axis)
btm::fmat4 view = btm::LookAt(cameraPos, cameraTarget, upVector); // the view matrix transforms world space to camera (view) space
// calculate a perspective projection matrix with a 20 degree field of view,
// an aspect ratio of 800/600, and near/far planes at 0.1 and 100.
float fov = btm::dtr(20.f); // convert 20 degrees to radians
float aspect = 800.0f / 600.0f; // example aspect ratio
float nearPlane = 0.1f; // near plane distance
float farPlane = 100.0f; // far plane distance
btm::fmat4 projection = btm::Perspective(fov, aspect, nearPlane, farPlane);
// finally, we combine the model, view, and projection matrices to get the MVP matrix
// that will be used in the vertex shader to transform the vertices of the object from model space to clip space.
btm::fmat4 mvp = projection * view * model;
}
This is the exact structure used in modern rendering.
9. Common Mistakes
Understanding matrices and transformations is crucial to avoid common pitfalls such as:
- Applying transformations in the wrong order
- Forgetting that scaling affects rotation
- Mixing up row major and column major conventions
- Treating points like vectors (or vice versa)
- Forgetting to normalize direction vectors
This tutorial prepares you to avoid all of them.
10. Summary
In this tutorial, we covered the fundamental concepts of matrices and transformations in graphics programming. We learned why 4×4 matrices are used, how translation, rotation, and scale are represented, and how the model, view, and projection matrices work together in the MVP pipeline. We also discussed common mistakes to avoid when working with transformations.
- Why 4×4 matrices are used
- How translation, rotation, and scale work
- How model, view, and projection matrices transform geometry
- How the MVP pipeline composes
- Why order matters
- How these concepts appear in the framework
This is the mathematical engine behind all rendering and simulation.
Next Step
Before we can move on to more advanced topics, we must make sure that we have a solid understatnding of programming basics. In the next few tutorials, we will cover the basics of programming in C++ and how to use C++ for Simulations and Graphics. This will include topics such as memory management, object-oriented programming, and the use of libraries and frameworks.
Once we have a solid understanding of C++ programming, we will be able to move on to more advanced topics such as physics simulations, graphics rendering, and CAE simulations.
Step 5: C++ as a Simulation Language.