Quaternion Multiplication in Unity: Why the Order Matters and How to Get It Right

This article is a translated version of my original post on Qiita. Original (Japanese): https://qiita.com/segur/items/0b8e3d74c7d11c60436a

Quaternion Rotation Example

Quaternion Multiplication in Unity: Why the Order Matters and How to Get It Right

In developing 3D games with Unity, we often deal with object rotations. Among the various methods, quaternions play a crucial role, but did you know that the computation result changes based on the multiplication order? Misunderstanding this can lead to bugs!

In this article, I'll explain how quaternion multiplication order affects results in Unity and how to handle it properly.

The Basics of Quaternions

When dealing with rotations in Unity, Euler angles might seem more intuitive. However, Euler angles suffer from gimbal lock, which quaternions help solve. Quaternions are implemented in Unity as the Quaternion class.

For instance, to rotate an object around the X-axis by -90°, you would write:

transform.rotation = Quaternion.Euler(-90, 0, 0);

Here's an example:

No Rotation
-90° Rotation on X-axis

Incidentally, the shrimp model is homemade. For those interested, see here: https://segur.booth.pm/items/2501347

Quaternion Multiplication

When you want to rotate an already rotated object further, you perform quaternion multiplication.

For instance, if you want to rotate an object already rotated by -90° on the X-axis by an additional -90° on the Y-axis, write:

transform.rotation = Quaternion.Euler(0, -90, 0) * Quaternion.Euler(-90, 0, 0);

This results in a sequential rotation like this:

No Rotation
-90° on X-axis
Quaternion.Euler(-90, 0, 0)
-90° on X-axis then -90° on Y-axis
Quaternion.Euler(0, -90, 0) * Quaternion.Euler(-90, 0, 0)

The Order of Quaternion Multiplication

Interestingly, the order of quaternion multiplication matters! The following code snippets yield different results:

// Rotate around Y-axis then X-axis
transform.rotation = Quaternion.Euler(0, -90, 0) * Quaternion.Euler(-90, 0, 0);

// Rotate around X-axis then Y-axis
transform.rotation = Quaternion.Euler(-90, 0, 0) * Quaternion.Euler(0, -90, 0);

A visual comparison highlights the difference:

No Rotation
-90° on X then -90° on Y
Quaternion.Euler(0, -90, 0) * Quaternion.Euler(-90, 0, 0)
-90° on Y then -90° on X
Quaternion.Euler(-90, 0, 0) * Quaternion.Euler(0, -90, 0)

Let's focus on multiplication order:

Yes, the order is reversed! It's counterintuitive.

So, remember to multiply in the reverse order of the rotation sequence when using quaternions! (The reason is explained further below.)

Failing to keep this in mind while programming could lead to bugs.

Why the Reverse Order?

If you're told to multiply in reverse order, it may not make much sense. Here's a more detailed explanation.

Earlier, we assumed the coordinate system didn't move. However, considering quaternions rotate the entire coordinate system makes it more intuitive.

Let's interpret quaternion multiplication like so:

Thus, Quaternion.Euler(0, -90, 0) * Quaternion.Euler(-90, 0, 0) can be understood as:

No Rotation
Quaternion.Euler(0, -90, 0) rotates the coordinate system, including the object, by -90° on the Y-axis, defining new axes. The X-axis (red) was originally the direction of the Z-axis. The Y-axis (green) remains the same. The Z-axis (blue) was originally the opposite of the direction of the X-axis.
Quaternion.Euler(-90, 0, 0) rotates the coordinate system, including the object, by -90° on the X-axis, defining new axes. The X-axis (red) remains unchanged. The Y-axis (green) was originally the opposite direction of the Z-axis. The Z-axis (blue) was originally the direction of the Y-axis.

As interpreted above, considering the rotation of the entire coordinate system, the object seems to rotate in the same order as the quaternion multiplication, aligning with intuition.

"Multiplying in reverse order" is merely an explanation to make sense if we interpret it as the coordinate system being fixed.

Understanding this allows you to use quaternion multiplication correctly!

Conclusion

This article was informed by the following page. Thank you for the clear explanation!

I hope this article helps you prevent bugs related to quaternion behavior!