投影转换有什么不同?

时间:2014-11-02 04:21:19

标签: opengl

这是此Why doesn't this viewing/projection transform work?之前帖子的后续内容。

出于实验目的,每次窗口绘制时,此代码都会在OpenGL计算的变换和我手动计算的变换之间翻转。它第一次跟踪OpenGL中的Projection和ModelView矩阵值,所以我可以自己使用它们。

如果我注释掉Projection变换,视觉输出是相同的。但是使用投影变换,它是'接近但不精确'#34; (看起来有点扭曲。)

由于所有其他转换工作使用相同的逻辑,我相信我的数学,列与行,转置等是合理的(与我之前的帖子相反),并且必须有一些投影变换的概念差异让我望而却步。有什么建议吗?

#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();
}

1 个答案:

答案 0 :(得分:1)

我没有完全研究你写的部分来测试和比较这两个选项。但是你的矩阵*向量乘法存在一个问题:

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];

tempW的计算缺少与向量分量的乘法,而只是将矩阵元素相加。它应该是:

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

整个事情是4x4矩阵与4个成员向量(x, y, z, 1)的简单乘法。结果的每个分量是带有向量的矩阵行的标量积。结果的w分量与所有其他分量的计算方法相同。