1
votes

So I am trying to multiply rotation and translation matrices together and I can't quite figure out what is going wrong.

If, in the program I multiply a translation matrix by a rotation matrix then send that matrix as a uniform to my shader program I end up with the object becoming 2D then 3D again as it spins [ https://a.pomf.se/xvvrsg.mp4 ] (object on the right).

shader.setUniformMat4("model_matrix", Matrix4::translation(Vector3(10.0f, 0.0f, 0.0f)) * Matrix4::rotation(rotation, Vector3(0.0f, 1.0f, 0.0f)));

(vertex shader)

#version 330 core

layout (location = 0) in vec4 in_position;
layout (location = 1) in vec4 in_normal;

uniform mat4 pr_matrix;
uniform mat4 vw_matrix = mat4(1.0);
uniform mat4 model_matrix = mat4(1.0);

out vec4 pos;
out vec4 normal;

void main()
{
    pos = pr_matrix * vw_matrix * model_matrix * in_position;

    normal = in_normal;
    gl_Position = pos;
}

However if I send my individual translation and rotation matrices as separate uniforms and then multiply them in the shader to create my model matrix it works as intended [ https://a.pomf.se/jyxpnb.mp4 ] (object on the right).

shader.setUniformMat4("translation_matrix", Matrix4::translation(Vector3(10.0f, 0.0f, 0.0f)));
shader.setUniformMat4("rotation_matrix", Matrix4::rotation(rotation, Vector3(0.0f, 1.0f, 0.0f)));
shader.setUniformMat4("scale_matrix", Matrix4::identity());

(vertex shader)

#version 330 core

layout (location = 0) in vec4 in_position;
layout (location = 1) in vec4 in_normal;

uniform mat4 pr_matrix;
uniform mat4 vw_matrix = mat4(1.0);
uniform mat4 translation_matrix = mat4(1.0);
uniform mat4 rotation_matrix = mat4(1.0);
uniform mat4 scale_matrix = mat4(1.0);

out vec4 pos;
out vec4 normal;

void main()
{
    mat4 model_matrix = translation_matrix * rotation_matrix * scale_matrix;
    pos = pr_matrix * vw_matrix * model_matrix * in_position;

    normal = in_normal;
    gl_Position = pos;
}

This leads me to believe that there must be an error in my multiplication of matrices, this is how I am currently doing it:

        Matrix4 &Matrix4::multiply(const Matrix4 &other)
        {
            elements[0] = elements[0]  * other.elements[0]  + elements[4] * other.elements[1]  + elements[8]  * other.elements[2]  + elements[12] * other.elements[3];
            elements[1] = elements[1]  * other.elements[0]  + elements[5] * other.elements[1]  + elements[9]  * other.elements[2]  + elements[13] * other.elements[3];
            elements[2] = elements[2]  * other.elements[0]  + elements[6] * other.elements[1]  + elements[10] * other.elements[2]  + elements[14] * other.elements[3];
            elements[3] = elements[3]  * other.elements[0]  + elements[7] * other.elements[1]  + elements[11] * other.elements[2]  + elements[15] * other.elements[3];
            elements[4] = elements[0]  * other.elements[4]  + elements[4] * other.elements[5]  + elements[8]  * other.elements[6]  + elements[12] * other.elements[7];
            elements[5] = elements[1]  * other.elements[4]  + elements[5] * other.elements[5]  + elements[9]  * other.elements[6]  + elements[13] * other.elements[7];
            elements[6] = elements[2]  * other.elements[4]  + elements[6] * other.elements[5]  + elements[10] * other.elements[6]  + elements[14] * other.elements[7];
            elements[7] = elements[3]  * other.elements[4]  + elements[7] * other.elements[5]  + elements[11] * other.elements[6]  + elements[15] * other.elements[7];
            elements[8] = elements[0]  * other.elements[8]  + elements[4] * other.elements[9]  + elements[8]  * other.elements[10] + elements[12] * other.elements[11];
            elements[9] = elements[1]  * other.elements[8]  + elements[5] * other.elements[9]  + elements[9]  * other.elements[10] + elements[13] * other.elements[11];
            elements[10] = elements[2] * other.elements[8]  + elements[6] * other.elements[9]  + elements[10] * other.elements[10] + elements[14] * other.elements[11];
            elements[11] = elements[3] * other.elements[8]  + elements[7] * other.elements[9]  + elements[11] * other.elements[10] + elements[15] * other.elements[11];
            elements[12] = elements[0] * other.elements[12] + elements[4] * other.elements[13] + elements[8]  * other.elements[14] + elements[12] * other.elements[15];
            elements[13] = elements[1] * other.elements[12] + elements[5] * other.elements[13] + elements[9]  * other.elements[14] + elements[13] * other.elements[15];
            elements[14] = elements[2] * other.elements[12] + elements[6] * other.elements[13] + elements[10] * other.elements[14] + elements[14] * other.elements[15];
            elements[15] = elements[3] * other.elements[12] + elements[7] * other.elements[13] + elements[11] * other.elements[14] + elements[15] * other.elements[15];
            return *this;
        }

I did have a nested loop to do this but I ended up writing it all out while trying to find out an answer to this problem. Bear in mind the matrices are in column major and do not get transposed by OpenGL

The rotation and translation matrices are as follows but I don't believe there is any problem with them:

        Matrix4 Matrix4::translation(const Vector3 &translation)
        {
            Matrix4 result(1.0f);
            result.elements[0 + 3 * 4] = translation.x;
            result.elements[1 + 3 * 4] = translation.y;
            result.elements[2 + 3 * 4] = translation.z;
            return result;
        }

        Matrix4 Matrix4::rotation(float angle, const Vector3 &axis)
        {
            Matrix4 result(1.0f);
            float r = toRadians(angle);
            float c = (float)cos(r);
            float s = (float)sin(r);
            float cFlip = 1.0f - c;

            result.elements[0 + 0 * 4] = axis.x * cFlip + c;
            result.elements[1 + 0 * 4] = axis.y * axis.x * cFlip + axis.z * s;
            result.elements[2 + 0 * 4] = axis.x * axis.z * cFlip - axis.y * s;

            result.elements[0 + 1 * 4] = axis.x * axis.y * cFlip - axis.z * s;
            result.elements[1 + 1 * 4] = axis.y * cFlip + c;
            result.elements[2 + 1 * 4] = axis.y * axis.z * cFlip + axis.x * s;

            result.elements[0 + 2 * 4] = axis.x * axis.y * cFlip + axis.y * s;
            result.elements[1 + 2 * 4] = axis.y * axis.z * cFlip - axis.x * s;
            result.elements[2 + 2 * 4] = axis.z * cFlip + c;
            return result;
        }

Any ideas on what the problem here could be or how to fix it would be greatly appreciated :^)

2
you show us function multiply but use operator* to do the actual multiplication, is this just a little typing mistake ?Guiroux
the operator is overloaded, my mistake for not adding it in :)Yen

2 Answers

2
votes

At your multiply function, you wrote:

elements[0] = elements[0]  * other.elements[0] ...
...

Notice that element[0] got its contents actualized now and then you do:

elements[8] = elements[0]  * other.elements[8] ...

which use the new value and not the original one. I guess, you want to make a copy of your original matrix before doing this multiplication

1
votes

opssss !! i just saw !!! in your multiply, your output matrice is the first input matrix, so the latest operations are calculated with coefficient of the multiplied matrix !! :

elements[0] = elements[0]  * .....
....       
elements[4] = elements[0]  * ..... /* here element[ 0 ] is the top left
                                      element of the multiplied matix */

moreover, operator* shouldn't modfify (nor return) one of his operand, operator*= is here for that