Quaternion woes

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

Recommended Posts

Like everyone else in the world, judging from the number of quaternion threads in this section, ive been *trying* to implement a quaternion camera. And i have been largely successful, except for one annoying effect i cannot seem to get rid of.

Here is my Camera class (the relevant parts anyway)

const Vector3 xAxis(1.0f, 0.0f, 0.0f); const Vector3 yAxis(0.0f, 1.0f, 0.0f); const Vector3 zAxis(0.0f, 0.0f, 1.0f); const Quaternion Xaxis(1.0f, 0.0f, 0.0f, 0.0f); const Quaternion Yaxis(0.0f, 1.0f, 0.0f, 0.0f); const Quaternion Zaxis(0.0f, 0.0f, 1.0f, 0.0f); Camera::Camera(Vector3 position) { Position = position; Rotation = Quaternion(0.0f, 0.0f, 0.0f, 1.0f); Velocity = Pitch = Heading = 0.0f; } void Camera::Move(float speed) { Vector3 direction = Rotation * Vector3(0.0f, 0.0f, speed); Position += direction; } void Camera::Strafe(float speed) { Vector3 direction = Rotation * Vector3(speed, 0.0f, 0.0f); Position += direction; } void Camera::Look() { // Form rotation quaternion // Quaternion pitch; pitch.FromAxis(xAxis, -Pitch); Quaternion heading; heading.FromAxis(yAxis, Heading); Rotation = pitch * heading; // Apply quaternion // float RotationMatrix[16]; Rotation.GetMatrix(RotationMatrix); glMultMatrixf(RotationMatrix); // Translate position // glTranslatef(-Position.x, -Position.y, Position.z); }

Pitch refers to the rotation about the x axis, while heading refers to the y rotation. This code works when im simply looking around (not changing my position), so i believe my GetMatrix and Rotation quaternion setup is correct. However, problems start occuring when i do move. If i rotate around the x-axis (pitch), the movement distorts considerably. If i am turned 90 degrees on the y axis and 45 on the x axis, strafing actually causes my Position.y to change! Also, if i simply call Move, the camera moves towards the wrong center.

But if my Rotation matrix is right, then that means that the problem lies here:
 Vector3 direction = Rotation * Vector3(0.0f, 0.0f, speed); Position += direction;

(and same for the strafing function)

So here is the code for vector rotation using a quaternion:

Vector3 Quaternion::operator* (const Vector3& v) { Quaternion vecQuat, resQuat; vecQuat.x = v.x; vecQuat.y = v.y; vecQuat.z = v.z; vecQuat.w = 0.0f; resQuat = vecQuat * GetConjugate(); resQuat = *this * resQuat; return Vector3(resQuat.x, resQuat.y, resQuat.z); }

As far as I can tell there is nothing wrong with that as well.

What gives?

Share on other sites
I suppose you use Camera::Look() to setup your view matrix? My guess would be that this part is where your problem is. Also, if you want a 6-DoF camera, you shouldn't be keeping pitch and heading separately - accumulate all orientation changes in your Rotation quaternion instead.

Of course, it depends on how you setup the rest of your transforms, but I would do something like this:

void Camera::Look() { glLoadIdentity(); glTranslatef(-Position.x, -Position.y, -Position.z); // Apply quaternion // float RotationMatrix[16]; Rotation.Inverse().GetMatrix(RotationMatrix); glMultMatrixf(RotationMatrix); }

Share on other sites
This code worked !:

 Quaternion pitch; pitch.FromAxis(xAxis, Pitch); Quaternion heading; heading.FromAxis(yAxis, -Heading); Rotation = heading * pitch; // Apply quaternion // float RotationMatrix[16]; Rotation.GetConjugate().GetMatrix(RotationMatrix); glMultMatrixf(RotationMatrix); glTranslatef(-Position.x, -Position.y, -Position.z);;

I have a few questions about why though:

Why do you need to get the inverse (conjugate in this case) of the Rotation quaternion before getting its matrix? I have never seen this before.
Why did you put glTranslatef before the view transform?

Thanks

Share on other sites
Well, the order of transformations is pretty much arbitrary. However, the results differ depending on the order you apply rotation, scale and translation. You have to be aware of that and pick the order that yields your desired result. I usually use scale, rotate, translate (SRT).

In any case, the reason why you have to use the inverse of the rotation is the following. In order to transform your view, what you want to be doing is translate all objects by the inverse of the view transformation. The inverse of a product of matricies is the reversed product of their inverses, so (SRT)^-1 = T^1R^1S^1. The inverse of a translation is simply its negation. The inverse of a rotation represented by a quaternion is its inverse (or if the quaternion is normalized, the conjugate).

Share on other sites

Well, the order of transformations is pretty much arbitrary. However, the results differ depending on the order you apply rotation, scale and translation. You have to be aware of that and pick the order that yields your desired result. I usually use scale, rotate, translate (SRT).

In any case, the reason why you have to use the inverse of the rotation is the following. In order to transform your view, what you want to be doing is translate all objects by the inverse of the view transformation. The inverse of a product of matricies is the reversed product of their inverses, so (SRT)^-1 = T^1R^1S^1. The inverse of a translation is simply its negation. The inverse of a rotation represented by a quaternion is its inverse (or if the quaternion is normalized, the conjugate).

Oh wow, did not think of it that way.

That makes sense. I guess before when i was applying the incorrect quaternion i was unknowingly compensating for it by changing random things in my other functions. All is back to normal though.

Thanks again

Share on other sites
The quaternion is conjugated because Camera::Look() is (presumably) intended to set up a view matrix, which is typically the inverse of the model/object/world matrix for the same object. The inverting of the rotation and translation and the changing of the transform order (translate first, then rotate) has the desired effect of creating the inverse transform. [Edit: As kloffy said.]

Also, I think it's worth noting that the use of quaternions in this context is more or less pointless. (Maybe there's more to it than what you posted, but as far as the code excerpts shown are concerned at least, the use of quaternions doesn't gain you anything.)

1. 1
2. 2
3. 3
4. 4
Rutin
15
5. 5

• 13
• 26
• 10
• 11
• 9
• Forum Statistics

• Total Topics
633724
• Total Posts
3013556
×