OpenGL 3 (LWJGL) LookAt Matrix Confusion

Я изучаю OpenGL 3, используя LWJGL. Я пытался реализовать эквивалент gluLookAt()и хотя это работает, я несколько запутался, почему.

Я признаюсь, что просто скопировал этот код из различных источников в сети, но после долгих исследований, я думаю, понимаю математические основы и понимаю, что делает LWJGL.

Однако "правильный" gluLookAt Код работал неправильно в моем приложении, так как камера, казалось, вращалась не в ту сторону. Мне удалось заставить мой код работать только транспонированием ортонормированных векторов. forward, side, а также up (надеюсь, я использую правильную терминологию!), что, я уверен, не так...

private static final Vector3f forward = new Vector3f();
private static final Vector3f side = new Vector3f();
private static final Vector3f up = new Vector3f();
private static final Vector3f eye = new Vector3f();

public static Matrix4f lookAt(float eyeX, float eyeY, float eyeZ, 
                              float centerX, float centerY, float centerZ, 
                              float upX, float upY, float upZ) {
    forward.set(centerX - eyeX, centerY - eyeY, centerZ - eyeZ);
    forward.normalise();

    up.set(upX, upY, upZ);

    Vector3f.cross(forward, up, side);
    side.normalise();

    Vector3f.cross(side, forward, up);
    up.normalise();

    Matrix4f matrix = new Matrix4f();
    matrix.m00 = side.x;
    matrix.m01 = side.y;
    matrix.m02 = side.z;

    matrix.m10 = up.x;
    matrix.m11 = up.y;
    matrix.m12 = up.z;

    matrix.m20 = -forward.x;
    matrix.m21 = -forward.y;
    matrix.m22 = -forward.z;

    matrix.transpose(); // <------ My dumb hack

    eye.set(-eyeX, -eyeY, -eyeZ);
    matrix.translate(eye);

    return matrix;
}

Я не думаю, что я должен делать транспонирование, но без этого он не работает. я кладу transpose() потому что я не мог потрудиться перепечатать все положения ячейки матрицы, кстати!

Насколько я понимаю, форма матрицы lookAt должна быть следующей

[ side.x  up.x  fwd.x  0 ] [ 1  0  0  -eye.x ]
[ side.y  up.y  fwd.y  0 ] [ 0  1  0  -eye.y ]
[ side.z  up.z  fwd.z  0 ] [ 0  0  1  -eye.z ]
[      0     0      0  1 ] [ 0  0  0       1 ]

И я думаю, что LWJGL Matrix4f класс представляет матричные ячейки как m<col><row>, translate(Vector3f) метод делает следующее

public static Matrix4f translate(Vector3f vec, Matrix4f src, Matrix4f dest) {
  ...
    dest.m30 += src.m00 * vec.x + src.m10 * vec.y + src.m20 * vec.z;
    dest.m31 += src.m01 * vec.x + src.m11 * vec.y + src.m21 * vec.z;
    dest.m32 += src.m02 * vec.x + src.m12 * vec.y + src.m22 * vec.z;
    dest.m33 += src.m03 * vec.x + src.m13 * vec.y + src.m23 * vec.z;
  ...
}

Так что я остался в растерянности относительно того, какую часть этого я облажался. Это мое понимание матрицы lookAt, важности столбца / строки (это слово?!) Matrix4f, или что-то другое? Остальная часть моего кода просто сломана? Это на самом деле правильно, и я просто слишком волнуюсь? Я просто идиот?

Благодарю.

1 ответ

Решение

Вы не должны ничего транспонировать. Вы должны отрицать вектор "глаза" матрицы lookAt() и направление взгляда. "ГЛАЗ" соответствует положению камеры, которое всегда должно быть инвертировано. Все это делается внутри lookAt()

Вот метод lookAt() из порта Java знаменитой математической библиотеки GLM.

 public static Mat4 lookAt(Vec3 eye, Vec3 center, Vec3 up) {

    Vec3 f = normalize(Vec3.sub(center, eye));
    Vec3 u = normalize(up);
    Vec3 s = normalize(cross(f, u));
    u = cross(s, f);

    Mat4 result = new Mat4(1.0f);
    result.set(0, 0, s.x);
    result.set(1, 0, s.y);
    result.set(2, 0, s.z);
    result.set(0, 1, u.x);
    result.set(1, 1, u.y);
    result.set(2, 1, u.z);
    result.set(0, 2, -f.x);
    result.set(1, 2, -f.y);
    result.set(2, 2, -f.z);

    return translate(result, new Vec3(-eye.x,-eye.y,-eye.z));
}

Я использую его с моим рендерером OpenGL 4 на основе LWJGL, и он работает как шарм:)

Другие вопросы по тегам