Importing skeleton from Assimp

Started by
1 comment, last by bzt 4 years, 6 months ago

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

Advertisement

Hi,

It looks like I answer my own question ? Maybe this will useful to others.

If anyone has the same problem as I did, don't try to understand open3mod's source (suggested on the assimp's repo) or the samples directory, but start checking out this code: assview (I know, funny name). It is much better than any tutorial or assimp documentation. Why is it so perfect? Because it has almost no dependencies (GLUT only), multi-platform (Mac, Linux, Win-MinGW), supports materials, textures, most importantly animations, and it does not create intermediate classes or vector lists for that, rather feeds aiScene directly into OpenGL, making it perfectly clear what is what! ? There's not much comment in the code, but function names are very informative, and it is written in a so clean way that's amazing. Seriously. Directly from aiScene to OpenGL without unnecessary conversions answers almost every questions you may have about Assimp.

Just taking a look at two functions, transformnode and transformmesh answered all but one of my questions.

1. I was right about the bone node's transformation matrices basically, however I was wrong about the direction as they are inverse, meaning they transform from bone node space into model space (and they have nothing to do with the mesh node space apparently, but see below). Note that the transformnode function is a postfix recursion so that it multiplies the matrices in the correct order.

2. Once you've collected the bone node matrices, you multiply that with the bone's offset matrix, then you calculate the weighted average and the result would be already in model space, no need for bone space -> model space transformation as I suspected.

There's one question left though, as you can see in animatescene, this code passes aiScene to the transformmesh, meaning it's not walking through the node tree. Does this mean that vertex coordinates are always in model space regardless to their positions in the node three, or is this just a simplification made on the assumption that only the root node has meshes?

(EDIT: all the models I have tested with assview worked perfectly, so it's hard to tell. I had only problem with Scorch3D's MilkShape models, but neither of them worked, so it's not a Assimp library usage issue.)

Thanks,
bzt

This topic is closed to new replies.

Advertisement