Hi,
I'm not sure if this is the right forum for this, or it should go to General Programming. Please feel free to move it.
I'd like to read skeleton from a model, using Assimp. As it turned out, interpreting Assimp structures is just as complicated as parsing many different formats at once. Judging by huge number of assimp-bone related questions on forums (some of them here too) I'm not alone with this problem. I've searched a lot, and I could find many answers to my questions, however the pieces are still not fitting together entirely. To explain what my problem is, I'll try to summarize what I've gathered so far, and please correct me if I'm wrong somewhere.
The main problem is, both bone structure and mesh structure is stored in the same node structure, however it would be false to assume they are correlated. Meaning you have to traverse the same node-tree two times, completely independently, to get the correct results: one time for the meshes, and one time for the bones. Is this true? The best instructions I could find so far is here under section "Bones", but it is just a pseudo-description of a rather ridiculous algorithm (I'm sorry, but I really think that). Some important answers I've found here.
Most assimp tutorials (like here and here) I've found seems to miss key parts of the whole procedure. They usually simply iterate through aiScene->mMeshes or walking the node tree collecting mMeshes in a vector, but from what I've learned so far, this is wrong (or more precisely only works in an exceptional case when only the root node has meshes). To explain what I mean:
- model space: this is what we use to display our model
- mesh node space: all mMeshes in a node contains vertices in this space (is this correct? or are they stored in model space in the first place?)
- bone node space: similar to mesh node space, however totally unrelated to the node space that contains the mesh
So, to correctly load all vertices into model space, we have walk through the node tree, concatenating the node's transformation matrix along the path and apply it to the vertices. Otherwise if there's only one node with meshes, and it's the root node, then, and only then model space == mesh node space. Is this correct?
Bone nodes' transformation matrices are not model space related, rather skeleton hierarchy related, and they also have an offset matrix which transforms from mesh node space into this bone's node space. This is clear (at least something is :-))
Traversing the node tree for bones and concatenating their transformation matrices along the path will result in a matrix that converts from bone node space into model space. If there's only one node with meshes and that's the root node, then, and only then this concatenated matrix is the inverse of the offset matrix. This seems reasonable if I understood everything correctly.
If we later want to use an animation, then we have to
1. get the list of bones which changed on that particular frame
2. collect all vertices that are affected by that bone (mMeshes[]->aiBone)
3. collect all of the bones that control those vertices and all of those bone's children (in a unique list, as we have to recalculate all vertices belonging to those bones)
4. using the corresponding offset matrices, convert those vertices from their "bind-pose" skeleton mesh node space into one or more bone node spaces ( V -> V'[1..numWeights])
5. use the transformation required by the animation frame on all vertices that belong to the modified bone using their corresponding bone node space versions (V'[x]),
or do we multiply the frame transformation matrix temporarily with the bone's transformation matrix? (In other words, should we transform the vertices in the bone space or their coordinate system in model space?)
6. get a weighted average of each vertex in their corresponding bone node space (w[1..numWeights] * V'[1..numWeights] -> Vm), then transform the result into model space (or should we / would it be better to convert the points into model space first and calculate the weighted average there?
(Let's assume we have a frame for the sake of simplicity, I know how to iterate skeletons.)
A little note on 5th question: although it seems to be irrelevant whether we transform the points or their coordinate system, because we'll get the same result (in model space), however this affects the points of the children bone spaces differently. I guess we must not convert the bone node spaces into model spaces, rather keep them parent bone node space relative, and only convert the final points back to model space. Am I correct?
Thanks,
bzt