Two ways to calculate the isometric projection matrix
Isometric projection of a pyramid rotating around z-axis
Isometric projection is one of the ways to map a 3D point on a 2D plane. It is a linear transformation, which means it can be represented by a 2-by-3 matrix. A common way to explain the projection and derive the matrix is via using a composition of rotations - a 3D vector is linearly transformed by two rotations. Finally its z-coordinate is ignored, giving a 2D vector corresponding to the 3D vector.
However there is another way to arrive at the projection matrix. This way is arguably simpler and completely circumvents the rotation matrices. Let's take a look at both the approaches and build the isometric projection matrix from the ground up.
TLDR: A function to map x,y,z to x,y
Below is the function that maps a 3D vector to a 2D vector. The rest of this article discusses two approaches to derive this function.
def get_isometric_projection(x:int, y:int, z:int):
SQRT_2, SQRT_3, SQRT_6 = 2**0.5, 3**0.5, 6**0.5
x_out = (x-y) / SQRT_2
y_out = (x+y-2*z) / SQRT_6
return x_out, y_out
1. Details of the 3D input points: a cube
For the purpose of illustration, we will map a cube whose eight vertices are located at the points \(
\begin{bmatrix}
±1 \\ ±1 \\ ±1
\end{bmatrix}
\). Note that each side of this cube has length 2. To distinguish between different sides, the top edges of this cube are drawn in red, the bottom edges in black and vertical edges in teal.
2. Isometric projection from the point of view of rotations
Probably the simplest way to map a 3D vector to a 2D plane is to simply ignore its z-coordinate: \(
\begin{bmatrix}
x \\ y \\ z
\end{bmatrix}
\) → \(
\begin{bmatrix}
x \\ y
\end{bmatrix}
\). This projection is shown in the visual below. We only see the top edges located at \(
\begin{bmatrix}
±1 \\ ±1
\end{bmatrix}
\).
To make all edges visible, we rotate the 3D vectors such that the vector \(
\begin{bmatrix}
1 \\ 1 \\ 1
\end{bmatrix}
\) becomes perpendicular to the XY-plane. This can be done in two rotations:
First rotation: Rotate the 3D vectors around the z-axis by 45 degrees. This will take the vector \(
\begin{bmatrix}
1 \\ 1 \\ 1
\end{bmatrix}
\) to \(
\begin{bmatrix}
0 \\ √2 \\ 1
\end{bmatrix}
\). This matrix is given by \(
\begin{bmatrix}
cos(⍺) & -sin(⍺) & 0 \\ sin(⍺) & cos(⍺) & 0 \\ 0 & 0 & 1
\end{bmatrix}
\).
Second rotation: Rotate the 3D vectors around the x-axis by arctan(√2). This will take the vector \(
\begin{bmatrix}
0 \\ √2 \\ 1
\end{bmatrix}
\) to \(
\begin{bmatrix}
0 \\ 0 \\ √3
\end{bmatrix}
\).This matrix is given by \(
\begin{bmatrix}
1 & 0 & 0 \\ 0 & cos(θ) & sin(θ) \\ 0 & -sin(θ) & cos(θ)
\end{bmatrix}
\).
You can combine the two rotations by multiplying the two rotation matrices. Using ⍺ = π/4, θ = arctan(√2) and plugging in the values in the matrices we get:
\(
\begin{bmatrix}
1 & 0 & 0 \\ 0 & 1/√3 & -√2/√3 \\ 0 & √2/√3 & 1/√3
\end{bmatrix}
\)\(
\begin{bmatrix}
1/√2 & -1/√2 & 0 \\ 1/√2 & 1/√2 & 0 \\ 0 & 0 & 1
\end{bmatrix}
\) =\(
\begin{bmatrix}
1/√2 & -1/√2 & 0 \\ 1/√6 & 1/√6 & -√2/√3 \\ 1/√3 & 1/√3 & 1/√3
\end{bmatrix}
\)2.1 The last step to get the matrix
Finally, ignoring the z-coordinate gives us the matrix for isometric 3D to 2D projection: \(
\begin{bmatrix}
1/√2 & -1/√2 & 0 \\ 1/√6 & 1/√6 & -√2/√3
\end{bmatrix}
\).
3. Isometric projection matrix via first principles
There is another approach to arrive at this matrix directly without thinking in terms of rotations. It uses the same line of reasoning that we used to derive the rotation matrix . Let's assume the 2-by-3 matrix we want is \(
\begin{bmatrix}
p_1 & q_1 & r_1 \\ p_2 & q_2 & r_2
\end{bmatrix}
\). All we need to do is to find out where on the XY-plane the three 3D basis vectors are mapped:
\(
\begin{bmatrix}
1 \\ 0 \\ 0
\end{bmatrix}
\) is mapped to \(
\begin{bmatrix}
p_1 \\ p_2
\end{bmatrix}
\).
\(
\begin{bmatrix}
0 \\ 1 \\ 0
\end{bmatrix}
\) is mapped to \(
\begin{bmatrix}
q_1 \\ q_2
\end{bmatrix}
\).
\(
\begin{bmatrix}
0 \\ 0 \\ 1
\end{bmatrix}
\) is mapped to \(
\begin{bmatrix}
r_1 \\ r_2
\end{bmatrix}
\).
Isometric mapping of 3D basis vectors on a 2D plane
But in the visual above, we can see where these basis vectors are mapped:
\(
\begin{bmatrix}
1 \\ 0 \\ 0
\end{bmatrix}
\) is mapped to \( \text{r} \)\(
\begin{bmatrix}
√3/2 \\ 1/2
\end{bmatrix}
\).
\(
\begin{bmatrix}
0 \\ 1 \\ 0
\end{bmatrix}
\) is mapped to \( \text{r} \)\(
\begin{bmatrix}
-√3/2 \\ 1/2
\end{bmatrix}
\).
\(
\begin{bmatrix}
0 \\ 0 \\ 1
\end{bmatrix}
\) is mapped to \( \text{r} \)\(
\begin{bmatrix}
0 \\ -1
\end{bmatrix}
\).
Here \( \text{r} \) is the ratio by which each vector is scaled. We do not know its value at this point but will calculate it shortly. But knowing these values almost gives us the entire matrix:
\( \text{r} \)\(
\begin{bmatrix}
√3/2 & -√3/2 & 0 \\ 1/2 & 1/2 & -1
\end{bmatrix}
\)
3.1 Calculating the foreshortening ratio
All we need to do is find the value of \( \text{r} \). We can find it out by comparing the edge length of the cube after the first rotation (which does not change the lengths) and the second rotation (which changes the length of each side). From the visual below, it is easy to see that \( \text{r = √2/√3} \):
Black bold line: view after first rotation (edge lengths remain the same)
Red dashed line: view after second rotation (edge lengths foreshortened)
Foreshorterning of vectors by a value \( \text{r = cos(45)/cos(30) = √2/√3} \)
Setting this value in the above matrix gives us the isometric projection matrix as:
\( \text{(√2/√3)} \)\(
\begin{bmatrix}
√3/2 & -√3/2 & 0 \\ 1/2 & 1/2 & -1
\end{bmatrix}
\)\( \text{=} \)\(
\begin{bmatrix}
1/√2 & -1/√2 & 0 \\ 1/√6 & 1/√6 & -√2/√3
\end{bmatrix}
\)
This is the same matrix that we arrive at using the approach of two rotations above.