GregT
GregT

Reputation: 1320

What's different about the Projection transformation?

This is a follow-up to this Why doesn't this viewing/projection transform work? earlier post.

For experimenting purposes, every time the window draws, this code flips between OpenGL-calculated transforms and ones I am calculating by hand. The first time it keeps track of the Projection and ModelView matrix values from OpenGL so I can use them when doing it myself.

If I comment out the Projection transform, the visual output is identical. But with the Projection transform, it is "close but not exact" (appears to be sort of twisted around).

Since all the other transforms work using the same logic, I believe my math, column vs. row, transposing etc. is sound (as opposed to my earlier post), and there must be some conceptual difference with Projection transform that is eluding me. Any advice?

#include <iostream>
#include <math.h>
#include "glut.h"
#include "vector3.h"

bool useOpenGL = true;
typedef GLfloat Matrix4x4[4][4];
Matrix4x4 matComposite;

void matrix4x4SetIdentity(Matrix4x4 matIdent4x4){
    GLint row, col;
    for(row = 0; row<4; row++){
        for(col = 0; col<4; col++){
            matIdent4x4[row][col] = (row == col);
        }
    }
}

void matrix4x4PreMultiply(Matrix4x4 m1, Matrix4x4 m2){
    GLint row, col;
    Matrix4x4 matTemp;
    for(row=0; row<4; row++){
        for(col=0; col<4; col++){
            matTemp[row][col] = m1[row][0] * m2[0][col] + 
                                m1[row][1] * m2[1][col] + 
                                m1[row][2] * m2[2][col] + 
                                m1[row][3] * m2[3][col];
        }
    }
    for(row=0; row<4; row++){
        for(col=0; col<4; col++){
            m2[row][col] = matTemp[row][col];
        }
    }
}


vector3 matrixMult(GLfloat x, GLfloat y, GLfloat z){
    if(useOpenGL){
        return vector3(x, y, z);
    } else {
        GLfloat tempX = matComposite[0][0] * x + matComposite[0][1] * y + matComposite[0][2] * z + matComposite[0][3];
        GLfloat tempY = matComposite[1][0] * x + matComposite[1][1] * y + matComposite[1][2] * z + matComposite[1][3];
        GLfloat tempZ = matComposite[2][0] * x + matComposite[2][1] * y + matComposite[2][2] * z + matComposite[2][3];
        GLfloat tempW = matComposite[3][0]     + matComposite[3][1]     + matComposite[3][2]     + matComposite[3][3];
        return vector3(tempX/tempW, tempY/tempW, tempZ/tempW);
    }
}

void transpose(Matrix4x4 mat){
    Matrix4x4 temp;
    for(int i=0;i<4;i++) {
        for(int j=0;j<4;j++) {
            temp[i][j] = mat[j][i];
        }
    }
    for(int i=0;i<4;i++) {
        for(int j=0;j<4;j++) {
            mat[i][j] = temp[i][j];
        }
    }
}

vector3 viewer(-.4, .4, .6);

GLfloat mvm[4][4];
GLfloat pm[4][4];

void storeMatrices(){
    GLfloat got[16];
    glGetFloatv(GL_PROJECTION_MATRIX,got);
    for(int i=0;i<16;i++){
        pm[i/4][i%4] = got[i];
    }
    glGetFloatv(GL_MODELVIEW_MATRIX,got);
    for(int i=0;i<16;i++){
        mvm[i/4][i%4] = got[i];
    }
}

void transformOpenGL(){
    std::cout << "BY OPENGL\n";
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1, 1, -1, 1, .1, 200);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(viewer.x, viewer.y, viewer.z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    // copy matrices before doing model transforms
    storeMatrices();
    // setup scene
    glScalef(.5, 1, 1);
    glTranslatef(.4, .4, 0);
    glScalef(.2, .1, .1);
}

void transformByHand(){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    std::cout << "BY HAND\n";
    matrix4x4SetIdentity(matComposite);
    GLfloat mvm[4][4] = {{0.832050, 0.269069, -0.485071, 0.000000}, {0.000000, 0.874475, 0.485071, 0.000000}, {0.554700, -0.403604, 0.727607, 0.000000}, {0.000000, 0.000000, -0.824621, 1.000000}};
    GLfloat pm[4][4]  = {{0.100000, 0.000000, 0.000000, 0.000000}, {0.000000, 0.100000, 0.000000, 0.000000}, {0.000000, 0.000000, -1.001001, -1.000000,}, {0.000000, 0.000000, -0.200100, 0.000000}};
    // order of transforms is opposite to OpenGL, and,
    // eg. translations go in col[3], not row[3]
    Matrix4x4 scale3 = {{.2, 0, 0, 0}, {0, .1, 0, 0}, {0, 0, .1, 0}, {0, 0, 0, 1}};
    matrix4x4PreMultiply(scale3, matComposite);
    Matrix4x4 translate = {{1, 0, 0, .4}, {0, 1, 0, .4}, {0, 0, 1, 0}, {0, 0, 0, 1}};
    matrix4x4PreMultiply(translate, matComposite);
    Matrix4x4 scale2 = {{.5, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
    matrix4x4PreMultiply(scale2, matComposite);
    transpose(mvm);
    matrix4x4PreMultiply(mvm, matComposite);
    transpose(pm);
    matrix4x4PreMultiply(pm, matComposite);
}

void render() {
    if(useOpenGL){
        transformOpenGL();
    } else {
        transformByHand();
    }
    glColor3f(1, 0, 0);
    glBegin(GL_POLYGON);
        vector3 vpt = matrixMult(0, 0, 0);
        glVertex3f(vpt.x, vpt.y, vpt.z);
        vpt = matrixMult(0, 5, 0);
        glVertex3f(vpt.x, vpt.y, vpt.z);
        vpt = matrixMult(5, 5, 0);
        glVertex3f(vpt.x, vpt.y, vpt.z);
        vpt = matrixMult(0, 5, 0);
        glVertex3f(vpt.x, vpt.y, vpt.z);
    glEnd();
    useOpenGL = !useOpenGL;
}

void display(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    render();
    glutSwapBuffers();
}

void main(int argc, char **argv){
    glutInit( &argc, argv );
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) ;
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    int windowHandle = glutCreateWindow("Testing MVM and PM Matrices");
    glutSetWindow(windowHandle);
    glutDisplayFunc(display);
    glutMainLoop();
}

Upvotes: 0

Views: 57

Answers (1)

Reto Koradi
Reto Koradi

Reputation: 54592

I didn't completely study the part you wrote to test and compare the two options. But there is a problem in your matrix * vector multiplication:

GLfloat tempX = matComposite[0][0] * x + matComposite[0][1] * y +
                matComposite[0][2] * z + matComposite[0][3];
GLfloat tempY = matComposite[1][0] * x + matComposite[1][1] * y +
                matComposite[1][2] * z + matComposite[1][3];
GLfloat tempZ = matComposite[2][0] * x + matComposite[2][1] * y +
                matComposite[2][2] * z + matComposite[2][3];
GLfloat tempW = matComposite[3][0]     + matComposite[3][1]     +
                matComposite[3][2]     + matComposite[3][3];

The calculation of tempW is missing the multiplication with the vector components, and just adds up the matrix elements instead. It should be:

GLfloat tempW = matComposite[3][0] * x + matComposite[3][1] * y +
                matComposite[3][2] * z + matComposite[3][3];

The whole thing is a plain multiplication of a 4x4 matrix with a 4-member vector (x, y, z, 1). Each component of the result is the scalar product of a matrix row with the vector. The w component of the result is calculated the same as all the other components.

Upvotes: 1

Related Questions