2009-07-24 2 views
2

Я пытаюсь реализовать модель камеры в Delphi/OpenGL после описания, приведенного в OpenGL SuperBible. Камера имеет положение, вектор вперед и вектор вверх. Перевод камеры, кажется, работает нормально, но когда я пытаюсь повернуть камеру в соответствии с передним вектором, я теряю вид моего объекта.OpenGL: Помощь с преобразованием камеры

function TCamera.GetCameraOrientation: TMatrix4f; 
var 
    x, z: T3DVector; 
begin 
    z := T3DVector.Create(-FForward.X, -FForward.y, -FForward.z); 
    x := T3DVector.Cross(z, FUp); 

    result[0, 0] := x.X; 
    result[1, 0] := x.Y; 
    result[2, 0] := x.Z; 
    result[3, 0] := 0; 

    result[0, 1] := FUp.X; 
    result[1, 1] := FUp.Y; 
    result[2, 1] := FUp.Z; 
    result[3, 1] := 0; 

    result[0, 2] := z.x; 
    result[1, 2] := z.y; 
    result[2, 2] := z.z; 
    result[3, 2] := 0; 

    result[0, 3] := 0; 
    result[1, 3] := 0; 
    result[2, 3] := 0; 
    result[3, 3] := 1; 
end; 

procedure TCamera.ApplyTransformation; 
var 
    cameraOrient: TMatrix4f; 
    a, b, c: TMatrix4f; 
begin 
    cameraOrient := getcameraOrientation; 
    glMultMatrixf(@cameraOrient); 
    glTranslatef(-FPosition.x, -FPosition.y, -FPosition.z); 
end; 

Учитывая положение (0, 0, -15), вперед, вектор (0 0 1) и до вектора (0 1 0), я ожидал, чтобы получить идентификационную матрицу из getCameraOrientation-метода, но вместо этого я получаю

(1, 0, 0, 0) 
(0, 1, 0, 0) 
(0, 0, -1, 0) 
(0, 0, 0, 1) 

Если я изменяю вперед вектора (0 0 -1) я получаю следующую матрицу:

(-1, 0, 0, 0) 
(0, 1, 0, 0) 
(0, 0, 1, 0) 
(0, 0, 0, 1) 

После вызова glMultMatrix() и glTranslate(), glGet () дает мне следующее GL_MODELVIEW_MATRIX:

(1, 0, 0, 0) 
(0, 1, 0, 0) 
(0, 0, -1, 0) 
(0, 0, 15, 1) 

Я бы ожидал, что 15 будет в колонке 4, строка 3, столбец не 3, строка 4.

Может кто-нибудь увидеть, где я получаю это неправильно?

EDIT: Исходный код с OpenGL SuperBible:

inline void GetCameraOrientation(M3DMatrix44f m) 
     { 
     M3DVector3f x, z; 

     // Make rotation matrix 
     // Z vector is reversed 
     z[0] = -vForward[0]; 
     z[1] = -vForward[1]; 
     z[2] = -vForward[2]; 

     // X vector = Y cross Z 
     m3dCrossProduct(x, vUp, z); 

     // Matrix has no translation information and is 
     // transposed.... (rows instead of columns) 
     #define M(row,col) m[col*4+row] 
      M(0, 0) = x[0]; 
      M(0, 1) = x[1]; 
      M(0, 2) = x[2]; 
      M(0, 3) = 0.0; 
      M(1, 0) = vUp[0]; 
      M(1, 1) = vUp[1]; 
      M(1, 2) = vUp[2]; 
      M(1, 3) = 0.0; 
      M(2, 0) = z[0]; 
      M(2, 1) = z[1]; 
      M(2, 2) = z[2]; 
      M(2, 3) = 0.0; 
      M(3, 0) = 0.0; 
      M(3, 1) = 0.0; 
      M(3, 2) = 0.0; 
      M(3, 3) = 1.0; 
     #undef M 
     } 

    inline void ApplyCameraTransform(bool bRotOnly = false)  
     { 
     M3DMatrix44f m; 

     GetCameraOrientation(m); 

     // Camera Transform 
     glMultMatrixf(m); 

     // If Rotation only, then do not do the translation 
     if(!bRotOnly) 
      glTranslatef(-vOrigin[0], -vOrigin[1], -vOrigin[2]); 
     } 

ответ

2

Учитывая ваш код getcameraOrientation результирующая матрица вполне очевидна: вперед = (0, 0, 1), получаем г = (0, 0, - 1), что соответствует третьей строке матрицы. Перекрестное произведение z = (0, 0, -1) и FUp = (0, 1, 0) приводит к x = (1, 0, 0), что соответствует первой строке матрицы. Вторая строка - это всего лишь копия FUp, а четвертая строка только исправлена.

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

+0

Он должен быть способен вращаться вокруг переднего вектора, не теряя из виду свой объект. – Nosredna

+0

Я не вращаюсь вокруг прямого вектора, я вращаюсь в соответствии с передним вектором. В моем случае, где up прямо вверх по оси y, это будет таким же, как вращение вокруг оси y. так как вперед прямо вниз по оси z, не должно быть никакого вращения вообще. Но есть, поэтому я теряю отслеживание своего объекта .... – Vegar

+2

Ну результирующая матрица в вашем первом случае возвращает ось z. Поскольку вы «смотрите на» положительную ось z, возврат ее будет просто «оглянуться». Итак, почему z рассчитывается из отрицательного вектора вперед вместо того, чтобы просто быть копией, если это? –

1

единичная матрица

Я не знаю, почему SuperBible предлагает использовать (-FForward.X, -FForward.y, -FForward.z), чтобы создать свой Z вектор. Если вы выберете знаки минус, вы получите идентификационную матрицу, которую вы ожидаете, когда ваш вектор вперед (0, 0, 1).

Если вы хотите сохранить знаки минус, и вы хотите, чтобы вектор вперед (0, 0, -1) создавал единичную матрицу, тогда вам нужно сменить крест-произведение с Cross (z, FUp) на Cross (FUp, z), потому что OpenGL использует правую систему координат. См. Cross product.

15 в неправильном месте

Я согласен с вами, что я ожидал бы матрица перевод выглядеть следующим образом:

(1, 0, 0, x) 
(0, 1, 0, y) 
(0, 0, 1, z) 
(0, 0, 0, 1) 

Примечание хотя, что OpenGL хранит свою матрицу в колонке заказа не строка заказ, поэтому, когда вы получите матрицу для просмотра модели, она будет выглядеть следующим образом:

(m[0], m[4], m[8], m[12]) 
(m[1], m[5], m[9], m[13]) 
(m[2], m[6], m[10], m[14]) 
(m[3], m[7], m[11], m[15]) 

Если вы считаете, что это был порядок строк, это может быть причиной путаницы.