PDA

View Full Version : Skeletal Animation with Assimp, FBX format.



Darkpower
06-23-2015, 05:18 AM
Hey!

I'm a total newbie when it comes to this subject, be patient! :)
I'm reading right know this tutorial: http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html
How do I determine the maximum number of bones that influence a vertex in a mesh? In this tutorial, they did choose 4, how come? If you look furher down in this tutorial, this line can be found:



struct VertexBoneData
{
uint IDs[NUM_BONES_PER_VEREX];
float Weights[NUM_BONES_PER_VEREX];
}


I have downloaded an animated mesh(FBX format) with bones. Look at the screenshots(without the skin/mesh, using Cinema 4D): http://oi62.tinypic.com/xkybu9.jpg and http://oi61.tinypic.com/b65w02.jpg
Is this correct? Seven bones influence the middle vertex? I need to set this constant "NUM_BONES_PER_VEREX", if it should be seven?

Thanks in advance.

GClements
06-23-2015, 09:25 AM
Neither of the images you posted provides any clue as to how many bones influence a given vertex.

You'll need to analyse the imported data to get that information. Unfortunately, assimp gives you the information backwards (a list of vertices per bone rather than bones per vertex). So you need something like:


int max_bones(const aiMesh *mesh)
{
int *counts = calloc(mesh->mNumVertices, sizeof(int));
for (int i = 0; i < mesh->mNumBones; i++) {
const aiBone *bone = mesh->mBones[i];
for (int j = 0; j < bone->mNumWeights; j++) {
const aiVertexWeight *weight = &bone->mWeights[j];
counts[weight->mVertexId]++;
}
}
int max = 0;
for (int i = 0; i < mesh->mNumVertices; i++) {
if (max < counts[i])
max = counts[i];
}
return max;
}

Darkpower
06-25-2015, 02:23 AM
Ah. Is it hard for a newbie like me to analyze that kind of information inside a 3D modelling program? Do you know any tutorials for how to do this?

Thank you so much for that function, will try it soon! :)

Dark Photon
06-25-2015, 05:32 AM
How do I determine the maximum number of bones that influence a vertex in a mesh? In this tutorial, they did choose 4, how come? If you look furher down in this tutorial, this line can be found:



struct VertexBoneData
{
uint IDs[NUM_BONES_PER_VEREX];
float Weights[NUM_BONES_PER_VEREX];
}


Why 4? It's a balance between minimizing space and what's generally useful in practice. You need more than 1 for blending influences from multiple joints, 2 usually isn't enough, and 4 is often sufficient.

Also, you'll need to encode all of the joint indices and weights influencing a vertex on each vertex in your skeletal mesh, so you need to keep the number down. And GPU vertex attributes work well with multiples of 4. Each vertex attribute is basically 4*32-bits wide. So you could (as above) use 4 full 32-bit units for the joint indices and 4 full 32-bit floats for the joint weights, consuming an even 2 full 128-bit vertex attributes (total = 2*(4*32) = 256-bits).

However, then you might ask yourself: do I really need the possibility of 65535 joints in a joint skeleton, and a full 32-bit float to represent a 0..1 weight? No, probably not. So what about if we limit outselves to 255 joints in a joint skeleton? Then we could use 4 8-bit uints for the joint indices (supporting up to 255 joints) and 4 8-bit uints for the joint weights. Bit-pack this and you find find you can pass all this into the shader with 1/4 of the space: only 64-bits, which is just two components on a single vertex attribute (e.g. attr.x and attr.y).



I have downloaded an animated mesh(FBX format) with bones. Look at the screenshots(without the skin/mesh, using Cinema 4D): http://oi62.tinypic.com/xkybu9.jpg and http://oi61.tinypic.com/b65w02.jpg
Is this correct? Seven bones influence the middle vertex?

No. Typically this "stick diagram" you're looking at is used to represent parent/child relationships between joints in the joint skeleton (the big end is typically the parent joint). There's nothing in this picture about the mesh. This is purely joint skeleton stuff.

In terms of modeling, the joint skeleton is defined first. The joint skeleton is basically defined as the list of joints, the parent/child relationships between joints, and the positions/orientations of child joint's relative to its parent in the "bind pose". Once that's defined, the mesh is "skinned" to the joint skeleton -- basically by defining joint influences and joint weights for each vertex in the mesh, "attaching" it to the skeleton. Once that's done, the mesh can be animated by animating the joint skeleton alone.

Darkpower
06-26-2015, 12:28 PM
Thank you for the great explanation!
I need to read a lot more on the web, but this was a good start! :)

I have tried open3mod(http://assimp.sourceforge.net/main_viewer.html) with 10 different animated models and only 1 worked properly!!!
Check this video: https://www.youtube.com/watch?v=ListZxWfjgw, an example of how distorted the models could look like in open3mod...
Just so you know, I've also tested the same models in Cinema 4D and autodesk fbx viewer and everything worked as expected.
It seems that assimp doesn't have so good support for FBX models with animations... Should I use collada or MD5 instead? Is it possible to convert from FBX to MD5? I don't wan't to implement my own FBX+Animation importer, reinventing the wheel is stupid...

I found another implemented solution: https://github.com/sho3la/FBX-Loader-OpenGL-C-. It uses FBX SDK instead of Assimp.

Darkpower
06-26-2015, 12:53 PM
Look at this picture: http://oi59.tinypic.com/2ch6bfd.jpg, distorted model....

Dark Photon
06-26-2015, 06:13 PM
Thank you for the great explanation!
I need to read a lot more on the web, but this was a good start! :)

I feel your pain! Here are a few posts I made a while back that might point you to a few good sources you can use to spin up on skeletal: link 1 (https://www.opengl.org/discussion_boards/showthread.php/178151-Animation?p=1239683&viewfull=1#post1239683), link 2 (https://www.opengl.org/discussion_boards/showthread.php/179419-Need-help-with-skeletal-animation?p=1243904&viewfull=1#post1243904). See also the next post under the 2nd link for a brief overview of how the transforms work.


Check this video: https://www.youtube.com/watch?v=ListZxWfjgw, an example of how distorted the models could look like in open3mod...

Ok, so you can render the mesh without any animation (i.e. ignoring the joint weights and indices) -- that's the mesh in the bind pose. However, you've just got something wrong with the math computing the "skinning transforms" (aka joint final transforms), or passing them to and applying them in the shader (though the latter is less likely). See that next post I mentioned, or one of the articles I mentioned to help fix your understanding of how the transforms need to be built.


I don't wan't to implement my own FBX+Animation importer, reinventing the wheel is stupid...
Yeah, I wouldn't re-implement an FBX importer. However, you might seriously consider writing your own simple exporter from your favorite modeling tool to your own custom format. That'll teach you a lot. Either that or start with MD5 -- less plumbing between you and the data which can go wrong.

Darkpower
06-29-2015, 01:46 PM
Today, I received a full implementation of an FBX importer/exporter from a very nice guy! It supports the latest version of the FBX SDK. It loads and draws animated FBX files completely independent of the FBX SDK library! :) It also supports GPU-skinning, optimizations etc..

With Assimp, only 1 out of 10 animated models did work, very bad ratio.... With this implementation, all the animated models works perfectly :)

Thanks for all the help!

raptor
10-07-2015, 12:00 AM
Thanks for all the wise advice on this thread.

I'm even more of a rookie - just joined.

I read about Dark Power's challenges with bone weights, influencers per vertex and crumby FBX importers/exporters, and I'd dearly like some help in this area too.

What are the best FBX importers/exporters that cover this level of detail? I'd prefer not to spend too much $$.

:)