2

在 OpenGL SuperBible 中给出的描述之后,我试图在 Delphi/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 行。

谁能看到我在哪里弄错了?

编辑:来自 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]);
        }
4

2 回答 2

2

鉴于您的 getcameraOrientation 代码,生成的矩阵非常明显:forward = (0, 0, 1) 产生 z = (0, 0, -1),它对应于矩阵的第 3 行。z = (0, 0, -1) 和 FUp = (0, 1, 0) 的叉积得到 x = (1, 0, 0),对应于矩阵的第一行。第二行只是 FUp 的副本,第四行只是固定的。

我实际上不明白您想要实现什么,但是当您旋转相机时,您显然会看不到您的对象。在现实世界中,如果你看着一个点并转过头来——这是一回事。您是否尝试过颠倒平移和旋转的顺序?

于 2009-07-24T16:00:20.837 回答
1

单位矩阵

我不确定为什么 SuperBible 建议使用 (-FForward.X, -FForward.y, -FForward.z) 来创建您的 Z 向量。如果你去掉减号,那么当你的前向向量为 (0, 0, 1) 时,你将得到你期望的单位矩阵。

如果要保留减号,并且希望 (0, 0, -1) 的前向向量产生单位矩阵,则需要将叉积从 Cross(z, FUp) 更改为 Cross(FUp, z),因为 OpenGL 使用右手坐标系。请参阅叉积

15在错误的地方

我同意你的看法,我希望翻译矩阵看起来像这样:

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

请注意,尽管 OpenGL 以顺序而不是顺序存储其矩阵,但当您 glGet 模型视图矩阵时,它将按以下顺序出现:

(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])

如果您认为它是按行顺序排列的,那么这可能就是造成混乱的原因。

于 2009-07-29T05:37:26.630 回答