views:

839

answers:

2

I'm trying to implement a camera-model in Delphi/OpenGL after the description given in OpenGL SuperBible. The camera has a position, a forward vector and a up vector. Translating the camera seems to work OK, but when I try to rotate the camera according to the forward vector, I loose sight of my object.

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;

Given the position (0, 0, -15), forward vector (0 0 1) and up vector (0 1 0), I expected to get a identity-matrix from the getCameraOrientation-method, but instead I get

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

If I change the forward vector to (0 0 -1) I get the following matrix:

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

After the call to glMultMatrix( ) and glTranslate( ), glGet( ) gives me the following GL_MODELVIEW_MATRIX:

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

I would have expected the 15 to be in column 4, row 3, not column 3, row 4.

Can anyone see where I get this wrong?

EDIT: The original code from 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  A: 

Given your code of getcameraOrientation the resulting matrix is quite obvious: forward = (0, 0, 1) yields z = (0, 0, -1), which corresponds to the 3rd line of the matrix. The cross product of z = (0, 0, -1) and FUp = (0, 1, 0) results in x = (1, 0, 0), which corresponds to the first line of the matrix. The second line is just a copy of FUp and the 4th line is just fixed.

I actually don't understand what you want to achieve, but when you rotate the camera you clearly loose sight of your object. In the real world if you look at a point and turn your head - it's the same thing. Have you tried to reverse the order of translation and rotation?

Uwe Raabe
He should be able to rotate around the forward vector without losing sight of his object.
Nosredna
I'm not rotating around the forward vector, I'm rotating according to the forward vector. In my case, where up is straight up the y-axis, this will be the same as a rotation around the y-axis. since forward is straight down the z axis, there shouldn't be any rotation at all. But there is, so I loose track of my object....
Vegar
Well the resultung matrix in your first case reverts the z axis. As you are "looking to" the positive z axis, reverting it will just "look back". So why is z calculated from the negative forward vector instead of just being a copy if it?
Uwe Raabe
I guess the real problem is that I don't understand what I'm doing here... :-/ Have added the original code from the OpenGL SuperBible to the initial post.
Vegar
If you don't understand what you are doing try using a wrapper around OpenGL like GLScene.
Uwe Raabe
That's what I'm telling my son at school also: If you don't understand addition, just use a calculator....
Vegar
My advice wasn't meant as an insult, just as a hint to some code that already does what you are trying to do. If you want to reinvent the wheel, fine. But you don't need to know how a motor or gear is working to drive a car.
Uwe Raabe
Trying to understand is the sole point of this little summer project of mine, so using a lot of wrappers kind of violate the idé. No hard sore feelings, though. Thanks for trying to help me out :-)
Vegar
+1  A: 

Identity matrix

I'm not sure why the SuperBible suggests using (-FForward.X, -FForward.y, -FForward.z) to create your Z vector. If you take out the minus signs then you will get the identity matrix that you expect when your forward vector is (0, 0, 1).

If you want to keep the minus signs, and you want a forward vector of (0, 0, -1) to produce an identity matrix, then you need to change your cross product from Cross(z, FUp) to Cross(FUp, z), because OpenGL uses a right-handed coordinate system. See Cross product.

15 in the wrong spot

I agree with you that I would expect a translation matrix to look like this:

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

Note though that OpenGL stores its matrix in column order not row order, so when you glGet the modelview matrix it will come out in this order:

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

If you thought that it was in row order then that may be what is causing the confusion.

Incredulous Monk