0
\$\begingroup\$

I have created a 3x3 matrix class which is then passed over to OpenGL Vertex Shader for transform my Quad. I have been trying to rotate my Quad around Z-Axis. Rotation is working but the Quad getting further away from the screen. Below are my Matrix and Vertex Shader source:

Matrix3x3.cpp

#include "matrix3x3.h"
#include "vector2d.h"
#include <cmath>

Matrix3x3::Matrix3x3()
{
    matrix[0][0] = 1.0f;
    matrix[0][1] = 0.0f;
    matrix[0][2] = 0.0f;

    matrix[1][0] = 0.0f;
    matrix[1][1] = 1.0f;
    matrix[1][2] = 0.0f;

    matrix[2][0] = 0.0f;
    matrix[2][1] = 0.0f;
    matrix[2][2] = 1.0f;    
}

void Matrix3x3::setIdentity()
{
    matrix[0][0] = 1.0f;
    matrix[0][1] = 0.0f;
    matrix[0][2] = 0.0f;

    matrix[1][0] = 0.0f;
    matrix[1][1] = 1.0f;
    matrix[1][2] = 0.0f;

    matrix[2][0] = 0.0f;
    matrix[2][1] = 0.0f;
    matrix[2][2] = 1.0f;
}

void Matrix3x3::translate(float tx, float ty, float tz)
{
    float tmpMatrix[3][3];

    tmpMatrix[0][0] = 1.0f;
    tmpMatrix[0][1] = 0.0f;
    tmpMatrix[0][2] = 0.0f;

    tmpMatrix[1][0] = 0.0f;
    tmpMatrix[1][1] = 1.0f;
    tmpMatrix[1][2] = 0.0f;

    tmpMatrix[2][0] = tx;
    tmpMatrix[2][1] = ty;
    tmpMatrix[2][2] = tz;

    mutliply(tmpMatrix);
}

void Matrix3x3::rotate(float angle)
{
    float tmpMatrix[3][3];

    const float radian = 3.141593f / 180 ;//(angle * 3.141592653589793 )/ 180.0;// (2 * PI) / (360.0 / cos(angle));

    float cs = cos(radian * angle);
    float sn = sin(radian * angle);

    tmpMatrix[0][0] = cs;
    tmpMatrix[0][1] = sn;
    tmpMatrix[0][2] = 0.0f;

    tmpMatrix[1][0] = -sn;
    tmpMatrix[1][1] = cs;
    tmpMatrix[1][2] = 0.0f;

    tmpMatrix[2][0] = 0.0f;
    tmpMatrix[2][1] = 0.0f;
    tmpMatrix[2][2] = 1.0f;

    mutliply(tmpMatrix);
}

void Matrix3x3::scale(float sx,float sy)
{
    float tmpMatrix[3][3];

    tmpMatrix[0][0] = sx;
    tmpMatrix[0][1] = 0.0f;
    tmpMatrix[0][2] = 0.0f;

    tmpMatrix[1][0] = 0.0f;
    tmpMatrix[1][1] = sy;
    tmpMatrix[1][2] = 0.0f;

    tmpMatrix[2][0] = 0.0f;
    tmpMatrix[2][1] = 0.0f;
    tmpMatrix[2][2] = 1.0f;

    mutliply(tmpMatrix);
}

void Matrix3x3::transform(vector2d& vec)
{
    /*float tx = vec.x * matrix[0][0] + vec.y * matrix[3] + vec.w * matrix[6];
    float ty = vec.x * matrix[1] + vec.y * matrix[4] + vec.w * matrix[7];
    float tw = vec.x * matrix[2] + vec.y * matrix[5] + vec.w * matrix[8];

    vec.x = tx;
    vec.y = ty;
    vec.w = tw;*/
}

void Matrix3x3::mutliply(const float(&matrixb)[3][3])
{
    /*matrix[0] = (matrix[0] * matrixb[0]) + (matrix[1] * matrixb[3]) + (matrix[2] * matrixb[6]); 
    matrix[1] = (matrix[0] * matrixb[1]) + (matrix[1] * matrixb[4]) + (matrix[2] * matrixb[7]);
    matrix[2] = (matrix[0] * matrixb[2]) + (matrix[1] * matrixb[5]) + (matrix[2] * matrixb[8]);

    matrix[3] = (matrix[3] * matrixb[0]) + (matrix[4] * matrixb[3]) + (matrix[5] * matrixb[6]);
    matrix[4] = (matrix[3] * matrixb[1]) + (matrix[4] * matrixb[4]) + (matrix[5] * matrixb[7]);
    matrix[5] = (matrix[3] * matrixb[2]) + (matrix[4] * matrixb[5]) + (matrix[5] * matrixb[8]);

    matrix[6] = (matrix[6] * matrixb[0]) + (matrix[7] * matrixb[3]) + (matrix[8] * matrixb[6]);
    matrix[7] = (matrix[6] * matrixb[1]) + (matrix[7] * matrixb[4]) + (matrix[8] * matrixb[7]);
    matrix[8] = (matrix[6] * matrixb[2]) + (matrix[7] * matrixb[5]) + (matrix[8] * matrixb[8]);*/

    for (int x = 0; x<3; ++x)
        for (int y = 0; y<3; ++y)
        {
            float sum = 0;
            for (int z = 0; z<3; ++z)
                sum += matrix[x][z] * matrixb[z][y];

            matrix[x][y] = sum;
        }
}

ostream& operator<<(ostream& os,Matrix3x3& matrix)
{
    os << matrix.matrix[0][0] << " " << matrix.matrix[0][1] << " " << matrix.matrix[0][2] << std::endl;
    os << matrix.matrix[1][0] << " " << matrix.matrix[1][1] << " " << matrix.matrix[1][2] << std::endl;
    os << matrix.matrix[2][0] << " " << matrix.matrix[2][1] << " " << matrix.matrix[2][2] << std::endl;

    return os;
}


float* Matrix3x3::getPtr()
{
    return &matrix[0][0];
}

vertex_shader.glsl

#version 330 core

layout (location = 0) in vec3 position;

uniform mat3 transform;

void main()
{
    gl_Position = vec4(transform  * vec3(position.x,position.y,0.0) , 1.0);
}

This is where i am using my matrix in the Quad class:

void Quad::rotate(float angle2)
{

    glUseProgram(shader->getProgramId());   
    this->transformMatrix->rotate(angle);   

    shader->setUniformMatrix3("transform", this->transformMatrix->getPtr());        
}

I have also tried to debug my GLSL shader to check the gl_Position . But its shows that my Z-Axis is always zero and W component is always 1. No idea why its getting away from my screen.

\$\endgroup\$
1
  • \$\begingroup\$ probably some accumulative rounding errors. check the values of the matrix and ensure that the length of the collums are consistent and the first two are orthogonal \$\endgroup\$ Jan 6, 2016 at 11:07

2 Answers 2

2
\$\begingroup\$

The quad is getting further away due to rounding errors in the cumulative matrix operations (it's actually getting scaled down).

You must either normalize the matrix or use a rotation angle variable and recreate the rotation matrix from that variable on every frame.

For the translation you must use vec3(position.x, position.y, 1.0) so that your last row becomes the translation.

Setting it to 0.0 multiplies the whole matrix row by 0.0 which nullifies your translation.

Because

transform  * vec3(position.x, position.y, 0.0)

is the same as

transform[0] * position.x + transform[1] * position.y + transform[2] * 0.0
\$\endgroup\$
4
  • \$\begingroup\$ Thanks for the Answer that makes sense. Now i have changed it into the create rotation matrix each frame. Scaling is fixed , but now i am facing another issue, my quad rotates around z-axis for some angle but after a while its started to rotate around other axis also. \$\endgroup\$
    – aaa111
    Jan 7, 2016 at 5:56
  • \$\begingroup\$ Make sure to wrap around the rotation values between 0 and full circle (2*pi if it's in radians) this is another case of rounding issues with floating points. \$\endgroup\$ Jan 7, 2016 at 13:29
  • \$\begingroup\$ Can you elaborate a little more please. \$\endgroup\$
    – aaa111
    Jan 7, 2016 at 13:55
  • \$\begingroup\$ sin/cos and other functions can get less and less precise as the numbers get larger. It's the nature of floating point numbers that causes this. 2*pi is a full circle so the rotation value can be wrapped-around at that point to keep the angle from getting too large. use current_angle = fmodf(current_angle + change, 2*M_PI); every time you change the rotation angle so the value stays between -2*pi and 2*pi. \$\endgroup\$ Jan 8, 2016 at 6:32
1
\$\begingroup\$

After spending whole day i finally found out whats the issue actually. Its really silly of me that its got overlooked at the very first place. So here is the problem :

matrix[1][1] = (matrix[1][0] * matrixb[0][1]) + (matrix[1][1] * matrixb[1][1]) + (matrix[1][2] * matrixb[2][1]);

Here i am setting matrix[1][1] to a new value. But in the next line i need to multiply the matrix[1][1] which need the old value

 matrix[1][2] = (matrix[1][0] * matrixb[0][2]) + (matrix[1][1] * matrixb[1][2]) + (matrix[1][2] * matrixb[2][2]);

So now what i did is i am multiplying the matrix using temporaries again and copy the values over the root matrix.

void Matrix3x3::mutliply(const float(&matrixb)[3][3])
{
    float tmat[3][3];

    tmat[0][0] = (matrix[0][0] * matrixb[0][0]) + (matrix[0][1] * matrixb[1][0]) + (matrix[0][2] * matrixb[2][0]);
    tmat[0][1] = (matrix[0][0] * matrixb[0][1]) + (matrix[0][1] * matrixb[1][1]) + (matrix[0][2] * matrixb[2][1]);
    tmat[0][2] = (matrix[0][0] * matrixb[0][2]) + (matrix[0][1] * matrixb[1][2]) + (matrix[0][2] * matrixb[2][2]);

    tmat[1][0] = (matrix[1][0] * matrixb[0][0]) + (matrix[1][1] * matrixb[1][0]) + (matrix[1][2] * matrixb[2][0]);
    tmat[1][1] = (matrix[1][0] * matrixb[0][1]) + (matrix[1][1] * matrixb[1][1]) + (matrix[1][2] * matrixb[2][1]);
    tmat[1][2] = (matrix[1][0] * matrixb[0][2]) + (matrix[1][1] * matrixb[1][2]) + (matrix[1][2] * matrixb[2][2]);

    tmat[2][0] = (matrix[2][0] * matrixb[0][0]) + (matrix[2][1] * matrixb[1][0]) + (matrix[2][2] * matrixb[2][0]);
    tmat[2][1] = (matrix[2][0] * matrixb[0][1]) + (matrix[2][1] * matrixb[1][1]) + (matrix[2][2] * matrixb[2][1]);
    tmat[2][2] = (matrix[2][0] * matrixb[0][2]) + (matrix[2][1] * matrixb[1][2]) + (matrix[2][2] * matrixb[2][2]);

    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 3; ++j)
            matrix[i][j] = tmat[i][j];
    }
}

Now all is working great. Only thing i need to do now is to find a way to optimize my matrix class.

\$\endgroup\$
1
  • \$\begingroup\$ You may want to consider using an existing battle-hardened library like MathGeoLib or GLM once you've sated your desire to handroll them. Finding subtle bugs in your math operations grows tiresome after a while. If you still insist on having your own, your tests could still use libraries to get ground truth to verify your operations against. \$\endgroup\$ Jan 9, 2016 at 3:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .