3D Transformation Math In A Nutshell
I have been a hobbyist game developer for a while now, with a keen interest in 3D programming. But I have been spoiled by the many great APIs out there (like XNA).
These APIs abstract so much that you can achieve all the fundamentals of 3D programming without actually understanding how it works.
This is fine right up to the point where you need to do something that goes beyond the fundamentals...
Recently I embarked on a quest to improve my understanding of the math and algorithms behind 3D transformations. To help solidify what I have learned - and in part due to my frustration at the materials available - I decided to write an article introducing the math.
Let's Get Started...
There are three structures relevant to 3D transformations:
The Vertex
Vertices represent a point in 3D space. The vertex stores the coordinates of the point (P) in the form of:

The Vector
Vectors represent the orientation and size of a line running from true origin – [0,0,0] – to a point in 3D space. A vector stores the coordinates of the point (P) in the form of:

Now obviously both vertices and vectors are simply storing the coordinates of a point; so it is really how they are used that differentiates them.
The Transformation
A transformation is a structure that defines how a vector or vertex should be modified. They can define several types of modifications including translation, scaling, rotation, and sheering.
The transformation is stored in the form of:

Notice that rows A through C take the form of a vector, and that row D takes the form of a vertex. This is because row D is the translation row.
In local-space (model-space), all vertices are set relative to origin – [0,0,0] – but an object/model might not be positioned at origin in world-space. Vertices must be ‘translated’ to ensure they are correctly positioned in world-space.
Local-space refers to the "space" in which a model is defined. Think of a cube where the centre of the cube is [0,0,0]. The corners of the cube might be [0.5,0.5,0.5], [-0.5,-0.5,-0.5], and so on - ultimately making a cube 1x1x1.
World-space is the bigger picture. Where would the centre of the cube be in the bigger "world"? That is essentially what translation is about.
The translation row basically says: “move the vertex by Dx on the x-axis, Dy on the y-axis, and Dz on the z-axis.”
Now you probably noticed that the last element of a vertex is set to 1, where as the last element of a vector is set to 0.
This is a ‘trick’ to allow for the translation of origin – [0, 0, 0] – which normally could not be translated as anything multiplied by 0 is always 0...
... But why then is the last element in the vector set to 0? Well a vector has no position, and therefore should not be translated.
If you translate (move) the point stored in the vector, you ‘corrupt’ the data the vector represents - the size and orientation of a line running from origin to that point. Rotation and scale then become meaningless.
The last element of a vertex being set to 1 ensures all vertices can be translated – even origin.
The last element of a vector being set to 0 ensures that vectors can never be translated.
The examples later in this document will make this clearer.
So if row D defines translation, what do rows A through C define? Well in combination they define everything else: scaling, rotation, and sheering.
How do they do this? Well to help explain this, we need to have a look at what the transformation matrix looks like when you are doing nothing:

Row A is oriented directly (and positively) along the x-axis, and has a magnitude of 1. Row B is oriented directly along the y-axis, and row C is oriented directly along the z-axis.
Interestingly, and importantly, if you look at the columns, you will notice they also represent vectors aligned to the major axes.
This is where it all starts to come to together... but to understand why, we need a quick refresher in matrix multiplication:

Now it becomes clear that all the values in the first column will modify the x-element of the vector/vertex. The second column will modify the y-element, and so on.
Knowing this, and with a strong knowledge of trigonometry, you can derive rules to do the various transformations like rotation and scaling.
Thankfully other people have saved us the time, and the rules are already well defined.
But before I get in to those rules, I would like to give a few very basic examples of translation, to help you get a better grasp on the importance of the static 0’s and 1’s, and how it all comes together.
Example: Translation of Origin Vertex

Example: Attempted Translation of Vector

OK. So hopefully those examples clarify the mysterious last-element, and give you a better feel for how everything comes together.
Now on to the rules for standard operations:
Translation

Scaling
Rotate Around X-Axis by Theta (θ)

Rotate Around Y-Axis by Theta (θ)

Rotate Around Z-Axis by Theta (θ)

Final Thoughts
The great thing about matrices is that you can combine them by following the simple rules of matrix multiplication.
Want to translate and then scale? Well create a translation matrix, create a scale matrix, and multiply them together!
Order of multiplication does matter – and sadly varies slightly in different 3D APIs – but a good general rule of thumb is translation * scale * rotation.
