5

My camera rotates around a point when I try to change the orientation. If I rotate my camera, say, 30 degrees in the Y axis, instead of the camera looking 30 degrees to the right, the camera rotates around the point it was looking at.

o is the camera, A and B are 3D models. The lines show line-of-sight.
This is what I expect:
     A    B
     | > /
     |  /
     | /
     |/
     o

This is what actually happens:
     A    B
     |\
     | \
     |  \
     | > \
          o

Now, from my understanding, in order to move the camera I have to move the world by the inverse of that amount. So if I want to move +1 in the Z axis I translate the world -1 in the Z axis. Since I am using quaternions to represent orientations, I use the camera quaternion's inverse (since the orientations are always unit quaternions, I optimize by using the conjugate instead of calculating the inverse) to rotate the world by the right amount.

Here is how I convert a quaternion to a matrix, where q is the inverted quaternion:

[1 - 2 * (q.y * q.y + q.z * q.z)   2 * (q.x * q.y - q.w * q.z)       2 * (q.x * q.z + q.w * q.y)         0]
|2 * (q.x * q.y + q.w * q.z)       1 - 2 * (q.x * q.x + q.z * q.z)   2 * (q.y * q.z - q.w * q.x)         0|
|2 * (q.x * q.z - q.w * q.y)       2 * (q.y * q.z + q.w * q.z)       1 - 2 * (q.x * q.x + q.y * q.y)     0|
[0                                 0                                 0                                   1]

After that, I set the translation component of the matrix:

[...   ...   ...  -x]
|...   ...   ...  -y|
|...   ...   ...  -z|
[0     0     0     1]

And finally I multiply that onto the model-view matrix stack, then render all my objects. I am pretty sure this math is correct, but it doesn't produce the results that I was expecting. Clearly the forward and right vectors are the problem, so my only question is why are they wrong and how should they be set if I want to get the results I am expecting. Thanks.

EDIT: I have found the solution from this guy's quaternion camera class. First i construct a rotation matrix like i was doing before, but then I take the column vectors of the matrix from the first, second and third columns (xa, ya, and za respectively). Then I set the translational component of the matrix like this:

[...  ...  ...  -xa.dotProduct(cameraPos)]
|...  ...  ...  -ya.dotProduct(cameraPos)|
|...  ...  ...  -za.dotProduct(cameraPos)|
[...  ...  ...  ...                      ]

Then the resulting matrix can be multiplied onto the modelview matrix stack, and it works perfectly.

user1175938
  • 285
  • 1
  • 3
  • 6
  • Make your edit a solution and accept it. That's how we mark questions solved around here. Also I think you deserve some explanation what's going on. I will write an answer for this. – datenwolf Feb 02 '12 at 08:41

2 Answers2

2

EDIT: I have found the solution from this guy's quaternion camera class. First i construct a rotation matrix like i was doing before, but then I take the column vectors of the matrix from the first, second and third columns (xa, ya, and za respectively). Then I set the translational component of the matrix like this:

[...  ...  ...  -xa.dotProduct(cameraPos)]
|...  ...  ...  -ya.dotProduct(cameraPos)|
|...  ...  ...  -za.dotProduct(cameraPos)|
[...  ...  ...  ...                      ]

Then the resulting matrix can be multiplied onto the modelview matrix stack, and it works perfectly.

Yes, this is exactly what I would have suggested, only a bit different. You must understand, that OpenGL does not have a camera, but instead you just move the world in the opposite direction, so you need to find the inverse transformation matrix.

A camera just rotates about and moves. This makes things very simple. The tnverse of translation is just the same vector with opposite sign, and the inverse of a rotation matrix is it's transpose (column and rows exchanged). Now look at a homogenous transformation matrix like OpenGL uses them:

R t
0 1

The upper left 3×3 is the rotational part, the rightmost column is the translation vector. I think the rest you already figured yourself.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
0

To be honest, trying to find a matrix to multiply to the module-view matrix is really complicated and very error-prone. There is a lot of confusion and special cases. For example, if you are looking 90 degrees up, two of your axes become the same. A logical problem is this: if you are rolling your head back, so you pass through the top point, your up vector should be inverted, right? But what if you miss it by a 0.0001 degree? then you should turn your head around that point so your up vector is still up.

In my opinion, the best way is to approach the problem from another perspective. Let's assume two cases:

  • Upside down impossible:
    • Keep a point for your camera location and latitude/longitude for the direction. With simple sin/cos operations you can get a direction vector. Your up vector is (0, 1, 0)
    • Turning is simply changing the latitude and longitude
  • Upside down possible:
    • Besides the camera location, keep both up and target vectors.
    • When turning, compute right=target x up and then change target to x*right+y*up
    • You then need to normalize target vector and compute new up. Lot's of cases to handle though.

After all of these, you simply call gluLookAt.

Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • "To be honest, trying to find a matrix to multiply to the module-view matrix is really complicated and very error-prone." No, it's not. Matrices are the most strightforward way to think about relative coordinate orientations. Each of the first 3 columns is one of the base vectors of the transformed coordinate system. The 4th column is the relative translation. It's far easier to write down a camera matric from the view and target vectors, then with all that trigonometry inbetween. – datenwolf Feb 02 '12 at 11:36
  • I know that. What I am saying is that, if for example you have 3 different kinds of movements (say, move, twist and roll) until next frame, it's much easier to do so with position/latitude/longitude and finally converting it to a matrix, than to try to apply each operation to the matrix of the previous one. – Shahbaz Feb 02 '12 at 12:54