Tag Archives: rotate

[OpenGL part 5] Matrix operations ( translate, scale, rotate )

Introduction to Matrix Operations


In this part, we’ll be looking at basic matrix math. We’ll be looking at how we create the various transformation matrices that we use for rotating, moving and scaling. If you really want, you can skip to the second part where we look at some code and let glm do the maths for us. But I really recommend actually learning the basics of matrix operations.

Matrices


Matrices are basically small tables of numbers. They are used in graphics programming when transforming vectors and object. We use them to move, rotate and scale objects. The math behind them is relatively simple though some of it can be hard to wrap your mind around first. And there are several mistakes that are easy to make and very hard to debug, so it’s very useful to know a bit about them and how they work.

The basics


In all simplicity, a matrix is just a table of numbers. Like the one you see below. With it comes a lot of simple operations we can do to transform objects ( like we saw with the model/view/projection matrix in the last part. But even though the idea is simple and the operations are basic ( usuaully just addition and multiplication ), they can quickly become confusing

\begin{bmatrix} 1\quad0\quad0\quad0 \\0\quad1\quad0\quad0 \\0\quad0\quad1\quad0\\0\quad0\quad0\quad1\end{bmatrix}

The unit matrix


What you see above is what we call the “unit matrix”. You can look at this like the base matrix or the null matrix. The idea behind it is that anything you multiply it with will remain the same ( we’ll look at this soon. ) That makes the unit matrix the starting point as well as it’s used in a few different, more complex matrix expression.

Matrix – vector multiplication


The simplest operations we’ll be looking at, is multiplying a matrix with a vector. This is quite straight forwards, though there will be a lot of numbers to keep track of so read through it a few times and get comfortable with it before proceeding. The formula for multiplying a 3×3 matrix with a 3d vector is as follows :

Let’s isolate just the top row ( all rows are multiplied in the same way )

We can multiply 4×4 matricies and verticies like this :

Step-by-step guide


  1. Look at first row
    1. Multiply first matrix value on that row with first vector value (x)
    2. Multiply second matrix value on that row with second vector value (y)
    3. Multiply third matrix value on that row with third vector value (z)
    4. Continue until no more more numbers on that line of the matrix
    5. Add all the numbers together
  2. Repeat for next row until no more rows
  3. Done!

You might have noticed that this requires that the number of values in each row of the matrix is the same as the numbers of values in the vector. If we have 3 values in each row of the matrix, the vector needs to have 3 values as well. This isn’t really an issue for us, so we won’t be looking at these cases here.

The unit matrix


As mentioned earlier, the unit matrix won’t change anything we multiply by it. We can see this by doing a multiplying with placeholder values for x, y, z and w

So now that we’ve learned how to do multiplication, let’s test it out and see if it’s really true! Let’s try to multiply it by the vector 1.03, -4.2, 9.81, 13 :

As you can see, we end up with the same as we began with, 1.03, -4.2, 9.81, 13.

Matrix – matrix multiplication


Multiplying a matrix with a vector was quite easy. Now let’s make things a tiny bit more difficult and multiply a matrix with a different matrix. This is one of the most important basic operations we need to do. It plays a huge role in moving/scaling/rotating objects. And, as we’ll see in a later part, it’s a very important part of lighting.

Matrix multiplication depends a bit on the sizes of the two matrices. But we’ll simplify it to say that we’ll always be working with unifrom matrixes ( 2×2, 3×3, 4×4 ). Firstly, lets look at the generic formula :

Now this seems a bit complicated, so let’s look at how to calculate just the first number :

matrix multi first cell

As you can see, for the first part of the multiplication we use the first numbers of both matrices ( A11 and B11 ). But for the second number, we use the next number in the same row for matrix A ( A12 ) and the next number in the same column for matrix B ( B21) This pattern repeats for the next number on that row like this :

matrix multi second cell

Now we move to the next row and repeat the process :

matrix multi third cell

And finally, the last cell :

matrix multi fourth cell


This can also be extended to a 3×3 matrix like this

This is a lot of numbers, but if you look closely, you’ll see it’s a lot like the previous one, only with an extra number on each row and column. So in this case, for the first number, all we did was add + a13 * b31 to the original operation ( which was a11 ∗ b11 + a12 * b21 ) For the second number on the top row we added + a13 ∗ b32 to the original operation. The third number on the top row is new but it follows the same pattern;

For all the numbers on the same row from matrix A

a11, a12, a13

and all the numbers in the same column from matrix B

b13, b23, b33

multiply each pair in the same position and add them together.

a31∗b13 + a32∗b23 + a33∗b33

The unit matrix again


Now let’s try multiplying a vector with the unit matrix again. We should get the same result as we started with, but let’s see…

Success! This product is exactly the same as we started with!

Ordering matters


A very important part of matrix operations is the ordering. Normally in mathematics the ordering is not important. When it comes to simple multiplication it does not matter what order you multiply two numbers 123 * 321 gives the exact same result as 321 * 123. But when it comes to matrices, this is not true. Let’s look at a very simple example :

But if we flip the ordering…

..we end up with something completely different.

Because of this, it is important to keep track of the ordering, otherwise, you’ll end up spending hours debugging!

Using matrices to change vertexes


Now that we’ve learned about the basic math about matrices, it’s time to learn how to use them. We’ll be using them to move, scale and rotate objects. We do this by multiplying each vertex by a matrix. After multiplying the vertex, we get a new vertex back that has been moved/scaled/rotated. After doing this to all the vertexes of the object, the entire object will have been moved/scaled/rotated. Creating these matrices is quite easy though there will be a few numbers to keep track of. Let’s look at the operations one by one.

Moving (translating)


The matrix we use for moving an object is quite simple. It is defined like this :

\begin{bmatrix}
\,\ 1\quad 0\quad 0\quad dx\\
\,\ 0\quad 1\quad 0\quad dy\\
\,\ 0\quad 0\quad 1\quad dz\\
0\quad 0\quad 0\quad 1\\
\end{bmatrix}

Where dx is movement in x direction, dy is movement in y direction and dz is movement in z direction. So in effect, we get this matrix :

\begin{bmatrix}
1 & 0 & 0 & \phantom{-}9.2\\
0 & 1 & 0 & \phantom{-}1.2\\
0 & 0 & 1 & -3.7\\
0 & 0 & 0 & \phantom{-}1\\
\end{bmatrix}

Will move the object 9.2 in the x direction, 1.2 in the y direction and -3.7 in the z direction.

Now this might look a bit familiar. Let’s compare it to the unit matrix :

\begin{bmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 1 & 0\\
0 & 0 & 0 & 1\\
\end{bmatrix}

That’s right. It’s the same except the dx, dy and dz part. This will come into effect when we do the actual translation.

Since we are using a 4×4 matrix, it is easier to use 4d vector. But that raises a new question; what about the last value? The x, y and z is, of course, the position. But there is a final number we haven’t cared about yet. As it turns out, this has to be 1 we’ll find out why now.

Let’s look at an example. Say we have the vector [11, 1.5, -43] first we need to add the last digit, 1 so we end up with :

\begin{bmatrix}
\phantom{-}11\\
\phantom{-}1.5\\
-43\\
1
\end{bmatrix}

Now for the translation matrix. Let’s use the one from above which will move the object 42 in the x direction, 19 in the y direction and -13 in the z direction.

\begin{bmatrix}
1 & 0 & 0 & \phantom{-}9.2\\
0 & 1 & 0 & \phantom{-}1.2\\
0 & 0 & 1 & -3.7\\
0 & 0 & 0 & \phantom{-}1\\
\end{bmatrix}

Finally we can try the translation. Translating an object is simply just multiplying the vertex and the translation matrix :

This might seem like a bit of over complication. Why not just add the numbers? Just adding the numbers would be practical if we were just moving the object. But we can do other things like scaling and rotating. By using a matrix, we can combine all of these into a single operation. So let’s look at the next operation, scaling.

Making things bigger or smaller (scaling)


The second operation we’ll look at is how to make objects larger or smaller. This is quite similar to translating objects. For scaling we have the base matrix:

\begin{bmatrix}
sx & 0 & 0 & 0\\
0 & sy & 0 & 0\\
0 & 0 & sz & 0\\
0 & 0 & 0 & 1
\end{bmatrix}

And just like with translation matrices, we multiply our vector with this matrix to get the scaled vector back.

Here sx, sy, sz are the scale factors, which are the numbers we need to multiply with in order to get the result :

  • If you don’t want to scale it all all, you se the scale factor to 1.
  • If you want to double the size you have a scale factor of 2, for trippling you have 3, etc…
  • If you want to make it 50% larger, you have a scale factor of 1.5, 25% larger the scale factor is 1.25, etc…>
  • If you want to halve it, you have a scale factor of 0.5, make it 75% smaller the scale factor is 0.25, etc…

Let’s first look at an example:

Say we have the vertex [2.1, 3.4, -9.5] and we want to scale it like the following :

  • Make it 70% smaller in x direction
    • Scale factor becomes 1.0 - 0.7 = 0.3
  • Make it 80% larger in y direction
    • Scale factor becomes 1.8
  • Triple the size in z direcion
    • Scale factor becomes 3.0

This gives us the scale factors [0.3, 1.8, 3.0 and the vertex [2.1, 3.4, -9.5]. Let’s plot these into the matrix operation:

This gives us the scale factors [0.3, 1.8, 3.0 and the vertex 0.63, 6.12, -28.5]… Which tells us that the vertex has been moved :

  • Closer to the center in x direction ( becasue object get smaller in x direction )
  • A little further away from the center in y direction ( which means the object gets larger in y direction )
  • A lot further away from the center in z direction ( getting a lot larger in z direction )
  • And if we apply this to all the vertices in an object, we find that the center of the object remains the same, so we’re not actually moving the object, we’re just moving the individual vertices. Closer to or further away from the center.

    Rotating


    Now this is where things get a little complicated. We need to translate the object using numbers calculated using sin and cos. The formula for calculating the rotated x and y is as follows :


    x2 = cos β * x1 − sinβ * y1
    y2 = sin β * x1 + cosβ * y1

    I won’t go into details about why this formula works, but you can read about it here.

    Specifying axis


    In order to rotate a 3d object, we need an axis to rotate it around. Take a look at the dice below :

    It is laid out like the following :

    Now imagine we want to rotate it so that we see other numbers. In order to do this, we need an axis to rotate it around. Imagine we stick a toothpick throw this dice from 5 to 6 like the following :

    Now we can rotate the dice 90° down and we end up with something like this :

    [Note: If anyone has any tips or can in any way help me improve these illustrations, it’d be much appreciated]

    The math


    When it comes to the actual math, it’s a bit more complicated. I won’t be explaining where we get the matrices for rotation, but if you’re interested, you can read more about it here.

    Like with translating and scaling, we use a matrix to do the rotation. But the matrix itself is a bit complex and is a little different depending on which axis you rotate :

    For X axis

    \begin{bmatrix}
    1 & \phantom{-}0 & 0 & 0\\
    0 & \phantom{-}cos\phantom{-}θ & sin\phantom{-}θ & 0\\
    0 & -sin\phantom{-}θ & cos\phantom{-}θ & 0\\
    0 & \phantom{-}0 & 0 & 1\\
    \end{bmatrix}

    For Y axis

    \begin{bmatrix}
    cos\phantom{-}θ & 0 & -sin\phantom{-}θ & 0\\
    0 & 1 & 0 & 0\\
    sin\phantom{-}θ & 0 & \phantom{-}cos\phantom{-}θ & 0\\
    0 & 0 & 0 & 1\\
    \end{bmatrix}

    For Z axis

    \begin{bmatrix}
    cos\phantom{-}θ & -sin\phantom{-}θ & 0 & 0\\
    sin\phantom{-}θ & \phantom{-}cos\phantom{-}θ & 0 & 0\\
    0 & 0 & 1 & 0\\
    0 & 0 & 0 & 1\\
    \end{bmatrix}

    Why are they so different


    The reason why they are different is how they multiply with the unit matrix

    \begin{bmatrix}
    1 & 0 & 0 & 0\\
    0 & 1 & 0 & 0\\
    0 & 0 & 1 & 0\\
    0 & 0 & 0 & 1\\
    \end{bmatrix}

    You’ll see that the formula for rotating around the x axis :

    \begin{bmatrix}
    1 & \phantom{-}0 & 0 & 0\\
    0 & \phantom{-}cos\phantom{-}θ & sin\phantom{-}θ & 0\\
    0 & -sin\phantom{-}θ & cos\phantom{-}θ & 0\\
    0 & \phantom{-}0 & 0 & 1\\
    \end{bmatrix}

    Has the same first column and row [1, 0, 0, 0] as the unit matrix. If you look at how matrices are multiplied, you’ll see that this won’t change the final x coordinate

    And if you look at the matrices for rotating around y and z, you’ll see the same. The y rotation matrix has the same second column and row as the unit matrix [ 0, 1, 0, 0 ] and the one for z axis has the same third column and row as the unit matrix [ 0, 0, 0, 1]. This means that rotating around z axis doesn’t change the z coordinate, and rotating around the y axis doesn’t change the y coordinate

    Imagine putting a dice on a table. Now turn the dice clockwise or counter-clockwise without lifting the dice in any way. If you define the z axis to be the height above the table, you’re now rotating the dice around the Z axis. And since you’re not lifting it, the z coordinate remains the same.

    Example


    Let’s make a matrix for rotating the point [2,4, 8] by 30 degrees around the x axis.

    As you can see, the y and z coordinates have changed, but the x coordinate is the same. This is due to how matrix multiplication work.

    Other axis


    You might wonder; what if I want to move the object around a combination of two or three axes? Well, that’s a bit more complex, and I won’t go into the math here. But we’ll see how we can use glm to specify an exact axis of rotation below

    Putting it all together


    Before we look at how to do these operations using code, we need to look at how to do it by hand. Or by online matrix calculators in this case… Buy why? As I mentioned earlier, ordering is important here. Do things in the wrong order, and you get weird results.

    In the previous post, we looked at object space, world space, view/camera space camera and projection space. Let’s skip the last two for now and focus on the object and world space.

    Remember that object space is basically the model represented as a set of coordinates around origin [0, 0, 0] and that world space is the position of the object in the game world. So if the object has moved 10 units to the right, it’ll have the position [0, 10, 0] which means we have to move it there. This is where the translation matrix comes in! The object could also have turned around ( rotated ) and grown (scaled). Since the object is defined in object space ( vectors around [0,0,0] ) and this will never change, we need to move/scale and rotate the object every time. So we need to multiply every coordinate with this matrix in order to place/scale/rotate it correctly.

    Luckily we can just multiply the matrices together and reuse this matrix until the object moves. But this is also where we need to be careful about getting the orientation right. Let’s start by moving and scaling.

    Example – Wrong way


    Say we want to scale by 2 units in every direction and move 3 unites in every direction. Remember that the scale matrix looks like this :

    \begin{bmatrix}
    sx & 0 & 0 & 0\\
    0 & sy & 0 & 0\\
    0 & 0 & sz & 0\\
    0 & 0 & 0 & 1
    \end{bmatrix}

    Filling in numbers :

    \begin{bmatrix}
    2 & 0 & 0 & 0\\
    0 & 2 & 0 & 0\\
    0 & 0 & 2 & 0\\
    0 & 0 & 0 & 1
    \end{bmatrix}

    And translation matrix

    \begin{bmatrix}
    \,\ 1\quad 0\quad 0\quad dx\\
    \,\ 0\quad 1\quad 0\quad dy\\
    \,\ 0\quad 0\quad 1\quad dz\\
    0\quad 0\quad 0\quad 1\\
    \end{bmatrix}

    Filling in the numbers, we get :

    \begin{bmatrix}
    \,\ 1\quad 0\quad 0\quad 3\\
    \,\ 0\quad 1\quad 0\quad 3\\
    \,\ 0\quad 0\quad 1\quad 3\\
    0\quad 0\quad 0\quad 1\\
    \end{bmatrix}

    Now let’s multiply them :

    Let’s analyse this. Looking at the scale numbers, we see 2, 2, 2 as we expected. But when we look at the translation, we see 6, 6, 6! That’s wrong! We wanted 3, 3, 3, not 6, 6, 6!

    The reason why this happens is that we multiplied by scale first when we should have started with the translation instead. So let’s reverse the order of the operations and try again

    That’s more like it. We see that we move by 3 and scale by a factor of 2.

    When we add rotation, we can run into the same problem. Imagine if the object is first moved, then rotated we would still move around the origin(0,0,0). But since we already have moved the object away from the origin, we’ll orbit the origin ( much like a planet ) instead.

    The correct order


    In our example ( and in most cases ) the correct order is scale -> translate -> rotate. You might think it would be the other way around, but matrix operations are in the opposite order of what you expected. So you start out with the last thing you want to happen ( scale ) and end with the first (rotate)

    Using glm to do matrix operations


    Luckily, we don’t have to do all of this ourselves. In fact, glm does nearly all the math for us. Including rotation ( fortunately )All of these methods takes a glm 4×4 matrix, called mat4 this is basically just a 4×4 array representing a matrix.

    You can find the documentation here.

    glm::translate


    Takes a matrix, translates it and returns it.

    Parameters :

    • glm::mat4 original – the matrix you want to translate
    • glm::vec3 dist – the distance to move

    Return :

    The original matrix original translated by dist like we looked at earlier

    glm::scale


    Takes a matrix and scales it and returns it

    Parameters :

    • glm::mat4 original – the matrix you want to scale
    • glm::vec3 scale – the factors to scale by

    Return :

    The original matrix original scaled by scale matrix like we looked at earlier

    glm::rotate


    Takes a matrix and rotates it around an axis and returns it

    Parameters :

    • glm::mat4 original – the matrix you want to scale
    • double angle – the amount/angle you want to rotate by ( radians )
    • glm::vec3 axis – the axis to rotate by

    Return :

    The original matrix original rotated by angle around the axis, axis like we looked at earlier

    Putting it all together


    Now that we have looked at the functions, we can easily put them all together.

    This is a simple class that shows how you can use all the operations we’ve looked at.

    File notes


    You can find the source code for an application that lets you move/scale/rotate a cubehere.

    Images with colored matrix/vector multiplications has been made using calcul.com

    Dice illustration has been made using Inkscape


    Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

    You can also email me : olevegard@headerphile.com
    Share