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 ?

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.

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

I posted this earlier, then got so annoyed at the comments, I deleted it. I’m going to repost and try to be more concise… I’m going to get to the point first, then explain some things afterwards.

Suppose you have an object “O” and want to rotate it by a quaternion Q. You need to decide if you want it to rotate around the world axis, or the object’s own local axis. (Most of the time I want it to rotate around its local axis)

W: O.transform.rotation = Q * O.transform.rotation   <- this rotates around world axis
L: O.transform.rotation = O.transform.rotation  * Q <- this rotates around its local axis

That’s it. Those are the two forms you need to remember. The way I remember the order is because (as the docs say), when Unity runs across A mul B, the * operator override performs the A rotation first (LHS), then applies the B operation next (RHS). In my head I phrase it “gives it an extra spin at the end of everything”. Iif you give it the extra spin before its normal spin, that’s not going to happen “locally”. That’s a global (world) spin.

Another sort of non-obvious result of this is that if you have a cube at a distance from 0,0,0, and you want to rotate it in a giant circle around say the Y axis, like a planet, you can’t do that by applying varying rotations on the transform, without that object having a parent, and even then you have to rotate the parent, not the object itself. If you were to try to rotate the object “around the world axis Y”, it would simply spin in place around the up and down axis in the world. Not spin around 0,0,0’s Y axis. Obvious to some, but not to everybody.


Somebody wrote me a private message and said, “you don’t know what you’re talking about wrt local rotations and parents. Nothing in Unity when it comes to setting rotations and positions matters with regards to if it has a parent or not”. So polite. Well, it’s true and it ain’t true. Let me explain…


Put two identical objects into a scene. One of them has a parent, one of them does not. The one with a parent, the parent has some non-zero position and rotation offset. I set both the objects’ world position and rotation to something interesting. I can do it via independently setting position and then rotation, or I could call SetPositionAndRotation. Both the objects end up in exactly the same world position and world rotation. So what’s the difference? The difference is that under the hood, during the = assignment for both position and rotation, Unity peeks at where you want it to be, and calculates where it already is (by looking at the parent chain), and it calculates deltas, and sets the local component to whatever it needs to be in order to get the object to where it should be. This applies to position AND it applies to rotation. In fact, rotation is “a bit special”. When you assign a world rotation to an object that has a parent, it will change both the local position and the local rotation to get the object to the exact spot you’ve told it to be at. I find this interesting…