- Home /

# Quaternion multiplication order

If I understand correctly multiplying two quaternions together is equivalent to applying the rotation of the first quaternion then the rotation of the second. In the Unity documentation it is stated :

`Rotating by the product lhs * rhs is the same as applying the two rotations in sequence, rhs first and then rhs`

The end of the sentence does not make sense for me. I would except either *rhs first and then lhs* or *lhs first and then rhs*. Can someone tell me which one of the two is correct ?

The documentation has been updated, and now reads: "Rotating by the product `lhs * rhs`

is the same as applying the two rotations in sequence: `lhs`

first and then `rhs`

, relative to the reference frame resulting from `lhs`

rotation." As Owen-Reynolds points out in his answer, below, it is left-to-right if you think of each transform being applied as a *local rotation*. If you want to think about applying transforms 'as if you're using the global rotation tool,' read it right-to-left instead.

**Answer** by Owen-Reynolds
·
Oct 16, 2014 at 04:47 PM

Combining rotations (and using Quaternions) is one of those things where Unity just copies the way everyone else does it. So you can find better descriptions in general gaming-math sites.

The missing piece is local vs. global. If you have rotations `A*B`

you can think of it as applying A as a global rotation to B. Or as applying B as a local rotation to A(*).

In other words, suppose R is the current rotation, and Ry is a small spin on Y, which you would like to apply. To apply it as if you're using the global rotation tool, use `Ry*R`

. To apply the spin as if using the rotation tool set to local, use `R*Ry`

.

In other, other words. `A*B`

is B applied on local A, or global A applied to B, depending on how you want to think of it. Yes, it is very confusing until you settle on the "right" way to think of it for any particular problem.

Robot hand is a common example. To find the rotation of a hand bone, use globalRbotSpin * localShoulderSpin * localElbowSpin ... . All rotations are stored and applied locally.

(*) I always get the orders mixed up, and my Unity machine isn't here. It could be the other way -- left is local and right is global.

Your logic of *“applying A as a global rotation to B. Or as applying B as a local rotation to A”* matches my own findings. I believe you can remove the *“I always get the orders mixed up”* footnote.

Can confirm: You have the order correct. (No need for the final paragraph/disclaimer.)

**Answer** by CHPedersen
·
Oct 16, 2014 at 01:32 PM

That is an *excellent* question, and clearly identifies a typo in the Unity docs. :)

The correct description should be "lhs first, then rhs". I created this little script to test it for you:

```
public class RotationFun : MonoBehaviour {
// Use this for initialization
void Start () {
Quaternion x90 = Quaternion.AngleAxis(90, Vector3.right); // 90 degrees around the x axis
Quaternion z90 = Quaternion.AngleAxis(90, Vector3.forward); // 90 degrees around the z axis
Quaternion x90z90Concat = x90 * z90; // The concatenation of first 90 degrees around the x axis, then 90 degrees around the z axis
Quaternion z90x90Concat = z90 * x90; // The opposite concatenation
// Apply the two single rotations one by one, then print the rotation
transform.rotation *= x90;
transform.rotation *= z90;
Debug.Log("Quaternion result of two rotatons in sequence: " + transform.rotation);
// Reset to identity
transform.rotation = Quaternion.identity;
// Now apply the first concatenation, i.e. lhs then rhs, then print to see
transform.rotation *= x90z90Concat;
Debug.Log("Quaternion result of two rotations combined lhs then rhs: " + transform.rotation);
// Reset to identity
transform.rotation = Quaternion.identity;
// Now apply the second concatenation, i.e. rhs then lhs, then print to see
transform.rotation *= z90x90Concat;
Debug.Log("Quaternion result of two rotations combined rhs then lhs: " + transform.rotation);
}
}
```

Slapping this onto a gameobject with 0's in position and rotation yields these prints to the console:

Quaternion result of two rotatons in sequence: (0.5, -0.5, 0.5, 0.5)

Quaternion result of two rotations combined lhs then rhs: (0.5, -0.5, 0.5, 0.5)

Quaternion result of two rotations combined rhs then lhs: (0.5, 0.5, 0.5, 0.5)

As you can see, doing the two rotations sequentially is clearly the same as multiplying them together LEFT to RIGHT. When switched, the rotation does not contain the same values (and will be visually different).

This isn't such a big surprise, first of all since matrix multiplication isn't *cummutative*, i.e. the order matters, and secondly, because multiplication in C# has left to right associativity, i.e. it is evaluated left to right.

Thanks, all I wanted to know. So, am I right saying that quaternion rotation applying order is reversed in regard to matrix transformation applying order ?

I think that is a correct statement, yes. My linear algebra classes in uni can be slightly foggy, but I do remember that matrix transformations in math notation are applied right-to-left. Check out this post and particularly the answer beneath it:

http://gamedev.stackexchange.com/questions/29260/transform-matrix-multiplication-order

The answer writes L = T * R * S, and then goes on to describe how one scales first, then rotates, then translates, which indicates that that notation clearly uses right-to-left, like normal math. Indeed, in Unity, the method for creating L also does happen to be called Matrix4x4.TRS. But in manual code, it should be left-to-right because of .Net's multiplicative associativity.

If you feel answers have helped you, please consider hitting the checkmark on the post. :)

This comment shows up in google as being a reasonable explanation, but the Unity docs are actually correct and the results of the author are caused by way that they are performing the test.

First, quaternion multiplications *are* associative, but *not* commutative, in other words, `(a*b)*c == a*(b*c)`

, but `a*b != b*a`

. To understand where this answer goes wrong is using the `*=`

operator on the rotation. To understand why, `a *= b -> a = a*b`

, so `a *= b; a *= c;`

is actually `(a*b)*c`

, which is why they come to the conclusion that the order of application is left -> right. However, the order of composition of the rotations (the order that they are applied to a vector or transform) is actually right to left. So if you have a vector `v`

, then `a*b*c*v`

is `v`

rotated by `c`

, then rotated by `b`

, then rotated by `a`

.

It's unusual to use the `*=`

operator on a rotation like that. I've certainly never seen anyone do that other than here. The reason is that it is normally the opposite of what you want.

When the docs say that the rotations are done "in sequence" it means "the sequence described as follows: rhs followed by lhs", not the sequence they appear in the expression (lhs * rhs).

If you are still unclear, I would suggest doing some experiments until it sinks in, not using euler angles, but using AngleAxis. The problem with euler angles is that they also have an implicit order.

Note: if Unity had wanted left->right ordering of the rotations, they would have overloaded the operator*(Quaternion, Vector3) in the reverse order so that it was operator*(Vector3, Quaternion). That would be a very unusual way to do it though.

**Answer** by winxalex
·
Nov 30, 2019 at 05:01 PM

SUPER SIMPLE:

```
//Note: Rotation values in Inspector are in Local space
//Let say Quaternion is something that contain information of how some 3D object is rotated
//for simplicity we will use just rotation aroundY and let say we have one parent game object and one child
//let parent is rotated 60 degree, and child is 30degree.
//as parent is first element in the world and world is not rotated it has same global and local rotation represented by Quaternions
//parentGO.transform.rotation==parentGO.transform.localRotation
//child has 60degree rotation from parent and 30 itself so it has 90 degree global rotation, and 30 local as we said
//childGO.transform.rotation.eulerAngles.y will be 90
//childGO.transform.localRotation.eulerAngles.y will be 30
//When we use multiply 2 Quaternions A * B,
**//Think Quaternions A * B as addition: of A+B=C, if A gives rotation of 60 and B of 30, A*B will give rotation of 90 degree
//Think of A as global rotation (transform.rotation) or as quaternion value, delta offset for B (delta + B)
//Think of B as local rotation (transform.localRotation) or quaternion value, delta offset for A (A + delta)**
//so to find out child global rotation
// parentGO.transform.rotation * childGO.transform.localRotation; // 60+30=90 gives you quaternion that will rotate something 90degree
// if Quaternon gives you rotation, inverse quaternion gives you minus rotation, ex. if A=60, Inverse(A)=-60
//but what if we have child global rotation which is 90 in our case, and we want to find child local rotation
//Quaternon.Inverse(childGO.transform.parent.rotation) * childGO.transform.rotation; // (-60 + 90 = 30)
//(delta + B)
//so what if we want to rotate childGO locally for 10degree more, was 30, so plus 10 will be 40
//childGO.transform.localRotation = Quaternion.AngleAxis(10, Vector3.up) * childGO.transform.localRotation; //(10+30)=40
//(A + delta)
//so what if we want to rotate childGO globally for 10degree more, was 90degree, will be 100
//childGO.transform.rotation = childGO.transform.rotation * Quaternion.AngleAxis(10, Vector3.up); //(90+10)=100
```

You seem to always have both rotations around y. That's a degenerate, easy, case where the order doesn't matter. To see what the question is asking, take any other rotations -- like around y and x.

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.