Skeleton model format

Started by
7 comments, last by Dirge 17 years ago
So I'm working on revamping the skeletal animation system in my engine and thought I would ask some g-devers for their thoughts on something I've been contemplating. When I originally started work on my model format, I didn't foresee a major need for sharing skeletons or animations between multiple models, so I stored the skeleton in the model file, and animations in their own separate files. While this works nicely and is relatively convenient, it's somewhat inefficient since it doesn't allow for a skeleton to be shared between multiple models, which can add up (imagine having a number of humanoid characters all duplicating the same data they could have been sharing...). So as I begin refactoring my skeleton loading code and coming up with a new format, a few questions have come up; 1. Should the skeleton be tightly coupled with a model, or completely separate to allow sharing between multiple models. 2. Should animations be combined into a single animation file to reduce the likelihood of user error (i.e. in instances when an animation is exported but the skeleton changed). (the main downside to this from projects I've worked on are very long animation file compilation times) 3. I use the collada model interchange format to export models from a 3d editing suite, and a custom converter to my own format (using a model export file for custom export options). Whats the most convenient way for an artist to get his model, skeleton, and animation into the game without requiring tons of unnecessary steps? (this is critical to me) 4. (Perhaps off topic) Is a chunk based file format worth pursuing. In the past they've been nothing but trouble for me, but I can see the merits of maintaining a model's compatibility across versions. Does anyone have any insights on the matter, perhaps based on previous experiences in the same situation. Thanks for any input.
"Artificial Intelligence: the art of making computers that behave like the ones in movies."www.CodeFortress.com
Advertisement
1.I would use a base skeleton for each model, but allows for a per model skeleton
just create an asset

<modelname>
{
skeleton = "playerdefault"
mesh = "meshname"
...
}

2. no, use packfiles and store the individual files in those packfiles

3. collada as a base sounds good, I personally will use the MD5 format from doom3

4. I would design a custom format similar to the md5 format,
and make it text based of course, md5 is very easy to parse as well using stl ifstream
http://www.8ung.at/basiror/theironcross.html
My skeleton code uses binding by name, i.e. bone names on the one side and vertex group names for skinning on the other. The binding step is done when the skeleton instance was created from the prototype and is added to the scene graph. (Okay, "prototype" isn't the 100% correct term here: It is furthurmore backing the instance since it holds all invariant data ("bind pose") while the instance holds the individual state.) Also animations are bound by name to target bones (inside the skeleton _instance_, of course).

I allow animations to have tracks that have no counterpart in a skeleton, and I also allow vertex groups with names not available in the used skeleton. I also allow the skeleton to have bone names without a counterpart in animations and/or vertex groups. Well, this has 2 reasons. 1st, animations can be blended or overlayed. 2nd, I don't expect the model to be always complete since the engine provides also an editing mode.

In summary I prefer binding by name (or something similar) to allow the re-use of skeleton prototypes. In fact, all this grants a bit more responsibility to the designer, right you are.
Great points!

Basiror:
Thats basically what I've been thinking of doing (keeping a skeleton reference defined within the model).

I do use packfiles for all loose files but I was wondering if people thought it might be easier to package animation files together for ease of use. Now that I think about it though with a good directly structure this is completely unnecessary.

MD5 huh? I had considered using that myself but only as an interchange format (to get from a 3d model app to my format, since the load times can be horrendous). Can you give me any details on the goods and bads you've discovered from using it.

I would use a text format for the reasons you mentioned but as a final format I want something as fast and streamlined as possible.


haegarr: Could you elaborate further. I'm not sure what the relation is between bones names and vertex group names.


A few more thing.

One of my major concerns is that bone weights/indices being invalid when used with a stale skeleton/animation. I suppose this is more of an export issue, but if anyone has any suggestions about error-proof export processes I'd love to hear them.

Also, it's hard justifying a separate format when a skeleton and animation file format are so similar, so a solution I am considering is maintaining a singular animation/skeleton format that keeps both sets of data. The Ogre renderer does this, has anyone here had any positive or negative experiences with this system.

Another option is to use two formats, but read them in almost exactly the same (so most internal logic is shared). The difference would be that for skeleton files only a single frame of animation is allowed (the base pose), while animation files allow for multiple keyframes. The point would be to allow the artists to be explicit with how they want to use a model with the animation system (although in the end internally it's not very different from using a unified animation/skeleton format).

Thanks for your help thus far.
"Artificial Intelligence: the art of making computers that behave like the ones in movies."www.CodeFortress.com
MD5 Wiki

Infos about how to setup the model from loaded data

btw the md5 format is so easy to read, you can use the STL ifstream to parse it, so its pretty fast, and since you are probably reading from a packfile you can also write your own tokeniser and just get tokens sperated by whitespaces

I wrote my own tokeniser which works pretty well without the overhead of those generated tokenisers, GTKRadiant for example also uses its own tokeniser
http://www.8ung.at/basiror/theironcross.html
(Perhaps the following text is a bit too detailed since you're "revamping the skeletal animation system" in your engine and may know already most of it.)

Skeletal based animation is a 2 step process: 1st the modifier (i.e. the skeleton in this case) is transformed from its bind pose to its current action pose. 2nd the shape is deformed from its bind shape to the current action shape by following the skeleton ("skinning"). This 2nd step differs in its implementation depending on whether you deform a shape consisting of 1 continuous mesh or else a shape of rigid nested parts.

In the former case a common approach is to blend the transformation prescriptions of up to 4 or so bones to each single vertex. This allows simulation of muscles and to avoid constrictions in the deformed mesh. Now, a way is needed to define which vertices are to be transformed by which bones by using which weights. Besides using pre-defined volumes (e.g. capsules) an artist gets full control if using vertex groups. In this sense a vertex group is nothing more than a set of tuples of a vertex and a weight. Since we want to couple the skeleton prototype and the mesh only loosely, each vertex group has to be named and this name can be used to get the transformation to be applied to the vertices of that group. For this purpose the group's name is searched for in the skeleton, and a matching bone's transformation is the one in request. (To avoid searching during every rendered frame, I actually perform a binding phase when the skeleton instance is added to the scene graph.) In other words, the vertex group's name names the bone that is to be applied to all vertices of that group.

An example: Group "abc" with tuples { (1,1.0) (3,0.9) (4,1.0) } means that the transformation of bone "abc" is to be applied to the vertices with index 1, 3, and 4 with the weights 1.0, 0.9, and 1.0, resp. EDIT: Notice please that vertex groups belong to the mesh but not to the skeleton or animation.

In the latter case (i.e. a shape of rigid nested parts) something like vertex groups are implicitely given by the parts itself. In such a case blending similar to the one above is normally not done at all. However, naming the parts (nodes ?) can be used in an equivalent way.

[Edited by - haegarr on April 11, 2007 2:34:17 AM]
What he is describing above is that each vertex is a convex combination (all weights sum up to 1.0) of weights with a position assigned to a joint/bone


the second link I posted above has an example how this works with MD5 models

http://www.8ung.at/basiror/theironcross.html
Perhaps also interesting to look at: cal3d
Basiror: I'm familiar with that site, what I was asking was more about your impressions using it. I know when I was working with it the format itself was easy to handle but suffered from a number of efficiency issues. Glad to hear your impressions appear positive. I may revisit using it at some point (in case collada loses traction for some reason).

haegarr: I have quite a bit of experience with skeletal animation but thanks for the explanation anyways. I just didn't know that by "vertex groups" you were referring to the vertex weights/indices.

Oh, and thank you very much for the Cal3d reference. I checked it out and their implementation is very similar to what I was proposing and had planned to do. It's kind of validated my assumptions so I plan to move forward with 3 formats (model/skel/anim) as they did.

Thanks again to you both for the great feedback.
"Artificial Intelligence: the art of making computers that behave like the ones in movies."www.CodeFortress.com

This topic is closed to new replies.

Advertisement