6

私の理解から、

gluLookAt(
        eye_x, eye_y, eye_z,
        center_x, center_y, center_z,   
        up_x, up_y, up_z
    );

次と同等です。

glRotatef(B, 0.0, 0.0, 1.0);
glRotatef(A, wx, wy, wz);
glTranslatef(-eye_x, -eye_y, -eye_z);

しかし、ModelViewマトリックスを印刷すると、への呼び出しがglTranslatef()正しく機能していないようです。コード スニペットは次のとおりです。

#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>

#include <iomanip>
#include <iostream>
#include <string>

using namespace std;

static const int Rx = 0;
static const int Ry = 1;
static const int Rz = 2;

static const int Ux = 4;
static const int Uy = 5;
static const int Uz = 6;

static const int Ax = 8;
static const int Ay = 9;
static const int Az = 10;

static const int Tx = 12;
static const int Ty = 13;
static const int Tz = 14;

void init() {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    GLfloat lmodel_ambient[] = { 0.8, 0.0, 0.0, 0.0 };
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
}

void displayModelviewMatrix(float MV[16]) {
    int SPACING = 12;
    cout << left;
    cout << "\tMODELVIEW MATRIX\n";
    cout << "--------------------------------------------------" << endl;
    cout << setw(SPACING) << "R" << setw(SPACING) << "U" << setw(SPACING) << "A" << setw(SPACING) << "T" << endl;   
    cout << "--------------------------------------------------" << endl;
    cout << setw(SPACING) << MV[Rx] << setw(SPACING) << MV[Ux] << setw(SPACING) << MV[Ax]  << setw(SPACING) << MV[Tx] << endl;
    cout << setw(SPACING) << MV[Ry] << setw(SPACING) << MV[Uy] << setw(SPACING) << MV[Ay]  << setw(SPACING) << MV[Ty] << endl;
    cout << setw(SPACING) << MV[Rz] << setw(SPACING) << MV[Uz] << setw(SPACING) << MV[Az] << setw(SPACING)  << MV[Tz] << endl;
    cout << setw(SPACING) << MV[3] << setw(SPACING) << MV[7] << setw(SPACING) << MV[11] << setw(SPACING) << MV[15] << endl;
    cout << "--------------------------------------------------" << endl;
    cout << endl;
}

void reshape(int w, int h) {
    float ratio = static_cast<float>(w)/h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, ratio, 1.0, 425.0);
}

void draw() {
    float m[16];
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    gluLookAt(
        300.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    );
    glColor3f(1.0, 0.0, 0.0);
    glutSolidCube(100.0);
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    displayModelviewMatrix(m);
    glutSwapBuffers();
}


int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Demo");
    glutReshapeFunc(reshape);
    glutDisplayFunc(draw);
    init();
    glutMainLoop();
    return 0;
} 

eyeベクトルにどのような値を使用しても、または
300, 0, 0平行移動ベクトルは同じですが、コードの順序が逆順であるため、最初に実行し、次に 2 つの回転を実行する必要 があるため、意味がありません。さらに、回転マトリックスは、(ModelView マトリックスの) 変換列から完全に独立しています。この奇妙な動作の原因は何でしょうか? 目のベクトルを使用した出力は次のとおりです。
0, 300, 0
0, 0, 300
glTranslatef(0.0f, 300.0f, 0.0f)

        MODELVIEW MATRIX
--------------------------------------------------
R           U           A           T
--------------------------------------------------
0           0           0           0
0           0           0           0
0           1           0           -300
0           0           0           1
--------------------------------------------------

T列は(0, -300, 0)! それで、誰かがこれを説明するのを手伝ってくれますか?

http://www.mesa3d.orggluLookAtからの実装

void GLAPIENTRY
gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
      GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
      GLdouble upz)
{
    float forward[3], side[3], up[3];
    GLfloat m[4][4];

    forward[0] = centerx - eyex;
    forward[1] = centery - eyey;
    forward[2] = centerz - eyez;

    up[0] = upx;
    up[1] = upy;
    up[2] = upz;

    normalize(forward);

    /* Side = forward x up */
    cross(forward, up, side);
    normalize(side);

    /* Recompute up as: up = side x forward */
    cross(side, forward, up);

    __gluMakeIdentityf(&m[0][0]);
    m[0][0] = side[0];
    m[1][0] = side[1];
    m[2][0] = side[2];

    m[0][1] = up[0];
    m[1][1] = up[1];
    m[2][1] = up[2];

    m[0][2] = -forward[0];
    m[1][2] = -forward[1];
    m[2][2] = -forward[2];

    glMultMatrixf(&m[0][0]);
    glTranslated(-eyex, -eyey, -eyez);
}
4

3 に答える 3

7

モデルビュー行列のような回転行列と平行移動行列を使用すると

Rxx Rxy Rxz Tx 
Ryx Ryy Ryz Ty 
Rzx Rzy Rzz Tz 
 0   0   0   1 

任意のベクトルに作用する

x
y
z
1

我々が得る

Rxx x + Rxy y + Rxz z  +  Tx 
Ryx x + Ryy y + Ryz z  +  Ty
Rzx x + Rzy y + Rzz z  +  Tz
1

(私は物事を書いているので、ベクトルは左側の行列で乗算されます)。

これは、行列の平行移動コンポーネントが、回転後に適用する平行移動を与えることを示しています。そのため、(-eye_x、-eye_y、-eye_z) ベクトルと同じではありません。ご指摘のとおり、回転の前に変換が行われているからです。

平行移動が常に -z 方向に沿っている理由は、ビュー フレームでは -z 方向が中心に向かっているからです。中心は常に目から 300 ユニット離れているため、すべての目の位置が中心をビュー フレームの (0, 0, -300) に置きます。したがって、中心は平行移動を行う前に原点から始まるため、正しい座標を与えるための平行移動は (0, 0, -300) でなければなりません。

また、これに気付いたかもしれませんが、表示するモデルビュー マトリックスは、ビュー方向 (目から中心) に沿ってアップ ベクトルを指すため、病的です。これは、2 つの完全なゼロ行がある理由を説明しています。

于 2012-10-31T23:04:56.073 に答える
0

「このコードで前方、上、および横のベクトルを使用して回転がどのように実行されるかについて非常に混乱しています...」「UVNカメラ」について何か知っておくべきだと思います.2つの座標系間で変換される座標についていくつかの理論があります上記の例では、2 つの座標はワールド座標とカメラ座標です。結果は次のとおりです。ここに画像の説明を入力

N - ターゲットからカメラへのベクトル。一部の 3D 文献では「look at」ベクトルとしても知られています。このベクトルは -Z 軸に対応します。

V - 直立したとき、これは頭から空へのベクトルです。フライト シミュレータを作成していて、飛行機が反転している場合、そのベクトルは地面を指している可能性があります。このベクトルは Y 軸に対応します。

U - このベクトルは、カメラから「右側」を指します。X 軸に対応します。

于 2012-12-19T08:32:15.123 に答える
0

@Andon M. Coleman - 上の図の行メジャーはどうですか? 行または列の主要な行列を持つことは、1D メモリ内の 2D 構造のメモリ表現に関するものであり、4x4 変換行列の上記の図とは関係ありません。

あなたが示唆しているように、ベクトル U、V、N が列として書き込まれた場合、カメラ空間からワールド空間への変換が行われます。

ただし、マトリックスへの入力はワールド空間の位置であり、出力はカメラ空間の位置であるため、マトリックスはワールド空間からカメラ空間への変換です。

U、V、N が転置される理由は、これが提案する行列の逆行列であり、逆行列も転置である直交行列のプロパティを使用するためです。つまり、U、V、N ベクトルを行に書き込んでワールド空間からカメラ空間への変換を取得し、U、V、N ベクトルを列に書き込んでカメラ空間からワールド空間への変換を取得します。

また、右側のワールド位置を乗算するという選択は、ダイアグラムが列ベクトルを使用しているためです。行ベクトルを使用している場合は、乗算のままにします。行列をメモリに格納する方法とはまったく関係がなく、2 つの行列を乗算する方法、つまり、ベクトルを 4x4 行列で乗算する前に 1X4 または 4X1 行列に変換する方法とは関係ありません。

要するに、上の図は問題ありません。これは、ある空間から別の空間への単なる変換です。この問題を、プログラミングの詳細であるメモリ レイアウトの話と混同しないでください。

于 2015-05-08T15:54:19.513 に答える