Question

Recently i implemented a simple Opengl program that composes of a scene of objects, i've applied most of the transformation & projection matrices, in such away that i am able to rotate transform & scale objects, move my camera through z & x coordinates and applied perspective projection however when it comes to camera rotation things get weird, my rotation matrix for my camera is simply a rotation matrix that rotates the world uniformly, however when i rotate the world so that i look in the up direction;+y; and when i move forward, the camera doesn't seem to advance in the direction where it is looking at;as it is the case in FPS games my camera moves relative to the world space, i know that i am missing the vectors that specify directions in x,y,z coordinates, but i am unable to incorporate these vectors with my camera (view Transformation) matrix, most of the tutorial on internet either describes it in a block diagram or uses the conventional gluLookAt() function, i really need a brief explanation about view Transformations and specifically camera rotation and how i should implement it in my matrices, my my final matrix is as follows:

resultTransform = perspectiveTrans * cameraTrans * modelTrans;

where:

perspectiveTrans = applies only a perspective projection transformation

cameraTrans = is a combination of rotate,translate matrices that affect all obj.s in the scene

modelTrans =is the transformation that is applied to the models

Matrix4X4.cpp file:

#include "Matrix4X4.h"

using namespace std;


////////////////////////////////// Constructor Declerations ////////////////////////////////

Matrix4X4::Matrix4X4()
{
setIdentity();
}

Matrix4X4::Matrix4X4(float value)
{
for(int i = 0 ; i < 4; i++)
    for ( int j = 0; j < 4; j++)
        Matrix[i][j] = value;

}

/////////////////////////////////////////////////////////////////////////////////







////////////////////////////// Destructor Decleration //////////////////////////////
Matrix4X4::~Matrix4X4()
{

}

///////////////////////////////////////////////////////////////////////////////////







/////////////////////// Set Identity Matrix /////////////////////////////////////////

void Matrix4X4::setIdentity()
{
Matrix[0][0] =1;   Matrix[0][1] = 0;  Matrix[0][2] = 0;      Matrix[0][3] = 0;
Matrix[1][0] =0;   Matrix[1][1] = 1;  Matrix[1][2] = 0;      Matrix[1][3] = 0;
Matrix[2][0] =0;   Matrix[2][1] = 0;  Matrix[2][2] = 1;      Matrix[2][3] = 0;
Matrix[3][0] =0;   Matrix[3][1] = 0;  Matrix[3][2] = 0;      Matrix[3][3] = 1;


}

///////////////////////////////////////////////////////////////////////////////////






///////////////////////// Set Translation Matrix //////////////////////////////////

Matrix4X4 Matrix4X4::setTranslation(float x,float y,float z)
{


Matrix[0][0] =1;   Matrix[0][1] = 0;  Matrix[0][2] = 0;      Matrix[0][3] = x;
Matrix[1][0] =0;   Matrix[1][1] = 1;  Matrix[1][2] = 0;      Matrix[1][3] = y;
Matrix[2][0] =0;   Matrix[2][1] = 0;  Matrix[2][2] = 1;      Matrix[2][3] = z;
Matrix[3][0] =0;   Matrix[3][1] = 0;  Matrix[3][2] = 0;      Matrix[3][3] = 1;

return  *this;

}
/////////////////////////////////////////////////////////////////////////////////





////////////////////////////////////// Set Rotation Matrix     ///////////////////////////////////////////

Matrix4X4 Matrix4X4::setRotation(float x,float y,float z)
{
Matrix4X4 xRot;
Matrix4X4 yRot;
Matrix4X4 zRot;

x = (float)x * 3.14/ 180.0;
y = (float)y * 3.14/ 180.0;
z = (float)z * 3.14/ 180.0;



xRot.Matrix[0][0] =1;         xRot.Matrix[0][1] = 0;        xRot.Matrix[0][2] = 0;            xRot.Matrix[0][3] = 0;
xRot.Matrix[1][0] =0;         xRot.Matrix[1][1] = cosf(x);  xRot.Matrix[1][2] = -sinf(x);   xRot.Matrix[1][3] = 0;
xRot.Matrix[2][0] =0;         xRot.Matrix[2][1] = sinf(x);  xRot.Matrix[2][2] = cosf(x);    xRot.Matrix[2][3] = 0;
xRot.Matrix[3][0] =0;         xRot.Matrix[3][1] = 0;        xRot.Matrix[3][2] = 0;          xRot.Matrix[3][3] = 1;

yRot.Matrix[0][0] = cosf(y);  yRot.Matrix[0][1] = 0;        yRot.Matrix[0][2] = -sinf(y);   yRot.Matrix[0][3] = 0;
yRot.Matrix[1][0] =0;         yRot.Matrix[1][1] = 1;        yRot.Matrix[1][2] = 0;          yRot.Matrix[1][3] = 0;
yRot.Matrix[2][0] = sinf(y);  yRot.Matrix[2][1] = 0;        yRot.Matrix[2][2] = cosf(y);    yRot.Matrix[2][3] = 0;
yRot.Matrix[3][0] =0;         yRot.Matrix[3][1] = 0;        yRot.Matrix[3][2] = 0;          yRot.Matrix[3][3] = 1;

zRot.Matrix[0][0] = cosf(z);  zRot.Matrix[0][1] = -sinf(z); zRot.Matrix[0][2] = 0;          zRot.Matrix[0][3] = 0;
zRot.Matrix[1][0] = sinf(z);  zRot.Matrix[1][1] = cosf(z);  zRot.Matrix[1][2] = 0;          zRot.Matrix[1][3] = 0;
zRot.Matrix[2][0] =0;         zRot.Matrix[2][1] = 0;        zRot.Matrix[2][2] = 1;          zRot.Matrix[2][3] = 0;
zRot.Matrix[3][0] =0;         zRot.Matrix[3][1] = 0;        zRot.Matrix[3][2] = 0;          zRot.Matrix[3][3] = 1;


return (zRot * yRot * xRot) ;

}

////////////////////////////////////////////////////////////////////////////////////////////////////






//////////////////////////////////////// Set Scale Matrix //////////////////////////////////////////

Matrix4X4 Matrix4X4::setScale(float x,float y,float z)
{


Matrix[0][0] =x;   Matrix[0][1] = 0;  Matrix[0][2] = 0;      Matrix[0][3] = 0;
Matrix[1][0] =0;   Matrix[1][1] = y;  Matrix[1][2] = 0;      Matrix[1][3] = 0;
Matrix[2][0] =0;   Matrix[2][1] = 0;  Matrix[2][2] = z;      Matrix[2][3] = 0;
Matrix[3][0] =0;   Matrix[3][1] = 0;  Matrix[3][2] = 0;      Matrix[3][3] = 1;

return *this;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////





///////////////////////////////// Set Perspective Projection ///////////////////////////////////////

void Matrix4X4::setPerspective(float fov,float aRatio,float zNear,float zFar)
{


fov = (fov/2) * 3.14 / 180.0;
float tanHalfFOV = tanf(fov);
float zRange = zNear - zFar;


 Matrix[0][0] =1.0f / (tanHalfFOV * aRatio);   Matrix[0][1] = 0;                  Matrix[0][2] = 0;                         Matrix[0][3] = 0;
 Matrix[1][0] =0;                              Matrix[1][1] = 1.0f / tanHalfFOV;  Matrix[1][2] = 0;                         Matrix[1][3] = 0;
 Matrix[2][0] =0;                              Matrix[2][1] = 0;                  Matrix[2][2] = (-zNear - zFar)/ zRange;   Matrix[2][3] = 2* zFar * zNear / zRange;
 Matrix[3][0] =0;                              Matrix[3][1] = 0;                  Matrix[3][2] = 1;                         Matrix[3][3] = 0;



}
/////////////////////////////////////////////////////////////////////////////////////////////////////////





////////////////////////////////////// Getters & Setters ////////////////////////////////////////////

float * Matrix4X4::getMat()
{
return (float *) Matrix;
}


float Matrix4X4::getMember(int x, int y) const
{
return Matrix[x][y];
}


void Matrix4X4::setMat(int row,int col,float value)
{
Matrix[row][col] = value;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////






/////////////////////////////////////// (*) Operator Overload //////////////////////////////////////

Matrix4X4 operator * (const Matrix4X4 & lhs,const Matrix4X4 & rhs)
{

Matrix4X4 result;

    for(int i = 0 ; i < 4; i++)
        for ( int j = 0; j < 4; j++)
            result.setMat(i, j,  lhs.getMember(i,0) * rhs.getMember(0, j) +
                            lhs.getMember(i,1) * rhs.getMember(1, j) +
                            lhs.getMember(i,2) * rhs.getMember(2, j) +
                            lhs.getMember(i,3) * rhs.getMember(3, j));


        return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////////

the Transformation code i use in my main block:

        SDL_PumpEvents();

        for (int x = 0; x< 256; x++)
        {
            if (state[x] == 1 )
            {
                if(x  == 26)
                    tranForward -= 0.001;
                if (x == 22)
                    tranForward += 0.001;
                if (x == 4)
                    tranRight += 0.0009;
                if (x == 7)
                    tranRight -= 0.0009;

                if (x == 82)
                    lookUp += 0.02;
                if (x == 81)
                    lookUp -= 0.02;
                if (x == 80)
                    lookRight -= 0.02;
                if (x == 79)
                    lookRight += 0.02;
            }
        }





        modelTrans =  Translation.setTranslation(0, 0, 5) * Scale.setScale(0.5, 0.5, 0.5);
        camTrans   =  Rotation.setRotation(lookUp, lookRight, 0) * Translation.setTranslation(tranRight, 0, tranForward);
        Projection.setPerspective(70, win.getWidth()/win.getHeight(), 0.1, 1000);


        result =  Projection * camTrans * modelTrans;




       glUniformMatrix4fv(uniformloc, 1, GL_TRUE, result.getMat());
Was it helpful?

Solution

The matrix multiplication does not have the same rules as the scalar multiplication and in your case A*B does NOT equal B*A when multiplying the matrices. If rest of the code is good your solution might simply be turning

result =  Projection * camTrans * modelTrans;

into

result =  Projection * (modelTrans * camTrans);

Do alway watch out for both, multiplication order and parentheses when dealing with anything but scalar values.

In general when you are combining a translation and rotation matrix you need to think in matrix own space coordinate system, that means like playing a FPS:

Multiplying rotation*translation means the object will rotate first and then translate meaning the object position will depend on the rotation being already applied and a 180 degrees rotation will translate the object backwards from the 3rd view perspective.

Multiplying translation*rotation means the object will translate first and then rotate meaning it will in fact be moved into the same direction no matter the rotation, only the direction of where the object is facing will be changed by rotation matrix.

Just a nice example, if you want to present a movement of earth around sun (the earth is circling the sun while rotating around its own axis being on some radius):

    Matrix4X4 orbitRotation; //rotation matrix for where in orbit the object is
    Matrix4X4 objectRotation; //object rotation around its own axis
    Matrix4X4 orbitRadius; //object orbit radius

    Matrix4X4 result = (orbitRotation*orbitRadius)*objectRotation;

OTHER TIPS

my code seemed to ignore the previous matrix calculation and re calculated the transformations with respect to my scene's initial state, the desired world rotation & Translation is achieved by using a fixed value for rotation & Translation, the modified code blocks are as follows:

      for (int x = 0; x< 256; x++)
        {
            if (state[x] == 1 )
            {
                if(x  == 26)
                    tranForward = -0.001;
                if (x == 22)
                    tranForward = 0.001;
                if (x == 4)
                    tranRight = 0.0009;
                if (x == 7)
                    tranRight = -0.0009;

                if (x == 82)
                    lookUp = 0.02;
                if (x == 81)
                    lookUp = -0.02;
                if (x == 80)
                    lookRight = -0.02;
                if (x == 79)
                    lookRight = 0.02;
            }
        }

camTrans   =   Rotation.setRotation(lookUp, lookRight, 0) * Translation.setTranslation(tranRight, 0, tranForward);

        result =   camTrans * result;

        modelTrans = Projection * result;



        tranForward = 0.0;
        tranRight   = 0.0;
        lookUp      = 0.0;
        lookRight   = 0.0;

       glUniformMatrix4fv(uniformloc, 1, GL_TRUE, modelTrans.getMat());

note that result matrix keeps track of the previous state and the current state transformations are applied with respect to it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top