<blockquote>
<p>To get a vertex in root space into C space, I would have to do (CBA) * v.</p>
</blockquote>
<p>Well, yes. But that's not actually what you want to do in skeletal animation. <strong>You have it reverse.</strong></p>
<p>It's the other way around. You assume you have a point in C space and want to compute its position in root/global space, in order to pump it further through the transformation pipeline, which gets <strong>increasingly more global with each transformation</strong> until your point ends up in eye-space (and further). That's why A doesn't transform from root space into A space, it transforms from A space into root space. So <span class="math-container">$ABC$</span> transforms from C space into root space.</p>
<p>Now your mesh vertices already are in root space, that's where the inverse bind pose comes into play, which transforms a point <strong>from root space into C space</strong>. So you basically transform your point from root space to C (or whatever joint) space with the inverse bind matrix that's only dependent on the joint and constant over the whole animation and then from that joint space back into root space with the animation-dependent joint transformation.</p>
<p>So C's transformation matrix for frame <span class="math-container">$t$</span>, that transforms a vertex from <em>unanimated</em> root space, which is how your mesh is defined, into <em>animated</em> (with respect to C's joint angle) root space would be <span class="math-container">$A(t)B(t)C(t)(A_RB_RC_R)^{-1}$</span>, where <span class="math-container">$M(t)$</span> is the <em>local</em> joint matrix at animation time <span class="math-container">$t$</span> and <span class="math-container">$M_R$</span> is the <em>local</em> joint matrix corresponding to the rest pose, the pose in which the mesh is defined, and thus <span class="math-container">$(A_RB_RC_R)^{-1}$</span> is C's inverse bind pose. You can also see that using the rest pose for both transformations makes them basically cancel each other out, because the vertex would already be at the proper position with respect to the rest pose animation frame.</p>

CC BY-SA 4.0
2018-05-09T19:38:15.903Z
Are you sure that the inverse bind pose (or mOffsetMatrix) transforms a point from root space to bone space? Because I have read conflicting opinions on that matter https://github.com/assimp/assimp/pull/1803
Manh Nguyen
CC BY-SA 4.0
2018-05-09T19:58:42.767Z
That's what it's *supposed* to do. But I don't know how Assimp handles it specifically. Maybe there's some confusion over the matrix vs its inverse?
Christian Rau
CC BY-SA 4.0
2018-05-09T20:04:36.890Z
Thanks for the prompt reply. So basically, I need to transform a vertex from mesh space to world space, then use inverseBindTransform to get it from world space to bone space, where I would multiply it with the desired animation pose, then I would again transform that into world space again right?
Manh Nguyen
CC BY-SA 4.0
2018-05-09T20:16:28.137Z
Not exactly. Your vertex is in mesh space. You transform it from mesh space (let's say that's also root space) into local joint/bone space with the inverse bind matrix, then from local joint space back into root/mesh space, but this time with the actual animation matrix. Usually that whole thing isn't really applied in order like this but instead builds a single matrix, the one transforming a vertex for *one* joint from root space into animated root space. And those are the joint matrices you combine with usual blend skinning (or other method) to get the matrix you transform your vertex with.
Christian Rau
CC BY-SA 4.0
2018-05-09T20:18:05.203Z
And this animated vertex, now still in mesh/root space, but properly animated, you then transform with the normal model-to-world and world-to-camera or whatever global transformation matrices.
Christian Rau
CC BY-SA 4.0
2018-05-10T03:10:47.870Z
I dont think I can directly transform it from mesh space to bone space. The way I am calculating inverse bind, I concatenate every transformation matrix starting from root node, so its actually in world space. So I need to move vertex from mesh space to world space before I can multiply it with inverse bind transform to bring it to bone space, right? The way I am doing is (CBA)^-1 but it is wrong somehow
Manh Nguyen
CC BY-SA 4.0
2018-05-10T13:08:41.187Z
Well, then from world space. The point is that you use the same matrices for the inverse bind matrix that you use for the actual animation, just inverse and for the animation frame that the mesh is defined in. But it's also really hard to argue and figure out what actual multiplication order you should use in a comment thread. I gave the general idea how it works above, the rest are technicalities and maybe a little more reading of introductory material how skeletal animation works in general. You just always need to be aware in which space your data is defined and in which space you want it.
Christian Rau
CC BY-SA 4.0
2024-03-06T13:44:43.790Z
@ChristianRau I agree with the answer; I think the formula's last component, inverse bind pose matrix, needs to be on the right.  Assuming column-vector convention where every successive matrix is left-multiplied: the un-animated mesh points are in model space, it needs to be taken to bone space first (using inverse bind pose matrix) and then animated bone space to model space back again: $v' = A B C (A_RB_RC_R)^{-1} v$ (ignored frame time for clarity).
legends2k
CC BY-SA 4.0
2024-04-11T16:03:12.490Z
@legends2k Damn, you're right, thanks!
Christian Rau
CC BY-SA 4.0
2018-05-09T15:58:58.557Z
2024-04-11T16:05:37.187Z
2024-04-11T16:05:37.187Z
Christian Rau
<p>I am trying to do skeletal animation using Assimp and the inverse bind pose matrix just trips me up. I will give a little example to illustrate my point.</p>

<pre><code>Root
    Bone A
        Bone B
            Bone C
</code></pre>

<p>Let's say we have a hierarchy like above. To get a vertex in root space into C space, I would have to do (CBA) * v. The inverse bind pose, which is supposed to get a vertex from bone space to root space, should be the inverse of this. Therefore, the way to calculate inverse bind matrix should be (CBA)^-1 or (A^-1)(B^-1)(C^-1). The formula then is (A^-1)(B^-1)(C^-1) * v, which makes sense. However, I am not able to reproduce the result of Assimp's mOffsetMatrix (inverse bind matrix caculated by Assimp) with (CBA)^-1. (ABC)^-1, however, surprisingly produces the correct result, albeit a little marginal error here and there which I attribute to floating point error.</p>

<opengl><linear-algebra>
Confusion about how inverse bind pose is actually calculated and used?
Manh Nguyen
# Confusion about how inverse bind pose is actually calculated and used?

(Asked by: username_0 on 2018-05-09)

I am trying to do skeletal animation using Assimp and the inverse bind pose matrix just trips me up. I will give a little example to illustrate my point.

```
Root
    Bone A
        Bone B
            Bone C

```

Let's say we have a hierarchy like above. To get a vertex in root space into C space, I would have to do (CBA) \* v. The inverse bind pose, which is supposed to get a vertex from bone space to root space, should be the inverse of this. Therefore, the way to calculate inverse bind matrix should be (CBA)^-1 or (A^-1)(B^-1)(C^-1). The formula then is (A^-1)(B^-1)(C^-1) \* v, which makes sense. However, I am not able to reproduce the result of Assimp's mOffsetMatrix (inverse bind matrix caculated by Assimp) with (CBA)^-1. (ABC)^-1, however, surprisingly produces the correct result, albeit a little marginal error here and there which I attribute to floating point error.

**Tags:** opengl, linear-algebra


---

## 1 answers

### Answer by username_1 on 2018-05-09. Score: 2 | Accepted answer

> To get a vertex in root space into C space, I would have to do (CBA) \* v.

Well, yes. But that's not actually what you want to do in skeletal animation. **You have it reverse.**

It's the other way around. You assume you have a point in C space and want to compute its position in root/global space, in order to pump it further through the transformation pipeline, which gets **increasingly more global with each transformation** until your point ends up in eye-space (and further). That's why A doesn't transform from root space into A space, it transforms from A space into root space. So $ABC$ transforms from C space into root space.

Now your mesh vertices already are in root space, that's where the inverse bind pose comes into play, which transforms a point **from root space into C space**. So you basically transform your point from root space to C (or whatever joint) space with the inverse bind matrix that's only dependent on the joint and constant over the whole animation and then from that joint space back into root space with the animation-dependent joint transformation.

So C's transformation matrix for frame $t$, that transforms a vertex from *unanimated* root space, which is how your mesh is defined, into *animated* (with respect to C's joint angle) root space would be $A(t)B(t)C(t)(A\_RB\_RC\_R)^{-1}$, where $M(t)$ is the *local* joint matrix at animation time $t$ and $M\_R$ is the *local* joint matrix corresponding to the rest pose, the pose in which the mesh is defined, and thus $(A\_RB\_RC\_R)^{-1}$ is C's inverse bind pose. You can also see that using the rest pose for both transformations makes them basically cancel each other out, because the vertex would already be at the proper position with respect to the rest pose animation frame.

> **Comments:**
> **username_0**: Are you sure that the inverse bind pose (or mOffsetMatrix) transforms a point from root space to bone space? Because I have read conflicting opinions on that matter https://github.com/assimp/assimp/pull/1803  
> **username_1**: That's what it's *supposed* to do. But I don't know how Assimp handles it specifically. Maybe there's some confusion over the matrix vs its inverse?  
> **username_0**: Thanks for the prompt reply. So basically, I need to transform a vertex from mesh space to world space, then use inverseBindTransform to get it from world space to bone space, where I would multiply it with the desired animation pose, then I would again transform that into world space again right?  
> **username_1**: Not exactly. Your vertex is in mesh space. You transform it from mesh space (let's say that's also root space) into local joint/bone space with the inverse bind matrix, then from local joint space back into root/mesh space, but this time with the actual animation matrix. Usually that whole thing isn't really applied in order like this but instead builds a single matrix, the one transforming a vertex for *one* joint from root space into animated root space. And those are the joint matrices you combine with usual blend skinning (or other method) to get the matrix you transform your vertex with.  
> **username_1**: And this animated vertex, now still in mesh/root space, but properly animated, you then transform with the normal model-to-world and world-to-camera or whatever global transformation matrices.  
> **username_0**: I dont think I can directly transform it from mesh space to bone space. The way I am calculating inverse bind, I concatenate every transformation matrix starting from root node, so its actually in world space. So I need to move vertex from mesh space to world space before I can multiply it with inverse bind transform to bring it to bone space, right? The way I am doing is (CBA)^-1 but it is wrong somehow  
> **username_1**: Well, then from world space. The point is that you use the same matrices for the inverse bind matrix that you use for the actual animation, just inverse and for the animation frame that the mesh is defined in. But it's also really hard to argue and figure out what actual multiplication order you should use in a comment thread. I gave the general idea how it works above, the rest are technicalities and maybe a little more reading of introductory material how skeletal animation works in general. You just always need to be aware in which space your data is defined and in which space you want it.  
> **username_2**: @username_1 I agree with the answer; I think the formula's last component, inverse bind pose matrix, needs to be on the right.  Assuming column-vector convention where every successive matrix is left-multiplied: the un-animated mesh points are in model space, it needs to be taken to bone space first (using inverse bind pose matrix) and then animated bone space to model space back again: $v' = A B C (A_RB_RC_R)^{-1} v$ (ignored frame time for clarity).  
> **username_1**: @username_2 Damn, you're right, thanks!  

---

