Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does my camera rotate around a point with this math?

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.

like image 461
user1175938 Avatar asked Nov 04 '22 06:11

user1175938


1 Answers

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.

like image 63
datenwolf Avatar answered Nov 11 '22 06:11

datenwolf