Multiplying multiple quaternions spins character out of control

I had a problem with my player look script where i make a xQuat and yQuat from the players mouse input and rotate the player to that rotation, those two work fine together, but I wanted the player to roll left and right and added a 3. quaternion for that but when i multiply the 3 together the character would spin out of control but only after rotating a certain varying amount.

//works fine
transform.rotation = xQuat * yQuat;

//spins out of control
transform.rotation = xQuat * yQuat * rollQuat;

I ended up doing this:

transform.rotation = xQuat * yQuat;
transform.Rotate(0, 0, rollAngle);

And that fixed the problem, but now since the input needs to be rotated to match the roll i changed how i got the x and yquat like this:

rotation.x += Input.GetAxis(xAxis) * sens;
rotation.y += Input.GetAxis(yAxis) * sens;
rotation.y = Mathf.Clamp(rotation.y, -90, 90);
//xQuat = Quaternion.AngleAxis(rotation.x, Vector3.up); //old x and y quat
//yQuat = Quaternion.AngleAxis(rotation.y, Vector3.left);

xQuat = Quaternion.AngleAxis(rotation.x, transform.up); //new x and y quat
yQuat = Quaternion.AngleAxis(rotation.y, -transform.right);

But that spins the character out of control, instead of before when rolling, now it spins when moving the mouse... I'm not very familiar with quaternions or rotations in general and i'm quite lost, any help or suggestions would be appreciated.

Don't touch the w, x, y or z components of a quaternion unless you have a math degree. They do not correspond to what you think they are.

It's important to note that the order that you combine two quaternions (done by multiplying them) does matter. I believe the one on the left will be the one you're 'adding' to. Sometimes you may need to start with a Quaternion.identity and add all your other rotations on top of that.

1 Like
public static Quaternion YawPitchRoll(float yaw, float pitch, float roll)
{
    Quaternion heading = Quaternion.AngleAxis(yaw, Vector3.up);
    Quaternion attitude = Quaternion.AngleAxis(pitch, Vector3.right);
    Quaternion bank = Quaternion.AngleAxis(roll, Vector3.forward);
    return heading * attitude * bank;

    //  transform.rotation *= YawPitchRoll(yaw, pitch, roll);
    ///// Instead of
    /////  transform.rotation *= Quaternion.Euler(pitch, yaw, roll);
    //
    // The Euler() function also applies three independent rotations.
    // There would be a natural expectation that you could use the Euler
    // angles to specify such a straightforward rotation.  However,
    // the order of rotations hardwired into Unity's function will cause
    // a gimbal lock situation and much confusion for the rotations.
    // The built-in Unity ordering for Quaternion.Euler() is Z, X, Y.
    // We want Y, X, Z.
    //
    // (Clarification: there is *always* a gimbal lock situation for
    // applying Euler angles in any order, but which order you choose
    // will determine what scenarios are likely to end up locked with
    // two axes merged into a single pole.  The Unity default ordering
    // is simply not helpful for flight-simulator type applications,
    // so we avoid it with this calculation instead.)
}
1 Like