4
votes

In OpenGL I'm trying to create a free flight camera. My problem is the rotation on the Y axis. The camera should always be rotated on the Y world axis and not on the local orientation. I have tried several matrix multiplications, but all without results. With

camMatrix = camMatrix  * yrotMatrix 

rotates the camera along the local axis. And with

camMatrix = yrotMatrix * camMatrix

rotates the camera along the world axis, but always around the origin. However, the rotation center should be the camera. Somebody an idea?

4
It's sad to see people ask questions here, people go out of their way to answer those questions, then the asker never returns to give feedback or simply accept an answer.Jerry Dodge
@JerryDodge: +1. Maybe a new parasite tag should be added to the SE network...code_dredd
@ray We call them "Help Vampires".Jerry Dodge
@JerryDodge: Noted. Wasn't aware of the term, but did find this SE post on the topic after you mentioned it.code_dredd

4 Answers

6
votes

One of the more tricky aspects of 3D programming is getting complex transformations right.

In OpenGL, every point is transformed with the model/view matrix and then with the projection matrix.

the model view matrix takes each point and translates it to where it should be from the point of view of the camera. The projection matrix converts the point's coordinates so that the X and Y coordinates can be mapped to the window easily.

To get the mode/view matrix right, you have to start with an identity matrix (one that doesn't change the vertices), then apply the transforms for the camera's position and orientation, then for the object's position and orientation in reverse order.

Another thing you need to keep in mind is, rotations are always about an axis that is centered on the origin (0,0,0). So when you apply a rotate transform for the camera, whether you are turning it (as you would turn your head) or orbiting it around the origin (as the Earth orbits the Sun) depends on whether you have previously applied a translation transform.

So if you want to both rotate and orbit the camera, you need to:

  1. Apply the rotation(s) to orient the camera
  2. Apply translation(s) to position it
  3. Apply rotation(s) to orbit the camera round the origin
  4. (optionally) apply translation(s) to move the camera in its set orientation to move it to orbit around a point other than (0,0,0).

Things can get more complex if you, say, want to point the camera at a point that is not (0,0,0) and also orbit that point at a set distance, while also being able to pitch or yaw the camera. See here for an example in WebGL. Look for GLViewerBase.prototype.display.

The Red Book covers transforms in much more detail.

Also note gluLookAt, which you can use to point the camera at something, without having to use rotations.

3
votes

Rather than doing this using matrices, you might find it easier to create a camera class which stores a position and orthonormal n, u and v axes, and rotate them appropriately, e.g. see:

https://github.com/sgolodetz/hesperus2/blob/master/Shipwreck/MapEditor/GUI/Camera.java

and

https://github.com/sgolodetz/hesperus2/blob/master/Shipwreck/MapEditor/Math/MathUtil.java

Then you write things like:

if(m_keysDown[TURN_LEFT])
{
    m_camera.rotate(new Vector3d(0,0,1), deltaAngle);
}

When it comes time to set the view for the camera, you do:

gl.glLoadIdentity();
glu.gluLookAt(m_position.x, m_position.y, m_position.z,
              m_position.x + m_nVector.x, m_position.y + m_nVector.y, m_position.z + m_nVector.z,
              m_vVector.x, m_vVector.y, m_vVector.z);

If you're wondering how to rotate about an arbitrary axis like (0,0,1), see MathUtil.rotate_about_axis in the above code.

2
votes

If you don't want to transform based on the camera from the previous frame, my suggestion might be just to throw out the matrix compounding and recalc it every frame. I don't think there's a way to do what you want with a single matrix, as that stores the translation and rotation together.

I guess if you just want a pitch/yaw camera only, just store those values as two floats, and then rebuild the matrix based on that. Maybe something like pseudocode:

onFrameUpdate() {
  newPos = camMatrix * (0,0,speed) //move forward along the camera axis
  pitch += mouse_move_x;
  yaw += mouse_move_y;

  camMatrix = identity.translate(newPos)
  camMatrix = rotate(camMatrix, (0,1,0), yaw)
  camMatrix = rotate(camMatrix, (1,0,0), pitch)
}
0
votes

rotates the camera along the world axis, but always around the origin. However, the rotation center should be the camera. Somebody an idea?

I assume matrix stored in memory this way (number represent element index if matrix were a linear 1d array):

0   1   2   3    //row 0
4   5   6   7    //row 1
8   9   10  11   //row 2
12  13  14  15   //row 3

Solution:

  1. Store last row of camera matrix in temporary variable.
  2. Set last row of camera matrix to (0, 0, 0, 1)
  3. Use camMatrix = yrotMatrix * camMatrix
  4. Restore last row of camera matrix from temporary variable.