# How to Use a Quaternion as a Camera Orientation

This topic is 2071 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

So a while ago I was trying to figure out how to rotate objects using quaternions, and I eventually succeeded. Now, I'm trying to adapt the same system for use in my camera. I am coding in C++, using OpenGL and SFML. Here is how I rotate and translates objects at the moment:

 //Create change quaternions for each axis Quaternion xOffset = Quaternion(); xOffset.FromAxisAngle(Rotation.x * m_TurnSpeed, 1.0, 0.0, 0.0); Quaternion yOffset = Quaternion(); yOffset.FromAxisAngle(Rotation.y * m_TurnSpeed, 0.0, 1.0, 0.0); Quaternion zOffset = Quaternion(); zOffset.FromAxisAngle(Rotation.z * m_TurnSpeed, 0.0, 0.0, 1.0); //Multiply the change quats by the current quat m_Orientation = yOffset * zOffset * xOffset * m_Orientation; //Get matrix m_Orientation.Normalize(); m_Orientation.RotationMatrix(m_RotationMatrix); Translation = m_Orientation.MultVect(Translation); m_Position.x += (Translation.x * m_MoveSpeed); m_Position.y += (Translation.y * m_MoveSpeed); m_Position.z += (Translation.z * m_MoveSpeed); 

I apply m_RotationMatrix using glMultMatrix(), and m_Position using glTranslatef().

This works fine for objects rotating and translating about, but when I apply this to my camera, obviously things don't work. Now, I say obviously, because as far as I know, if I want to change the direction I'm "looking at" in OpenGL, I need to apply the reverse of the changes I'd apply to an object. However, I'm not quite sure how to do this, and all my attempts have failed.

Leaving everything exactly the same, I find rotations don't add up and translations are backwards or inverted. Inverting the input doesn't help.

I believe that using

 m_Orientation = m_Orientation * yOffset * zOffset * xOffset; 

Instead of the previous form is appropriate for the camera, and this is enough to fix all the rotation issues, but I simply can't manage to get translations to work after that. I can get close by adding the X and Y changes to the position normally and then subtracting the Z change from the position, but this still leads to wonky behavior when moving and rotating around the Z axis at the same time, and the object ends off spiraling away from the point it is supposed to be pointing towards.

So, any tips on how to adapt the above behavior for proper use as a camera?

Also, when applying a camera to OpenGL, to I need to use glPushMatrix() and glPopMatrix()? I ask because that helped some tests run better than others, but it doesn't seem to make sense to do so, since those are basically for pushing a new local space for transformations onto the stack (I'm horribly mangling my terminology, I'm sure). Edited by Saldan

##### Share on other sites
"Doing the reverse" means in this case m_TurnSpeed becomes "-m_TurnSpeed"
And, when translating, m_MoveSpeed is also negated "- m_MoveSpeed"

But don't change the order of the quaternion multiplcations, it's not the same. The idea behind the "camera matrix" (actually called view matrix) is that, if you can't the camera, move the whole world. This means if the camera is moved 2 units to the left, it's the same as if everything else moves 2 units to the right. Same with rotations, etc. You get the idea.

If you still don't get it working after negating those variables, the way you're extracting the translation part and then apply movement doesn't look quite right. Can't really tell without debugging the numbers.
If I'm not mistaken, that code should make the camera spin around the origin when trying to rotate, rather than rotating around it's center. But in the models you don't see it glitch like that because you normalize the matrix, and use glTranslate to let OpenGL perform the translation for you, so it miraculous works.

But in the camera, you don't have that, so if I'm not mistaken, you are unable to move it, right?

##### Share on other sites

"Doing the reverse" means in this case m_TurnSpeed becomes "-m_TurnSpeed"
And, when translating, m_MoveSpeed is also negated "- m_MoveSpeed"

But don't change the order of the quaternion multiplcations, it's not the same. The idea behind the "camera matrix" (actually called view matrix) is that, if you can't the camera, move the whole world. This means if the camera is moved 2 units to the left, it's the same as if everything else moves 2 units to the right. Same with rotations, etc. You get the idea.

See, I thought this was the case, but when I try that out (inverting m_TurnSpeed and m_MoveSpeed, leaving the order of the quaternion multiplication alone), what happens is the rotations are in the wrong direction, and they don't add up. So for example, if I turn to the right around the Y axis (by pressing the key meant to turn to the left), then try to rotate around the Z axis, I end up rotating around the global Z axis, not the camera's Z axis, i.e. I end up rotating around the camera's X axis (if it's a 90° turn). When I leave the values alone and reverse the multiplication order, rotation *appears* to work as expected (i.e. rotation around the Y axis, then around the Z axis, leads to a rotation around the new, post-Y-rotation Z axis and not the old one). It might not be, of course; if that's the case, then there's a deeper problem.

If you still don't get it working after negating those variables, the way you're extracting the translation part and then apply movement doesn't look quite right. Can't really tell without debugging the numbers.
If I'm not mistaken, that code should make the camera spin around the origin when trying to rotate, rather than rotating around it's center. But in the models you don't see it glitch like that because you normalize the matrix, and use glTranslate to let OpenGL perform the translation for you, so it miraculous works.

Hm, that could be a problem. Here is what MultVect() looks like:

 sf::Vector3<float> Quaternion::MultVect(sf::Vector3<float> Vector) { //From http://www.idevgames.com/articles/quaternions Quaternion VectorQuat = Quaternion(); VectorQuat.x = Vector.x; VectorQuat.y = Vector.y; VectorQuat.z = Vector.z; VectorQuat.w = 0.0; Quaternion Inverse = (*this); Inverse.Invert(); Quaternion Result = Inverse * VectorQuat * (*this); sf::Vector3<float> ResultVector; ResultVector.x = Result.x; ResultVector.y = Result.y; ResultVector.z = Result.z; return ResultVector; } 

I do use glTranslafef() when rendering the scene. Here is what that code looks like (it is called before anything else in the scene is rendered):

 //Rotate camera glMultMatrixf(m_PlayerCamera.GetMatrix()); //Translate camera sf::Vector3<float> CameraPos = m_PlayerCamera.GetPosition(); glTranslatef(CameraPos.x, CameraPos.y, CameraPos.z); 

But in the camera, you don't have that, so if I'm not mistaken, you are unable to move it, right?

It actually moves quite smoothly, just in the wrong direction. If I do the following, I get near-perfect movement so long as I don't try to rotate around the camera's Z axis.

 //Create new quaternions for each axis Quaternion xOffset = Quaternion(); xOffset.FromAxisAngle(Rotation.x * m_TurnSpeed, 1.0, 0.0, 0.0); Quaternion yOffset = Quaternion(); yOffset.FromAxisAngle(Rotation.y * m_TurnSpeed, 0.0, 1.0, 0.0); Quaternion zOffset = Quaternion(); zOffset.FromAxisAngle(Rotation.z * m_TurnSpeed, 0.0, 0.0, 1.0); //Multiply the new quaternions into the orientation m_Orientation = m_Orientation * yOffset * zOffset * xOffset; //Get matrix m_Orientation.Normalize(); m_Orientation.RotationMatrix(m_RotationMatrix); ///Translate camera Translation = m_Orientation.MultVect(Translation); m_Position.x += (Translation.x * m_MoveSpeed); m_Position.y += (Translation.y * m_MoveSpeed); m_Position.z -= (Translation.z * m_MoveSpeed); 

Now, mathematically, I'm almost certain something isn't right here, since that's not what I'd expect the proper operations to look like. Edited by Saldan

##### Share on other sites
Good news! I've solved the problem. The issue was that I should have been pushing a matrix created from the inverse of the Orientation (as well as reversing all the transformation data, i.e. the rotation and translation). What I do now is

 //Rotate camera glMultMatrixf( m_PlayerCamera.GetInvertedMatrix() ); //Translate camera sf::Vector3<float> CameraPos = m_PlayerCamera.GetPosition(); glTranslatef(CameraPos.x, CameraPos.y, CameraPos.z); 

Where GetInvertedMatrix() looks like this:

 GLfloat* Camera::GetInvertedMatrix() { //Get a new quaternion, the inverse of the Orientation Quaternion InvertedOrientation = m_Orientation; InvertedOrientation.Invert(); //Fill the matrix with the orientation InvertedOrientation.RotationMatrix(m_RotationMatrix); //Return that matrix return m_RotationMatrix; } 

Once I do this, everything works as intended.

In case anybody in the future is looking for the way to Invert() a quaternion, here's my code:

 void Quaternion::Invert() { float Length = 1.0 / (x*x + y*y + z*z + w*w); x *= -Length; y *= -Length; z *= -Length; w *= Length; } 

##### Share on other sites

In case anybody in the future is looking for the way to Invert() a quaternion, here's my code:

 void Quaternion::Invert() { float Length = 1.0 / (x*x + y*y + z*z + w*w); x *= -Length; y *= -Length; z *= -Length; w *= Length; } 

Right on. Clever way to minimize the division ops. This is a handy cheatsheet for quaternion ops/functions (the Boost code is good too, or was, last time that I checked):
http://world.std.com...ools/tools.html Edited by taby