Hi! This is in relation to several conversations I’ve had with you on the Blender SE, for example the one at https://blender.stackexchange.com/questions/244450/how-does-blender-rotate-parented-bones/244507?noredirect=1#comment416613_244507 . Because you had a lot of questions, I recommended asking here, because SE really isn’t good for this kind of back-and-forth. Throwing this out there, so that’s there’s some context for anyone; and I’m going to skip what’s already been dealt with there-- I’m gonna get into it.

First thing I see on opening your file is that your armature has unapplied scale. So I’m going to apply that first, because it makes it difficult to measure things.

So, of course, if we open up your file, and only rotate Right leg by 45 degrees in world X, then Right knee also rotates 45 degrees in world X. Because it is RL that is rotating, RK’s rotation is about the origin of RL. That position is world space 0.46, 0.22, 3.82-- the location of the head of RL. Notice that if we rotate RL, we do nothing to change the **position** of RL.

If we then rotate ROOTJOINT, its child RL will rotate around the center of ROOTJOINT, and RK will rotate about ROOTJOINT, then about RL. There are two centers of rotation at that point, but the centers of rotation aren’t stored anywhere in RK; they are encoded in the position of ROOTJOINT and RK (or, more specifically, in their inverse matrices.)

Now, before we get any further, I want to emphasize something. I’ve never written a skeletal animation system. I’ve read about 3D math, but that’s not the same thing. I haven’t worked through all the problems and likely errors, and errors come easy. So it’s entirely likely that I’m going to get some details wrong in what I write below, details like multiplication order. I’m not necessarily getting the terminology right everywhere. I’m just aiming to communicate how a child actually acquires its parent’s rotation, mathematically.

Let’s make something super idealized here:

I got bones P and C there. P is at origin. C is at 0,1,0. C is parented to P. All xxes align with world axes.

So the instant that I leave edit mode here, Blender will calculate what is called an inverse matrix for these bones. This is the matrix needed to bring the bone into perfect agreement with the world (really, the armature, but the armature agrees with the world here.) P is already in agreement with the world, so P’s inverse is going to be the identity matrix: 4x4, with 1s down the diagonal, and the rest are 0s. C’s inverse is going to represent only the translation it needs to bring it to the origin, so it’s going to be mostly 0s, with 1s down the diagonal, but the 2nd row of the 4th column will have a -1 in it. (What’s a row and what’s a column depends on the software/API, so don’t get too hung up on it. There’s more than one way to represent the math that is identical.)

Now, if we parent a point at 0,1,0 to P, and then rotate P by 45 degrees, where is that point? We need to make a matrix out of that 45 degrees rotation. Which I’m not going to do, but you can find out how at https://en.wikipedia.org/wiki/Rotation_matrix . *Then*, to find the real transformation here, P will multiply three matrices: its inverse (which is identity), then its local transformation (that rotation matrix), then the inverse of its inverse (which is likewise identity.) Let’s call this matrix Mp. In this case, this matrix is identical to the rotation matrix we made, because all the identity multiplications don’t do anything, it’s like multiplying by 1.

So now we have a single matrix Mp describing the transformation of P. To find out the position of the point, we multiply (0,1,0,1) by Mp. The answer is the transformed position of the point. That extra “1” at the end is the “w”; it doesn’t really mean much in this case, but you should know that it exists, and that it’s always 1 until we do something weird (like do a perspective transform on the point to get inside a camera’s frustum.) If we rotate P by 45 degrees in world Z and do our matrix multiplication, we’re going to get something like (-cos45d, sin45d, 0, 1) as our answer. We don’t pay any attention to the w, but it’s still there.

Okay, now let’s figure out another point. This one is at 0,2,0, and it’s parented to C. So we need to find the transform matrix of C. What is that matrix? It is C’s inverse, times C’s local transform, times the inverse of C’s inverse. Let’s call this particular product “Mc”. Now, if C has no transform, then that’s C’s inverse matrix, times identity, times the inverse of our inverse matrix, which all comes out to the identity matrix. However, because C is parented to P, we need to do one more thing: we need to multiply Mp by Mc. If Mc is identity, that product is just Mp. So when we run our new point through Mc’s matrix, it’s exactly the same as if we had just run it through Mp’s matrix-- it’s exactly the same as if that point was parented to P.

But, when we give C some local rotation, then Mc is no longer the identity matrix. To find the position of our new point, we need to calculate (0,2,0,1) times (Mp times Mc).

What are these matrices Mc and Mp? Mc represents a rotation about the origin of C. Mp represents a rotation about P. When we multiply them, we no longer have anything that can cleanly be said to be a single rotation, or could even cleanly be said to be just a rotation. We have two, sequential rotations: rotation about P, followed by rotation about C.

C never knows that P rotated. P never knows that C rotated. And our transformed points only ever know the final matrix into which they’re multiplied; that second point never knows that it has some particular rotation from C, let alone that it’s also inheriting some rotation from P.