9
votes

I want to add an euler angle to an existing quaternion. Here is what i got:

Quaternion oldTransform = transform.Rotation;

float YawRotation = mouseDiff.x *  RotationSpeed;
Quaternion YawRotationQuaternion = new Quaternion();
YawRotationQuaternion.CreateFromAxisAngle (0, 1, 0, YawRotation);

float PitchRotation = mouseDiff.y * RotationSpeed;
Quaternion PitchRotationQuaternion = new Quaternion();
PitchRotationQuaternion.CreateFromAxisAngle ( 1, 0, 0, PitchRotation);

Quaternion result = oldTransform * YawRotationQuaternion * PitchRotationQuaternion;
transform.Rotation = result;

I want to have only yaw and pitch rotation. The old transform has this property. My euler angles I add to it are also only pitch and yaw rotations. What happens when i multiply it is that the rotation that oldTransform describes introduces a roll rotation.

Then i tried:

Quaternion result = YawRotationQuaternion * oldTransform * PitchRotationQuaternion;

This introduces no roll rotation. This option is even worse as it has a gimbal lock when oldTransform rotates the yaw-axis onto the pitch-axis.

Now what I could imagine is that one gets the old yaw and pitch rotation from the oldTransform and modifies the yaw and pitch-axis so that they are not (0,1,0) and (1,0,0) anymore. The problem here is that when I extract the euler angles from the quaternion I get gimbal locks as well.

So how do you add an euler angle of a specific axis to a quaternion?

1
Suddenly, I feel dumb.Bill Gregg
I am sorry, that was not my intention...jsf
:) Of course not, it's not your fault. Good question.Bill Gregg
Gimbal lock is what happens when you use pitch/yaw/roll or euler angles. You can't get around this. That's one reason why quaternions are used. What are you actually trying?Nico Schertler
This explains your problem quite nicely: math.stackexchange.com/questions/8980/…Tilo

1 Answers

5
votes

Solution:

Change the order of your transformations.

Quaternion result = PitchRotationQuaternion * oldTransform * YawRotationQuaternion;

Explanation:

You have an object with a local reference frame. I'll say that +x_o is toward the object's right, -z_o is "forward" and +y_o is "up" with respect to the object. The object exists in the world's reference frame. The world has its own axes: (x_w,y_w,z_w) with +y_w being the world's up. When the object changes orientation, you want it to pitch (rotate around x_o), and yaw (rotate around y_w).

In your code, you create two quaternions. The way you apply them represents rotations around x_w, and y_w. If there is any yaw already applied to the transformation, then x_o is no longer aligned with x_w; consequently, you'll get some roll. Fortunately, for the transformations you're applying, gimbal lock isn't a problem. Gimbal lock would be manifest here by the fact that if you pitch by 90 degrees, yaw and roll become the same thing. But your not using roll; so it doesn't matter.

Your transform can always be represented as a rotation around x_w followed by a rotation around y_w. Putting the new "pitch quaternion" on the left side of the old transform adds it to the other accumulated pitch. Keeping the "yaw quaternion" on the right adds it to the accumulated yaw. So if you were to represent the final quaternion as a bunch or multiplications, it would be a string of pure rotations around x_w followed by a string of rotations around y_w. As long as the object starts of with x_o parallel to x_w, this does what you want.