 Trying to understand how child bones inherit rotations from parents

Hello, i am trying to understand how exactly child bones are rotated if the parent bone is rotated(how child bones inherit rotations and what the pivot point for each bone is)

For example lets look at the leg which has the following hierarchy:
Leg, has child Elbow
Elbow, has child Foot
Foot, has child Toe

If i now rotated the Leg bone 45 degrees in the x axis, how are the 3 children bones rotated?

Ideally i’d like to know exactly how the 3 children bones are rotated and what their pivot points are. I understand that the leg bone itself is just rotated 45 degrees in the x axis and the pivot point is it’s head(which should be the location of the bone) as it has no parents(other than root which is at 0, 0, 0)

Blend file: https://blend-exchange.com/b/rRexzzNz/

When child bones inherit the rotation of their parents they will rotate with their parent, from the parents pivot point and at the same angle.

If you set the lower leg to NOT inherit the rotation of the upper leg it will not rotate (nor will the foot as it still inherits the lower legs rotation which is 0º)

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.

2 Likes

First of all, thank you so much for the extremely detailed reply.
I believe i understood it all except maybe the very last part, so just to confirm:

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.

so P and C are the origins of rotation here?

I’ll also explain my setup
In my animation system i use rotation methods that assume the point is in 0, 0, 0
So what i do is first move the point to 0, 0, 0 then rotate it and move it back.
so basically:
translate(point, -origin)
rotate(point)
translate(point, +origin)

So basically before each rotation i have to set the origin which is why im trying to figure out how to compute the origin for each bone so i can emulate it in my animation viewer and have the same results as in blender

Yup, mathematical rotations are always about 0, you’re doing it right.

Yes, P and C are ordered origins of rotation. If you take two copies of your model, one with unparented bones, you can see this by rotating around cursors.

Uh, what exactly do you mean by ‘ordered’ origins of rotations? sorry if im asking silly/obvious questions btw, but im just trying to have a full understanding of every single part.

The end result of rotations depends on the order in which they are performed:

Two monkeys rotated in 180 degree rotations about two points, but in different order, acquire different positions.

The rotations of an armature are in order: the root is rotated, then its immediate children, then their immediate children.

So in my case for the leg(if i were to rotate the leg), it would first be the leg, then the knee, then the foot and then the toe?

Yes, that’s correct.

Okay, i think i understand it to an extent now, but i still don’t fully understand the matrices, are the matrices that are constructed(referring to Mc and Mp) purely rotation matrices or do they also contain other data which is used(like the translation part of the matrix)?

I called them rotation matrices just because they only contained rotation data in my example. In real life, translation, rotation, and scale are all contained in the same matrix (although if you wanted, you could create that matrix by multiplying other matrices that each only contained rotation, translation, or scale.)

I see, thanks i’ll try to figure out how to implement the same behaviour in my engine now.

Okay, i am still not 100% sure after attempting to program it and it not working out:

For the rotations as matrices, is this correct in a case where i have 4 bones (Bone1 → Bone2 → Bone3 → Bone4) and i rotate bone1 by 45 degrees in the x axis?

float rotation = PI / 4; // 45 degrees

Matrix bone1Matrix = Matrix.identity().translate(Bone1.localPosition).rotateX(rotation)

Matrix bone2Matrix = bone1Matrix.multiply(Matrix.identity().translate(Bone2.localPosition).rotateX(rotation)

Matrix bone3Matrix = bone2Matrix.multiply(Matrix.identity().translate(Bone3.localPosition).rotateX(rotation)

Matrix bone4Matrix = bone3Matrix.multiply(Matrix.identity().translate(Bone4.localPosition).rotateX(rotation)

And the origin of each bone would just be the translation part of their matrix(just a guess)

the rotation of each bone would either be the accumulated rotation or the initial rotation(i’d assume it’s the latter)

Personally, I don’t know the answer to that. I don’t know Blender’s structures, and I don’t know in which order the matrices need to be multiplied.

Okay thanks anyway ill try to figure it out