执行gluLookAt和gluPerspective

时间:2011-11-14 15:43:57

标签: iphone opengl-es matrix perspective

我在制作游戏的过程中在opengl中编写了一个小型2D引擎。我正在使用OpenGL ES 2,代码在iOS和Mac OSX上编译并运行。

现在我正在扩展它以支持3D,我在设置相机时遇到了问题 我已经检查了一百次代码并且我无法找到问题所在,所以也许有经验的人可以给出一个想法。

这是我的代码:我发布了我认为可能存在问题的部分代码,但如果需要其他东西,请问我。

Matrix4 _getFrustumMatrix(float left, float right, float bottom, float top, float near, float far){
    Matrix4 res = Matrix4(2.0 * near / (right - left), 0, 0, 0,
                           0, 2.0 * near / (top - bottom), 0, 0,
                           (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1.0,
                           0,0, -2.0 * far * near / (far - near), 0);

    return res;
}

Matrix4 _getPerspectiveMatrix(float near, float far, float angleOfView){
    static float aspectRatio = float(SCREENW)/float(SCREENH);
    float top = near * tan(angleOfView * 3.1415927 / 360.0);
    float bottom = -top;
    float left = bottom * aspectRatio;
    float right = top * aspectRatio;

    return _getFrustumMatrix(left, right, bottom, top, near, far);    
}

Matrix4 _getLookAtMatrix(Vector3 eye, Vector3 at, Vector3 up){
    Vector3 forward, side;
    forward = at - eye;
    forward.normalize();
    side = forward ^ up;
    side.normalize();
    up = side ^ forward;

    Matrix4 res = Matrix4(side.x, up.x, -forward.x, 0,
                          side.y, up.y, -forward.y, 0,
                          side.z, up.z, -forward.z, 0,
                          0, 0, 0, 1);
    res.translate(Vector3(0 - eye));
    return res;
}

void Scene3D::_deepRender(){    
    cameraEye = Vector3(10,0,40);
    cameraAt = Vector3(0,0,0);
    cameraUp = Vector3(0,1,0);

    MatrixStack::push();

    Matrix4 projection = _getPerspectiveMatrix(1, 100, 45);    
    Matrix4 view = _getLookAtMatrix(cameraEye, cameraAt, cameraUp);    

    MatrixStack::set(projection * view);

    Space3D::_deepRender();

    MatrixStack::pop();    
}

绘制的对象是轴的表示,其中x =红色,y =绿色,z =蓝色,它位于(0,0,0)。

如果我把眼睛放在(0,0,40),一切看起来都像预期的那样: eye at (0,0,40)

如果我把眼睛放在(10,0,40)处,那么物体不会在屏幕中间绘制,因为它应该是。 eye at (10,0,40)

这是Matrix4 :: translate方法:

void Matrix4::translate(const Vector3& v) {
    a14 += a11 * v.x + a12 * v.y + a13 * v.z;
    a24 += a21 * v.x + a22 * v.y + a23 * v.z;
    a34 += a31 * v.x + a32 * v.y + a33 * v.z;
    a44 += a41 * v.x + a42 * v.y + a43 * v.z;
}

编辑:添加一些信息:

将_getLookAtMatrix()与此参数一起使用:

cameraEye = Vector3(40,40,40);
cameraAt = Vector3(0,0,0);
cameraUp = Vector3(0,1,0);

应该给我一个等效的矩阵吗?

Matrix4 view;
view.setIdentity();
view.translate(Vector3(0,0,-69.2820323)); // 69.2820323 is the length of Vector3(40,40,40)
view.rotate(45, Vector3(1,0,0));
view.rotate(-45, Vector3(0,1,0));

至少那些变换对我来说是有意义的,结果图像看起来像我期待的那样。 但是这个矩阵与我使用_getLookAtMatrix()的矩阵相比是非常不同的:

视图:

0.707106769,    -0.49999997,    0.49999997,     0,
0,              0.707106769,    0.707106769,    0, 
-0.707106769,   -0.49999997,    0.49999997,     0, 
0,              0,              -69.2820358,    1

_getLookAtMatrix(cameraEye,cameraAt,cameraUp):

0.707106769,    0,              -0.707106769,   0, 
-0.408248276,   0.816496551,    -0.408248276,   0, 
0.577350259,    0.577350259,    0.577350259,    0, 
-35.0483475,    -55.7538719,    21.520195,      1

1 个答案:

答案 0 :(得分:2)

你的矩阵类似乎有一些严重的排序不一致。

例如,我假设您的Matrix4构造函数将其参数(矩阵元素)作为列专用,否则您的函数将与glFrustumgluLookAt的参考实现不匹配,你会得到完全搞砸的结果。

您的translate函数的代码看起来也正确,因为它必须修改矩阵的最后一列,即元素(a14a24,{{1 }和a34)。

但是,您打印出的a44矩阵表明view实际上修改了最后一行,除非您以列主格式打印矩阵并因此进行转置。但在这种情况下,_ translate的打印表明getLookAtMatrix构造函数以行主顺序获取其参数,这确实使其他事物无效。

当然所有这些还取决于你如何将矩阵发送到OpenGL以及如何在顶点着色器中使用它们(我假设ES 2.0,否则就不需要你自己的矩阵库)。如果你确实使用ES 1,那么你需要按列主要顺序将矩阵元素发送到OpenGL,但是翻译必须在最后一列而不是最后一行。

但无论您使用什么约定,矩阵代码中肯定存在严重的不一致。但是没有看到整个Matrix4类,顶点着色器和将矩阵上传到OpenGL的代码,很难说这种不一致的地方。