Consequent rotations changing the axis of rotation

When dealing with rotation sequences, it’s often said that each rotation rotates the coordinate system thus affecting the subsequent rotations by changing their axes (their frame of reference).
I’ve found that hard to grasp at first for the following reason: if you rotate a point “A” around some axis by some angle to result in point “B” then why is it any different from starting with point “B” in the first place?

Let’s say you rotate point A = (1, 0, 0) around the Y axis 90 degrees arriving at B = (0, 0, -1). Now with that rotation you supposedly have rotated everything around Y by 90 degrees, including the axes so for example the Z axis has rotated into the original X axis). If you next rotate around Z that will rotate around the new Z axis (the original X axis) and not the original Z axis. But how is that different from starting with point B in the first place and rotating around Z without any previous rotations? How does the second rotation “know” about the first one?

The answer to this simple (or stupid) question is that of course it doesn’t, and rotations don’t rotate the axes.
Assume we have this rotation sequence: X, Y, Z. We can look at this one of two ways:
1. First rotate around the original X axis, then the rotated Y axis, finally around the rotated Z axis (that we rotated twice with the first 2 rotations).
2. Or first rotate around the original Z axis, then the original Y axis, finally around the original X axis.
These 2 ways are equivalent and it’s only a matter of how you think about it. Note the order of axes in the second version is reversed and it uses the original (fixed) axes. This is true generally: if you reverse the order of axes, you can switch between using fixed vs. rotated ones.
The first one is called “Intrinsic”, the second one is called “Extrinsic” and it’s described pretty well on Wikipedia (see conversion between the two):

What happens is that if you look at rotation sequences in the “correct” (or actual) order ie. the order in which they are mathematically executed one after another then the axes remain fixed of course. If you look at it in reversed order then you have to look at it like each rotation changes the axes for upcoming rotations.
Why is the first (intrinsic) method used frequently? Sometimes it’s easier to orient your object thinking about rotations like they change the orientation of the coordinate system, after the first rotation you don’t want to think about the original axis but rather the object’s local axes, that are the rotated ones.
Another reason is that when working with transformations, eg. rotation matrices (but the same applies to quaternions), you usually do this (pseudo code):

// start with the identity matrix
rotationMatrix = new Matrix4();
// right multiply rotationMatrix by rotationMatrixAroundX, then Y, then Z:
rotationMatrix = rotationMatrix * rotationMatrixAroundX;
rotationMatrix = rotationMatrix * rotationMatrixAroundY;
rotationMatrix = rotationMatrix * rotationMatrixAroundZ;

Eventually when you apply the rotation to a point (typically in the vertex shader), you do this:

pos = rotationMatrix * localPos;

so what you actually do is this:

pos = rotationMatrixAroundX * rotationMatrixAroundY * rotationMatrixAroundZ * localPos;

You can see that the actual order in which rotations are applied is: Z, Y, X (because rotationMatrixAroundZ is closest to the point) which is the reversed order in which you multiplied the rotation matrix. This is the result of you right multiplying (post-multiplying) the rotation matrix to calculate the rotation result matrix and left multiplying the point with this result matrix. If you used left multiply (pre-multiply) when multiplying the matrices, the order would be reversed.
Again, you can look at this in the actual execution order of Z, Y, X with all axis remaining fixed or in the order of X, Y, Z while each rotation changes the axes for subsequent rotations.

This is not a matter only for rotation matrices, the same idea applies when using quaternions if you’re thinking in rotation sequences around some axes (eg. when using Euler angles).

If you use three.js you can rotate an object simply like this:

mesh.rotation.x = angleXInRadians;
mesh.rotation.y = angleYInRadians;
mesh.rotation.z = angleZInRadians;

The actual order of execution in three.js is: Z, Y, X (it doesn’t matter in what order you set the rotation properties). Here’s a demo to play with:!/c-cs291/l-91073092/m-123949249

You can see that if you look at this the “Intrinsic” way, you can rotate first around X, which rotates all other axes, then you can rotate around the new Y (call it Y’) which rotates the new Z (z’) to yet another new Z (Z”) and finally you can rotate around that Z”.
Or you can look at it in the actual order (“Extrinsic” way), so first rotate around Z which doesn’t rotate any axes, then rotate around the (original, unrotated) Y axis, finally rotate around the original X axis.

I plan to write another post on something related with more examples (especially if there’s interest).