The 2024 Wheel Reinvention Jam just concluded. See the results.

Using Quaternions for camera controller

Hi,

I'm making a fps style camera in a 3d game and was learning about Quaternions. I just want the camera to have pitch and heading, but no bank. And not track euler angles over multiple frames. Whats the best way to do this? The code I have looks like this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//Get the change in mouse position
V2 diff = normalize(v2_minus(mouseP, state->lastMouseP));

float sensitivity = 3;
float angleX = sensitivity*diff.y*dt;
float angleY = -sensitivity*diff.x*dt;

Quaternion rot = eulerAnglesToQuaternion(angleY, angleX, 0);

//rotate the camera orientation by the change in rotation 
camera.orientation = quaternion_mult(camera.orientation, rot);


I was wondering if this looks correct and is it equivalent to the below code, which is tracking Euler angles over frames.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    static V2 eulerXY = {};

    float sensitivity = 3;
    float angleX = sensitivity*diff.y*dt;
    float angleY = -sensitivity*diff.x*dt;

    eulerXY.x += angleX;
    eulerXY.y += angleY;

    camera.orientation = eulerAnglesToQuaternion(eulerXY.y, eulerXY.x, 0);
   


Also in the first code snippet, is:
1
camera.orientation = quaternion_mult(camera.orientation, rot);


the same as:
1
camera.orientation = quaternion_mult(rot, camera.orientation);


Thanks for your help, any info about the best way to use Quaternions would be great.

Edited by Oliver Marsh on Reason: Initial post
I can't help you much but according to wikipedia, quaternion multiplication isn't commutative.
Hello Oliver,

Imagine your heading is zero and your pitch is 45 degrees. Now you move the mouse to the left to produce a 90 degrees rotation.

In your second snippet it will be ok, your heading is now 90 and your pitch is still 45.

But in your first snippet the rotation will happen respective to your current orientation, so your new heading is 90 degrees, your new pitch is 0, and your bank is 45 degrees.

So maybe I'm wrong but I think your two snippets are not equivalents. You probably want the second one, because a change in heading always produce a rotation around a vertical axis, whereas your first snippet a change in heading will produce a rotation around an axis which depends on your previous pitch/axis angles.

Also, as Simon said, quaternion multiplication is not commutative, since rotations of the unit sphere are not.

For instance, if you reverse my previous example and first rotate 90 degrees to the left, then 45 degrees up, you will end up with a different orientation (ie, heading = 90, pitch = 45, bank = 0).
Thanks Martin and Simon,
Yes I think I understand a bit better. The banking is what prompted the question, the camera seemed to introduce bank after looking around, and I couldn't understand why. Could you say the tracking euler angles method has knowledge of the original 'correct' orientation, i.e. looking down the z axis (since we only ever rotate once from this orientation), whereas the first snippet only knows of it's previous frame orientation?

Thanks, Oliver

Edited by Oliver Marsh on
Yes you could put it that way.
In the euler angles method you always rotate from an original (x,y,z) basis.
In the quaternion multiplication method, you rotate a basis attached to the camera itself, so the next rotation will happen relative to that new basis, and so on.