in maths

The Transformation Matrix for 2D Games

Share Button

This tutorial will introduce the Transformation Matrix, one of the standard technique to translate, rotate and scale 2D graphics. The first part of this series, A Gentle Primer on 2D Rotations, explaines some of the Maths that is be used here.

Introduction

In the previous post we have seen how a 2D point \left(x,y\right) can be represented in the plane, and how trigonometry links its Polar and Cartesian representations:

2d transform 2

In a nutshell:

    \[x=R \, \cos\left(\theta\right ) \]

    \[y=R \, \sin\left(\theta\right ) \]

The second important result is that any given point \left(x,y\right) an be rotated by an angle \theta around the origin as follow:

    \[{x}' = x \, \cos\left(\theta\right)- y\, \sin\left(\theta\right)\]

    \[{y}' =  x\, \sin\left(\theta\right) + y \, \cos\left(\theta\right)\]

These are the only two notions you need to understand this tutorial.

Matrix notation

When it comes to 3D graphics, there’s an alternative representation that is often encountered. A rotation can, in fact, be expressed as a matrix multiplication. To do this, let’s express \left(x,y\right) as the column vector \begin{bmatrix} x & y \end{bmatrix}. The problem is now finding a matrix T\left(\theta\right) so that:

    \[T\left(\theta\right) \cdot \begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} x\,\cos\left(\theta\right) -y\,\sin\left(\theta\right) \\ x\,\sin\left(\theta\right) + y\,\cos\left(\theta\right) \end{bmatrix} = \begin{bmatrix} {x}' \\ {y}' \end{bmatrix}\]

Remembering matrix multiplication:

    \[\begin{bmatrix} a & b \\ c & d \end{bmatrix} \cdot \begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} x a + yb \\ xc + yd \end{bmatrix}\]

Please, note that the result is a vector with one column. This makes sense, because the result is another point in the 2D plane.Matrix_multiplication_diagram_2.svg

The matrix T\left(\theta\right) can be defined as:

    \[\underbrace{\begin{bmatrix} \cos\left(\theta\right) & -\sin\left(\theta\right) \\ \sin\left(\theta\right) & \cos\left(\theta\right) \end{bmatrix} }_{T\left(\theta\right)} \cdot \begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} x\,\cos\left(\theta\right) -y\,\sin\left(\theta\right) \\ x\,\sin\left(\theta\right) + y\,\cos\left(\theta\right) \end{bmatrix} = \begin{bmatrix} {x}' \\ {y}' \end{bmatrix}\]

Every rotation of \theta radians in the 2D plane can be obtained by multiplying a column vector by T\left(\theta\right).

Adding translations

There are other operations which, unfortunately, cannot be achieved with this matrix. Translations is one of them. What we want is a new matrix T\left(t_x, t_y\right) such that:

    \[T\left(t_x, t_y\right) \cdot \begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} x+ t_x \\ y+ t_y \end{bmatrix}\]

This is not possible with the current setting. In order to obtain this result, we need to modify the way \left(x,y\right) is represented.

    \[\underbrace{ \begin{bmatrix} 1&0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \\ \end{bmatrix} }_{T\left(t_x, t_y\right)} \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \begin{bmatrix} x+t_x\\ y +t_y \\ 1 \end{bmatrix}\]

The point \left(x,y\right) is now represented by the three dimensional column vector \begin{bmatrix} x & y & 1 \end{bmatrix}. This is necessary in order to make the matrix multiplication works, since the new T now has three rows and columns.

This technique is currently being used in most 2D graphics framework. The matrix T is often called the Transformation matrix and can be used to perform the following operations:

2D_affine_transformation_matrix.svg_

Composition

Using matrices to perform transformation has an incredible advantage: they can be multiplied together to perform multiple transformation. A single matrix can hold as many transformation as you like. In a nutshell:

    \[ T_2 \cdot \left ( T_1 \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \right) = \left ( T_2 \cdot T_1 \right) \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \]

This is true because matrix multiplication is an associative operator. It is important to remember, however, that these transformations are not commutative. This means that T_2 \cdot T_1 is not the same as T_1 \cdot T_2. Intuitively, this is obvious: rotating and translating is different from translating and then rotation.

Inversion

Transformations can be undone. For every transformation matrix T which does rotates or translates, there is a matrix T^{-1} which performs the “opposite” operation. This means that if we apply T, followed by T^{-1}, we obtain the original point:

    \[ T^{-1} \cdot \left ( T \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \right) = \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \]

By using the associative property, we can get a glimpse of what this matrix is:

    \[ \left ( T^{-1} \cdot T \right) \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \]

    \[ \left ( T^{-1} \cdot T \right) \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \mathbb{I} \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \]

    \[T^{-1} \cdot T = \mathbb{I}\]

If you have a basic knowledge of matrix algebra, you should recognise this: T^{-1} is the inverse matrix of T. Inverting a matrix is a non trivial task, and goes beyond the scope of this tutorial. However, you don’t really need to know how to invert a matrix to undo a transformation. Because of the way the transformation matrix has been constructed, it is always true that:

    \[ T\left(-\theta\right) \cdot \left ( T\left(+\theta\right) \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \right) = \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \]

    \[ T\left(-x,-y\right) \cdot \left ( T\left(+x,+y\right) \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \right) = \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \]

The meaning of these two equations should be intuitive to grasp: if you rotate a point of \theta angles, followed by a rotation of -\theta, you get the original point. The same applies for translations.

    \[T\left(+\theta\right)^{-1} = T\left(-\theta\right)\]

    \[T\left(+x,+y\right)^{-1} = T\left(-x,-y\right)\]

From this, it follows that if you have a series of elementary rotations and translations, the inverse of their composition is the composition of their inverses, in reversed order:

    \[\left( T_n \cdot T_{n-1}\cdot \dots \cdot T_2\cdot T_1 \right)^{-1}= T_1^{-1} \cdot T_2^{-1} \cdot T_{n-1}^{-1}\cdot \dots \cdot T_n^{-1}\]

From a more general point of view, it is not true that all transformations can be undone. For instance the following transformations cannot be undone:

    \[\begin{bmatrix} 0 & 0 & 0  \\ 0 & 1 & 0  \\ 0 & 0 & 1 \end{bmatrix} \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \right)= \begin{bmatrix} 0 \\ y \\ 1 \end{bmatrix} \right)\]

Multiplying the x component by zero destroys its information, which cannot be restored with another multiplication. Such transformation, however, is neither a rotation nor a translation. In this particular case, the matrix cannot be inverted. When this occurs, it is also referred as singular or degenerate. A matrix is singular is and only if its determinant is zero.

Rotation around a point

As seen in the previous part of this tutorial (A Gentle Primer on 2D Rotations), to rotate around an arbitrary point, we need to first make that our new origin of the Cartesian plane. Then we rotate the point, and finally we restore the origin of the plane. This can be expressed a composition of three transformations:

    \[T\left(P_x,P_y\right) \cdot  T\left(\theta\right) \cdot T\left(-P_x,-P_y\right)\]

It’s important to remember that, despite the order in which they are written, the first transformation is the one on right.

Conclusion

This post has introduced the transformation matrix, which is one of the standard ways in which transformations are stored and performed in computer graphics. We have explored the following transformations:

  • Translation by t_x, t_y:

    \[\underbrace{\begin{bmatrix} 1 & 0 & t_x\\ 0 & 1 & t_y \\ 0 & 0 & 1 \end{bmatrix} }_{T\left(t_x, t_y\right)} \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \begin{bmatrix} x + t_x \\ x + t_y \\ 1 \end{bmatrix}\]

  • Rotation by \theta around the origin:

    \[\underbrace{\begin{bmatrix} \cos\left(\theta\right) & -\sin\left(\theta\right) & 0\\ \sin\left(\theta\right) & \cos\left(\theta\right) & 0 \\ 0 & 0 & 1 \end{bmatrix} }_{T\left(\theta\right)} \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \begin{bmatrix} x\,\cos\left(\theta\right) -y\,\sin\left(\theta\right) \\ x\,\sin\left(\theta\right) + y\,\cos\left(\theta\right) \\ 1 \end{bmatrix}\]

  • Rotation by \theta around the point \left(P_x, P_y\right):

    \[T\left(P_x,P_y\right) \cdot  T\left(\theta\right) \cdot T\left(-P_x,-P_y\right) \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}\]

The main advantage of the matrix notation is that transformations can be composed by multiplying their respective transformation matrices. This also allows to “undo” transformation by calculating the inverse of its matrix.

The next post in this series will focus on the geometrical consequences of the equations we have derived. This will help to demystify one of the most misunderstood concept of Maths: complex numbers. Their understanding is essential for quaternions.

Other resources

  • Part 1. A Gentle Primer on 2D Rotations
  • Part 2. The Transformation Matrix
  • Part 3. Rotations in the Complex Plane
  • Part 4. Understanding Rotations in 3D
  • Part 5. Understanding Quaternions
📧 Stay updated

A new tutorial is released every week.

💖 Support this blog

This websites exists thanks to the contribution of patrons on Patreon. If you think these posts have either helped or inspired you, please consider supporting this blog.

Paypal
Ko-fi
Twitter_logo

Write a Comment

Comment

  1. Hi Alan,
    I’m trying to understand what a mentor has described to me and am looking for some additional help.

    I am attempting to cancel out velocity of movement of a player when I’ve detected a collision, given the normal of the collision geometry, so that I have a smooth result that does not overlap the geometry of the collision.

    Vector3 CancelCollision(Vector3 dVel, Vector3 normal)
    {
    Vector3 originalVector = dVel;
    dVel = Vector3.Project(dVel, normal);

    dVel = originalVector – dVel;

    dVel = dVel.normalized * originalVector.magnitude;

    return dVel;
    }

    This mostly works, but there is a small amount of error, which has been attributed by my mentor as being a discrepancy of the magnitude as a result of using the ‘shadow’ of the projection.

    I’ve been told that I need to rotate the original velocity to a cardinal direction, do the calculation, then rotate the result back. I’ve been told that the only way to get the correct result is with matrix math, which I somewhat understand but do not understand within the context of the current application.

    I have enjoyed reading through your article here. Thanks for the help.

Webmentions

  • Matriz de Transformação para jogos 2D | October 3, 2018

    Hi Alan,
    I’m trying to understand what a mentor has described to me and am looking for some additional help.

    I am attempting to cancel out velocity of movement of a player when I’ve detected a collision, given the normal of the collision geometry, so that I have a smooth result that does not overlap the geometry of the collision.

    Vector3 CancelCollision(Vector3 dVel, Vector3 normal)
    {
    Vector3 originalVector = dVel;
    dVel = Vector3.Project(dVel, normal);

    dVel = originalVector – dVel;

    dVel = dVel.normalized * originalVector.magnitude;

    return dVel;
    }

    This mostly works, but there is a small amount of error, which has been attributed by my mentor as being a discrepancy of the magnitude as a result of using the ‘shadow’ of the projection.

    I’ve been told that I need to rotate the original velocity to a cardinal direction, do the calculation, then rotate the result back. I’ve been told that the only way to get the correct result is with matrix math, which I somewhat understand but do not understand within the context of the current application.

    I have enjoyed reading through your article here. Thanks for the help.