Sign in to follow this  
NumberXaero

Creating an Animation File Format

Recommended Posts

Animated COLLADA files provide the following info Skin - bind shape matrix - list of joint/weight index pairs - list of weights - list of joint nodes used during skinning - list of inverse bind matrices, one per joint and the animation channel (track) data. Does the entire contents of this file make for a single animation? (lets assume there is only one animation in the file) is the skin info unique to this specific animation data, or is it unique to the model data? I read you can pre transform the model by the bind shape matrix because this will be the base pose for the entire animation. So does that mean for every animation you will have unique skin data (bind pose matrix, weights, inv bind matrix), animation data and a pre transformed mesh copy?

Share this post


Link to post
Share on other sites
Quote:
So does that mean for every animation you will have unique skin data..?

I'm not sure which terms you're applying "unique" to, just the skin data, or animation data and "pre-transformed" mesh. I'm not particularly familiar with Collada so I'll have to guess at what some of your terms mean.

A single set of skin data can be animated with any number of animations. However, the joints in each animation set must match the joints in the skin data.

Yes, you can pre-transform the mesh, but that requires multiple sets of mesh data (which can be a lot of memory depending on the number of vertices), equal in number to the maximum weights-per-vertex. It's a memory versus speed choice.

Is that what you're asking about?

Share this post


Link to post
Share on other sites
Yeah thats what I was wondering about, if i pre transform using the bind shape matrix for every animation (this was assuming each animation got its own set of skin data, with a different bind shape matrix) the copies of that mesh would balloon every time I need a new animation.
Quote:
A single set of skin data can be animated with any number of animations.

This is what I figured at first its also what Im hoping. What Im trying to do is pull all the animation and character geometry from animated COLLADA files, and create a mesh and animation file from them, but Im trying to figure what data is constant across all animations and put that in the mesh file, and the animation data that changes per animation (walk, idle, run, etc) pull that out and drop it in an animation file, then bring it all together. One animated model file, and a bunch of animation files that target it. So any unique data that doesnt change, skeleton node hierarchy, mesh, joint name list, ends up in the mesh. Any data related to making him do an animation, goes into the animation file. So I have

Mesh File
------------------
Skeleton node hierarchy (joints)
Joint name list (referred to by index)containing joint transform data)
Mesh data (that get skinned/rendered)

Animation file
------------------
Single Animation (time data, name)
- containing channels
Multiple channels (track data? xform info for joints)
- target joint index
- interpolation type
- type of output values (quat, translation, scale)
- output values (xform data)

and the skin data which im unsure of where to place, because Im not an animator and Im unsure if this stuff would change per animation, or change partially

Skin data
- bind shape matrix (places him in T pose, is there one of these per animation?)
- list of nodes that are targeted
- inv bind matrix list (one per target node)
- weight list
- per vertex, joint/weight index pairs, or the number of influences per vertex

I guess when youre animating do you "set" a new bind pose at the start before animating? this would change the bind shape matrix, and the inv bind list and at least make those two unique to the animation. Meaning part of the skin info at least would end up in the animation file.

Share this post


Link to post
Share on other sites
Quote:
I guess when youre animating do you "set" a new bind pose at the start before animating?

Hmm. No. You should use the same rest pose for all animations. EDIT: For each animation set (walk, run, etc.), start with the rest pose, orient each joint (which moves the mesh) for frame 0 of the animation. Don't set a "new" rest pose. Animate the rest of the frames.

The inverse bind matrices move the rest pose into joint space. The animation matrices move the vertices from joint space back into world space. The animation data doesn't "know" anything about the rest pose in the Mesh data. It's just data that you've created, based on moving the rest pose around.

The skinning data is (should be) a list of joints (each of which must correspond to a node in the mesh hierarchy), list of vertices/weights that the joint influences, and info to transform the mesh into joint space (the inverse bind matrices).

If you're careful with your bookkeeping and you want to, there's no reason (except wasting some memory) not to include skinning info for a joint in its node in the hierarchy.

Mesh rest pose vertices + skinning info = Mesh Data (can be used for any animation that has the same hierarchy and is based on the same rest pose)

[Edited by - Buckeye on February 20, 2010 12:12:32 PM]

Share this post


Link to post
Share on other sites
Im basing this all off what COLLADA throws at me so I get the feeling there is something I should be calculating/deriving from this data that isnt explicitly provided with respect to "poses". What Im doing right now is

- after loading the mesh, create a copy of it and transform each vertex position by the <bind_shape_matrix> (BSM) a 4x4 matrix (transform normal later when its working)

loaded mesh data (skinned and render)
loaded mesh data copy (pre transformed copy of loaded mesh by BSM)

Each frame with a running animation...
1) Update the Animation: Interpolate/build the joint animation xform data, apply it to the joint
2a) Update the joint hierarchy: creates jointWorld
2b) Update skinMatrix = jointWorld * jointInvBind
3) Update skin mesh: Using the pre transformed bind shape copy
For each vertex (from BSM copy)
- start with bsm_vertex
- For each vertex influence (joint/weight)
-- get joints skin matrix, get weight
-- out_vertex += (jointSkinMatrix * bsm_vertex) * weight
- store skinned out_vertex for rendering
Next vertex (from BSM copy)

this does perform the animation, but because the bind shape matrix is always the same T pose (character terminology, rest pose?) for every animation (walk, run idle), it seems that its influencing or biasing every animation towards this T pose, which would make sense seeing as its being used that way (start point for skinning), but it seems like it shouldnt. Which is where this idea of some sort of start "pose" per animation comes in, which I feel Im missing, and should be calculating some how. Or, a bind shape matrix per animation, something. Although it could be related to the way it was animated.

For ref sake, the weight data looks odd but that because his parts are not joined, Rayman like

Share this post


Link to post
Share on other sites
Quote:
transform each vertex position by the <bind_shape_matrix> (BSM)

I'm not familiar with Collada, I'm afraid, and I'm not sure what you mean by BSM. If your statement has anything to do with using some sort of matrix related to joints which influence the vertex, that's not good.

Animation is usually done:

v1 = original_v*inverseBindMatrix[joint1]*animMatrix[joint1]*weight[joint1]
v2 = original_v*inverseBindMatrix[joint2]*animMatrix[joint2]*weight[joint2]
finalV = v1 + v2

where animMatrix[jointx] is the lerped/slerped matrix for the animation time
If you're doing something like:

v_used_for_animation = original_v*inverseBindMatrix[joint1]*weight[joint1]+original_v*inverseBindMatrix[joint2]*weight[joint2]...

and then using v_used_for_animation for animating the mesh, that's not the same.

EDIT: I may be making some invalid assumptions regarding what Collada is giving you. I'm afraid I can't follow the terms you use (skinMatrix, jointWorld, etc.).

In general, I would expect (after you load the mesh and animation data):
vertex_array - vertex positions, normals, array of joint indices & weights, etc.
offset_array - an array of matrices, one for each joint (inverseBindMatrix??), once created, never changes
animation_matrix_array - matrices to be updated during animation.

[Edited by - Buckeye on February 20, 2010 2:13:03 PM]

Share this post


Link to post
Share on other sites
In your first example where would "animMatrix" come from? What would it be? How is it calculated?

From the COLLADA spec BSM is... which I assumed to be the first matrix you apply to the mesh vertices every frame, regardless, so do it once and store a copy of the original mesh with it applied



where:
n: number of joints that influence vertex v
BSM: bind shape matrix
IBMi: inverse bind matrix of joint i
JMi: joint matrix of joint i
JW: joint weight/influence of joint i on vertex v
Common optimizations include:
(v * BSM) is calculated and stored at load time.

Share this post


Link to post
Share on other sites
Okay. That's (sort of) the algorithm for generating the animated vertex (outv) that I mentioned above. JMi is the animation matrix. I'm guessing that BSM may just be a transform for the base pose mesh.

So, taking it one step at a time:
Quote:
1) Update the Animation: Interpolate/build the joint animation xform data, apply it to the joint

What do you mean by "apply it to the joint"?

Just for clarification, the animation matrix calculated for each joint from the animation data is a local transform and needs to be combined with it's parent's animated transform and it's parent-parent's xform, etc. Perhaps that's what your step "2a) Update the joint hierarchy: creates jointWorld" is doing?

Share this post


Link to post
Share on other sites
Yes. The result of the interpolation is stored as the joints local xform, once all interpolating is done and the local is set for each joint, the world matrix is calculated from the parents of each joint (JM from the img, which i have referred to has jointWorld, which I think is your animMatrix).

Quote:
I'm guessing that BSM may just be a transform for the base pose mesh.


Yes. I must have the Bind shape matrix applied to my vertices first or my geometry explodes and arms and legs end up everywhere.

Share this post


Link to post
Share on other sites
Quote:
skinMatrix = jointWorld * jointInvBind

Then you multiply the jointWorld and jointInvBind and store it in array which you call jointSkinMatrix?

If so, then it appears your general algorithm is correct.

I kinda lost track, are you still having a problem? [looksaround]

Share this post


Link to post
Share on other sites
Quote:
are you still having a problem?

Yeah, something is still off, I didnt think the skinning was ever a problem, in that it animated correctly, but looks off.
And it looks off in such a way that it seems to be pulling toward the bind pose (T Pose, or rest pose). But it seems Im only suppose to have one of them ever with the skinning info. For instance one of the animations that is leaning forward animates sort of tilted back from where it should be, almost as though the bind shape matrix being applied is pulling it towards the rest pose.
Ill have to give it a closer look. Thanks for your help, atleast I know its not completely off.

Edit: yeah the skinMatrix is basically the middle part of the formula calculated and stored per joint, and used when the weight is applied,

Share this post


Link to post
Share on other sites
I'm not a collada expert, but...

Quote:
Original post by NumberXaero
is the skin info unique to this specific animation data, or is it unique to the model data?
...
So does that mean for every animation you will have unique skin data (bind pose matrix, weights, inv bind matrix), animation data and a pre transformed mesh copy

My understanding is that the skin info represents the time when the vertices are bound to the skeleton. The skin data will appear to be unique to the model if neither the mesh is reskinned, nor the bind pose is altered for different animations. I think the BSM moves the vertices from world space to object space. The invBind matrices are then defined in that space (bringing a vertex from object space into the joint's space). If the model has multiple skin groups (materials, etc) then the BSM is likely different for each group even if they are bound to the same skeleton.

I used the (BSM * v) exclusively for animated models. Which it sounds like you are already doing?

Good luck, collada threw me some curveballs when I used it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this