Jump to content
  • Advertisement
Sign in to follow this  

matrices and transformations

This topic is 935 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone,


    I am trying to implement my own transformations in my engine. I got both translations and scaling to work but I can't seem to get rotation to work. I am new to matrices and transformations as a whole and this is my first attempt at them.


These are my 2d vector and 3x3 matrix structs and their multiplication operator functions.

union V2f32 {
    struct {
        f32 x;
        f32 y;

    struct {
        f32 w;
        f32 h;

struct Matrix {
    f32 a1, a2, a3;
    f32 b1, b2, b3;
    f32 c1, c2, c3;

inline V2f32 operator*(V2f32 lhs, Matrix rhs) {
    V2f32 temp = {(lhs.x * rhs.a1) + (lhs.y * rhs.a2) + (1 * rhs.a3),
                  (lhs.x * rhs.b1) + (lhs.y * rhs.b2) + (1 * rhs.b3)};
    return temp;

inline void operator*=(V2f32& lhs, Matrix rhs) {
    lhs.x = (lhs.x * rhs.a1) + (lhs.y * rhs.a2) + (1 * rhs.a3);
    lhs.y = (lhs.x * rhs.b1) + (lhs.y * rhs.b2) + (1 * rhs.b3);

inline Matrix operator*(Matrix lhs, Matrix rhs) {
    Matrix temp = {(lhs.a1 * rhs.a1) + (lhs.b1 * rhs.a2) + (lhs.c1 * rhs.a3),
                   (lhs.a1 * rhs.b1) + (lhs.b1 * rhs.b2) + (lhs.c1 * rhs.b3),
                   (lhs.a1 * rhs.c1) + (lhs.b1 * rhs.c2) + (lhs.c1 * rhs.c3),
                   (lhs.a2 * rhs.a1) + (lhs.b2 * rhs.a2) + (lhs.c2 * rhs.a3),
                   (lhs.a2 * rhs.b1) + (lhs.b2 * rhs.b2) + (lhs.c2 * rhs.b3),
                   (lhs.a2 * rhs.c1) + (lhs.b2 * rhs.c2) + (lhs.c2 * rhs.c3),
                   (lhs.a3 * rhs.a1) + (lhs.b3 * rhs.a2) + (lhs.c3 * rhs.a3),
                   (lhs.a3 * rhs.b1) + (lhs.b3 * rhs.b2) + (lhs.c3 * rhs.b3),
                   (lhs.a3 * rhs.c1) + (lhs.b3 * rhs.c2) + (lhs.c3 * rhs.c3)};
    return temp;

Here is the code for a rectangle I want to rotate 45 degrees.

            V2f32 size = {32.0f, 32.0f};
            V2f32 pos = {50.0f, 100.0f};
            V2f32 vertices[4] = {{-size.x / 2, -size.y / 2},
                                 { size.x / 2, -size.y / 2},
                                 { size.x / 2,  size.y / 2},
                                 {-size.x / 2,  size.y / 2}};

            Matrix translation = {1.0f, 0.0f, pos.x,
                                  0.0f, 1.0f, pos.y,
                                  0.0f, 0.0f, 1.0f};

            f32 theta = 45 * (PI / 180);
            Matrix rotation = {cos(theta), -sin(theta), 0.0f,
                               sin(theta),  cos(theta), 0.0f,
                               0.0f,        0.0f,       1.0f};
            Matrix scale = {1.0f, 0.0f, 0.0f,
                            0.0f, 1.0f, 0.0f,
                            0.0f, 0.0f, 1.0f};

            Matrix transform = translation * rotation * scale;

            V4f32 colour = {1.0f, 0.0f, 0.0f, 1.0f};
            PushRect(&renderer, &transform, verticies, &colour, true);

Renderer is an object that contains all the data needed for my renderer to render stuff. The last argument of PushRect(...) is filled and determines if the rectangle is filled or not.


This is a snippet from PushRect(...) which applies the transform on all the vertices, and sets the min and max value and uses those to find the center position and size of the rectangle for rendering.

    V2f32 min, max;

    for(i32 i = 0; i < 4; i++) {
        vertices[i] *= *transform;

        if (i == 0) {
            min = vertices[i];
            max = vertices[i];

        if(vertices[i].x < min.x) {
            min.x = vertices[i].x;
        else if(vertices[i].x > max.x) {
            max.x = vertices[i].x;

        if(vertices[i].y < min.y) {
            min.y = vertices[i].y;
        else if(verticies[i].y > max.y) {
            max.y = vertices[i].y;

    V2f32 size = max - min;
    V2f32 pos = min + (size / 2);

My code doesn't render the rotated rectangle yet it should render a filled axis aligned rectangle around the rotated rectangle, but it doesn't even do that. It renders the rectangle off the screen at (-35.35, 81.06) but should be rendering it at (100, 50). What am I doing wrong? I'm very confused because the translations and scaling work so why doesn't rotation work? 


-- Mathew


Edit: Formatting.

Edited by krusable

Share this post

Link to post
Share on other sites

Hey krusable, 


If I am not wrong, the issue might be because of how you are applying the transformations.


The order of matrix multiplication is not commutative i.e:


A * B is NOT equal to B * A.


When you wish to apply scaling, rotation and translation (in that order) then the transformation must be as such:

vertices[i] = *transform * vertices[i];

as opposed to:

vertices[i] *= *transform;

Think of it as making sure that the multiplication happens in the order that you intend for it to. This way, scaling is applied first, followed by rotation and then translation.

Share this post

Link to post
Share on other sites

To extend on the point made by Sai Narayan, rotation always rotates relative to the origin, rotating a line (100, 0)-(100, 10) in 2D by 90 degrees will end up at (0, 100)-(-10, 100), rather than (100, 0)-(90, 0).


In general, you always first translate the shape to the right spot relative to the origin, then rotate, and translate back.

Edited by Alberth

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!