• 11
• 27
• 9
• 20
• 31

# Issues With Quaternion Based Camera

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

## Recommended Posts

I'm attempting the implement a quaternion based camera but I am having issues with the rotation.

My camera has an origin and an orientation (quaternion). The origin and quaternion are lerped and slerped between logical updates. The camera vector components (direction, origin, up, left) are computed every frame for the renderer (in my case it goes directly into a gluLookAt()):

 void Camera::update() { direction = (orientation * Vector<3>(0, 0, 1)).normalize(); up = (Vector<3>(0, 1, 0)).normalize(); left = Vector<3>::cross(up, direction); } void Camera::translate(const Vector<3>& amount) { origin += amount; } void Camera::rotate(const Vector<3>& axis, const Angle& angle) { orientation *= Quaternion<>::fromAxisAngle(axis, angle); orientation.normalize(); } 

This all seems to work fine, but when I rotate the camera by the mouse then I get strange results. Here is the camera rotation code (Lua):

 self.camera : rotate(self.camera.left, Angle(self.rotateVelocity.y)) self.camera : rotate(self.camera.up, Angle(self.rotateVelocity.x)) self.camera : translate(self.velocity) 

(self.rotateVelocity is the change in mouse coordinates)

At first the rotation appears to be correct, but as I turn the camera around the y-axis rotation inverts (moving mouse up makes camera rotate down) and if I face left the camera does not rotate at all vertically. It seems as though my camera's left vector is incorrect, but I know that it is correct (camera strafing works).

I am also sure that my quaternion rotation is correct, I believe I am just using them incorrectly. Is there anything obviously wrong with my approach?

##### Share on other sites
You code to perform a rotation using a quaternion is not correct. If q is a unit quaternion and v is a vector you want to rotate, then the correct rotated vector is

u = q v q[sup]-1 [/sup]= q v q*,

where q* is the quaternion conjugate of q. The correct code should be something like:

 void Camera::rotate(const Vector<3>& axis, const Angle& angle) { Quaternion<> q = Quaternion<>::fromAxisAngle(axis, angle); orientation = q * orientation * q.inverse(); orientation.normalize(); } 

##### Share on other sites

You code to perform a rotation using a quaternion is not correct. If q is a unit quaternion and v is a vector you want to rotate, then the correct rotated vector is

u = q v q[sup]-1 [/sup]= q v q*,

where q* is the quaternion conjugate of q. The correct code should be something like:

 void Camera::rotate(const Vector<3>& axis, const Angle& angle) { Quaternion<> q = Quaternion<>::fromAxisAngle(axis, angle); orientation = q * orientation * q.inverse(); orientation.normalize(); } 

I don't know if this affects your answer or not... but when I multiply a quaternion by a vector I believe it is calculating the rotation. I honestly didn't attempt to understand the math behind this when I implemented it, I was just looking for a quick solution:

 template <class T> Vector<3, T> Quaternion<T>::operator*(const Vector<3, T>& vector) const { Vector<3> uv, uuv; uv = Vector<3, T>::cross(v, vector); uuv = Vector<3, T>::cross(v, uv); uv = uv * (2.0 * w); uuv = uuv * 2.0; return vector + uv + uuv; } 

Does that code not rotate the vector by the given quaternion?

edit: I have implemented what you have suggested and I still am not seeing correct results:

 template <class T> Quaternion<T> Quaternion<T>::inverse() const { return Quaternion(w, -v); } //... void Camera::rotate(const Vector<3>& axis, const Angle& angle) { Quaternion<> q = Quaternion<>::fromAxisAngle(axis, angle); orientation = q * orientation * q.inverse(); orientation.normalize(); } 

edit again: More specifically, when I add the inverse to the multiply no rotation ever occurs.

##### Share on other sites
I believe I have found the answer. I had to re-implement my quaternion/vector multiply and I appear to be seeing correct results:

 template <class T> Vector<3, T> Quaternion<T>::operator*(const Vector<3, T>& vector) const { Quaternion<T> q(0, vector); q *= this->inverse(); return (*this * q).v; } 

Thank you for the help. I always find a way to confuse myself when using quaternions.

##### Share on other sites
Your inverse isn't correct. Conjugation and inversion are equal only when working on unit quaternions (i.e. quaternions such that the norm is 1). More generally, the inverse quaternion is given by

q[sup]-1[/sup] = q[sup]*[/sup]/(qq[sup]*[/sup]).

The correct implementation of inverse and conjugate are therefore something like

 template <class T> Quaternion<T> Quaternion<T>::conjugate() const { return Quaternion(w, -v); } template <class T> T Quaternion<T>::norm() const { return w*w + v.lengthSquared(); } template <class T> Quaternion<T> Quaternion<T>::inverse() const { T n = this->norm(); return Quaternion(w / n, - v / n); } 

I find quite confusing to use the product to do rotation when working with quaternions. In mathematics the product between a quaternion and a 3D vector is usually interpreted as a quaternion product.

##### Share on other sites
Just to reinforce what apatriarca said, you definitely don't want to implement the * operator as rotation of a vector by a quaternion (IMO), as it's counterintuitive, potentially confusing, and mathematically incorrect.

(Some math libraries do use the * operator for this, so obviously not everyone agrees with the above, but nevertheless I strongly recommend avoiding ambiguous overloading of this sort.)