我是否正确地创造了视角和透视矩阵?

时间:2016-04-24 08:47:09

标签: c opengl matrix

我编写了OpenGl Super Bible的例子https://github.com/openglsuperbible/sb7code/blob/master/src/grass/grass.cpp 用C和freeglut。结果是点在视图之外。

我是否正确计算并使用了外观和透视矩阵?

渲染功能的一部分:

Matrix proj=CreateProjectionMatrix(45.0f,CurrentWidth/CurrentHeight,0.1f,1000.0f);

float t=glutGet(GLUT_ELAPSED_TIME)*0.002f;
float eye[]={sinf(t)*550.0f,25.0f,cosf(t)*550.0f};
float center[]={0.0f,-50.0f,0.0f};
float up[]={0.0f,1.0f,0.0f};
Matrix look=lookAt(eye,center,up);

Matrix final=MultiplyMatrices(&proj,&look);

glUniformMatrix4fv(UniformsMvpMatrix,1,GL_FALSE,final.m);

计算:

typedef struct Matrix{
  GLfloat m[16];
}Matrix;

Matrix CreateProjectionMatrix(float fovy,float aspect,float Znear,float Zfar){
    // Array index in the matrix
    //  _          _
    // | 0 4  8  12 |
    // | 1 5  9  13 |
    // | 2 6 10  14 |
    // |_3 7 11  15_|
    //
    Matrix out;
    float tanhalffovy = tanf(DegreesToRadians(fovy/2));
    out.m[ 0]=1/(aspect*tanhalffovy);
    out.m[ 5]=1/(tanhalffovy);
    out.m[10]=(Zfar+Znear)/(Znear-Zfar);
    out.m[11]=(2*Zfar*Znear)/(Znear-Zfar);
    out.m[14]=-1;
    out.m[ 1]=0;
    out.m[ 2]=0;
    out.m[ 3]=0;
    out.m[ 4]=0;
    out.m[ 6]=0;
    out.m[ 7]=0;
    out.m[ 8]=0;
    out.m[ 9]=0;
    out.m[12]=0;
    out.m[13]=0;
    out.m[15]=0;
    return out;
}

Matrix lookAt(float eye[3],float center[3],float up[3]){
    // Array index in the matrix
    //  _          _
    // | 0 4  8  12 |
    // | 1 5  9  13 |
    // | 2 6 10  14 |
    // |_3 7 11  15_|
    //
    double help=sqrt(up[0]*up[0]+up[1]*up[1]+up[2]*up[2]);
    float upN[3];
    upN[0]=up[0]/help;
    upN[1]=up[1]/help;
    upN[2]=up[2]/help;

    float f[3];
    f[0]=(center[0]-eye[0]);
    f[1]=(center[1]-eye[1]);
    f[2]=(center[2]-eye[2]);
    help=sqrt(f[0]*f[0]+f[1]*f[1]+f[2]*f[2]);
    f[0]/=help;
    f[1]/=help;
    f[2]/=help;

    float s[3];
    s[0]=f[1]*upN[2]-upN[1]*f[2];
    s[1]=f[2]*upN[0]-upN[2]*f[0];
    s[2]=f[0]*upN[1]-upN[0]*f[1];

    float u[3];
    u[0]=s[1]*f[2]-f[1]*s[2];
    u[1]=s[2]*f[0]-f[2]*s[0];
    u[2]=s[0]*f[1]-f[0]*s[1];

    Matrix out={{s[0],s[1],s[2],0, u[0],u[1],u[2],0, f[0],f[1],f[2],0, -eye[0],-eye[1],-eye[2],1}};
   return out;
}

Matrix MultiplyMatrices(const Matrix* m1, const Matrix* m2){    
    Matrix out;
    // First column
    out.m[ 0]=(m1->m[0])*(m2->m[0])+(m1->m[4])*(m2->m[1])+(m1->m[ 8])*(m2->m[2])+(m1->m[12])*(m2->m[3]);
    out.m[ 1]=(m1->m[1])*(m2->m[0])+(m1->m[5])*(m2->m[1])+(m1->m[ 9])*(m2->m[2])+(m1->m[13])*(m2->m[3]);
    out.m[ 2]=(m1->m[2])*(m2->m[0])+(m1->m[6])*(m2->m[1])+(m1->m[10])*(m2->m[2])+(m1->m[14])*(m2->m[3]);
    out.m[ 3]=(m1->m[3])*(m2->m[0])+(m1->m[7])*(m2->m[1])+(m1->m[11])*(m2->m[2])+(m1->m[15])*(m2->m[3]);
    // Second column
    out.m[ 4]=(m1->m[0])*(m2->m[4])+(m1->m[4])*(m2->m[5])+(m1->m[ 8])*(m2->m[6])+(m1->m[12])*(m2->m[7]);
    out.m[ 5]=(m1->m[1])*(m2->m[4])+(m1->m[5])*(m2->m[5])+(m1->m[ 9])*(m2->m[6])+(m1->m[13])*(m2->m[7]);
    out.m[ 6]=(m1->m[2])*(m2->m[4])+(m1->m[6])*(m2->m[5])+(m1->m[10])*(m2->m[6])+(m1->m[14])*(m2->m[7]);
    out.m[ 7]=(m1->m[3])*(m2->m[4])+(m1->m[7])*(m2->m[5])+(m1->m[11])*(m2->m[6])+(m1->m[15])*(m2->m[7]);
    // Third column
    out.m[ 8]=(m1->m[0])*(m2->m[8])+(m1->m[4])*(m2->m[9])+(m1->m[ 8])*(m2->m[10])+(m1->m[12])*(m2->m[11]);
    out.m[ 9]=(m1->m[1])*(m2->m[8])+(m1->m[5])*(m2->m[9])+(m1->m[ 9])*(m2->m[10])+(m1->m[13])*(m2->m[11]);
    out.m[10]=(m1->m[2])*(m2->m[8])+(m1->m[6])*(m2->m[9])+(m1->m[10])*(m2->m[10])+(m1->m[14])*(m2->m[11]);
    out.m[11]=(m1->m[3])*(m2->m[8])+(m1->m[7])*(m2->m[9])+(m1->m[11])*(m2->m[10])+(m1->m[15])*(m2->m[11]);
    // Fourth
    out.m[12]=(m1->m[0])*(m2->m[12])+(m1->m[4])*(m2->m[13])+(m1->m[ 8])*(m2->m[14])+(m1->m[12])*(m2->m[15]);
    out.m[13]=(m1->m[1])*(m2->m[12])+(m1->m[5])*(m2->m[13])+(m1->m[ 9])*(m2->m[14])+(m1->m[13])*(m2->m[15]);
    out.m[14]=(m1->m[2])*(m2->m[12])+(m1->m[6])*(m2->m[13])+(m1->m[10])*(m2->m[14])+(m1->m[14])*(m2->m[15]);
    out.m[15]=(m1->m[3])*(m2->m[12])+(m1->m[7])*(m2->m[13])+(m1->m[11])*(m2->m[14])+(m1->m[15])*(m2->m[15]);

    return out;
}

我99.9%确定着色器与示例中的相同。

1 个答案:

答案 0 :(得分:0)

我发现您的代码有两个问题:

  1. 您使用的矩阵存储布局惯例并不十分清楚。

    您的lookAt代码将-eye翻译放入元素12到14中,这意味着您将列主要布局与标准GL matrix * vector乘法顺序一起使用着色器。但是,您的投影矩阵被定义为转换为该约定。应交换元素11和14。

  2. 您的lookAt功能错误:

    视图矩阵应将世界空间转换为相机位于中心并朝向-z方向的眼睛空间。这可以解释为相对于固定相机移动所有对象,或者相对于世界坐标定义新视图坐标系。在这两种情况下,您都会得到公式R * T(-eye)。在第一种解释中,这意味着我们首先按-eye移动所有对象(以便点eye最终位于中心),然后围绕该新中心旋转,以便lookAt方向旋转进入-z轴,将up向量转移到+y

    但是,您的lookAt矩阵并没有这样做。您的矩阵可以分解为T(-eye) * R^-1。首先,您的R不是您需要的旋转:如果您通过-z轴向量(0,0,-1,0)^T多次移动矩阵,则只需选择第三列并将其否定,你最终会得到-f。但是你的前向方向向量应该是f,所以在将它放入矩阵之前你忘了否定f

    第二个问题是旋转实际上是倒置。如果你否定第三列,你最终会得到V * (0 0 -1 0)^T = (f 0)^T,但那是你需要的相反的转换方向。您必须构建一个导致V * (f 0)^T = (0 0 -1 0)的轮换。现在关于旋转矩阵的好处是它们是正交的,所以R^-1 = R^T。这意味着你可以简单地转置你的旋转矩阵来反转它。

    但是,您不能只转置视图矩阵。这将我们带到最后一个问题:您只需将翻译部分-eye写入第四列。从概念上讲,这意味着您执行V=T(-eye) * R,即您将翻译应用为 last 步骤。但是,正如我们之前看到的,我们必须首先应用翻译。因此,要完全修复矩阵,首先要通过转置轮换部分来构建R^T,即将su-f向量写为{{1}进入矩阵,最后你用<{1}} 乘以该矩阵。