1

I've been experimenting with using matrix manipulation instead of using the euler or quaternion based functions that come with Open GL ES (and the ulti lib).

I can get most stuff working, however I can't recreate the gluLookAt function quite right, as you will be able to see from the screen shots below:

The correct gluLookAt version.

The busted, matrix version.

Please note, the screen shot is just a portion of the actual screen. Those buttons you see in both are overlays done using 2D orthographic, and they help show the difference because they're in the same spot in both images.

I took my information from here: http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml

Which I recreated in my java code in below (some details omitted):

class point3D {
    public double mX, mY, mZ;
}

double scaler(point3D pt){
    return Math.pow(
        Math.pow(pt.mX, 2.0) + Math.pow(pt.mY, 2.0) + Math.pow(pt.mZ, 2.0),
        1.0/3.0
    );
}

void cross(point3D A, point3D B, point3D output){
    output.mX = (A.mY*B.mZ) - (A.mZ*B.mY);
    output.mY = (A.mZ*B.mX) - (A.mX*B.mZ);
    output.mZ = (A.mX*B.mY) - (A.mY*B.mX);
}

void normalise(point3D normMe, point3D output){
    double s = scaler(normMe);
    output.mX = normMe.mX / s;
    output.mY = normMe.mY / s;
    output.mZ = normMe.mZ / s;
}

float mx, my, mz, mfx, mfy, mfz;
private FloatBuffer mLookatMx; //- All setup and stuff elsewhere

void myLookAt(){
    point3D ptTmpA, ptTmpB, ptTmpC, ptTmpD;

    //- 'forward' F part
    ptTmpA.mX = mfx - mx;
    ptTmpA.mY = mfy - my;
    ptTmpA.mZ = mfz - mz;
    normalise(ptTmpA, ptTmpA);

    //- 'up' part
    ptTmpB.mX = 0;
    ptTmpB.mY = 1.0;
    ptTmpB.mZ = 0;

    cross(ptTmpB, ptTmpA, ptTmpC);  //- S
    normalise(ptTmpC, ptTmpC);

    cross(ptTmpA, ptTmpC, ptTmpD);  //- U
    normalise(ptTmpD, ptTmpD);

    //- the 4x4 matrix. Not including the transformation this time for simplicity.
    //- m = {
    //-        s1,  s2,  s3, -x
    //-        u1,  u2,  u3, -y
    //-       -f1, -f2, -f3, -z
    //-         0,   0,   0,  1
    //- }

    //- 0
    mLookatMx.put((float)ptTmpC.mX);            
    mLookatMx.put((float)ptTmpC.mY);            
    mLookatMx.put((float)ptTmpC.mZ);            
    mLookatMx.put(0);

    //- 4
    mLookatMx.put((float)ptTmpD.mX);            
    mLookatMx.put((float)ptTmpD.mY);            
    mLookatMx.put((float)ptTmpD.mZ);            
    mLookatMx.put(0);

    //- 12
    mLookatMx.put((float)ptTmpA.mX *-1.0f); 
    mLookatMx.put((float)ptTmpA.mY *-1.0f); 
    mLookatMx.put((float)ptTmpA.mZ *-1.0f); 
    mLookatMx.put(0);

    //- 16
    mLookatMx.put(0);                           
    mLookatMx.put(0);                           
    mLookatMx.put(0);                           
    mLookatMx.put(1.0f);
    mLookatMx.position(0);
}

void myDraw(){
    glDisable(GL_DEPTH_BITS);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(mGL, 90.0, mScreen.mX / mScreen.mY, 0.01, 10.0);

    //- This works
    //gluLookAt(mGL, 
    //    mx, my, mz, 
    //    mfx, mfy, mfz,
    //    0.0f, 1.0f, 0.0f
    //);

    //- This is distorted
    glMultMatrixf(mLookatMx);
    glTranslatef(mx * -1.0f, my * -1.0f, mz * -1.0f)

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //- draw models as seen in screen shot
}
4

1 回答 1

0

OpenGL 使用列优先矩阵。您似乎正在逐行填充矩阵,这实际上可以在 Direct3D (row-major) 仅供参考。

最简单的解决方案是调用mLookatMx.transpose (...)(如果您使用的是适当的矩阵类);这将为您翻转行和列。

但是,由于您使用的是普通的 old FloatBuffer,因此您需要put (...)一次一列而不是一次一行的矩阵的内容。

顺便说一句,OpenGL 的核心始终使用矩阵进行转换。那些欧拉角和四元数辅助实用程序实际上只是为 OpenGL 创建变换矩阵。您可以在顶点着色器中实现基于非矩阵的转换,但这比您现在应该考虑的要先进 :)

于 2013-09-15T00:09:25.280 回答