• Advertisement
Sign in to follow this  

.X animation

This topic is 2770 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts


I'm trying to build a manual parser for .X files, without using the DirectX specific functions for loading, just to learn by practicing how skinning and animation works. I am already able to present the mesh on the screen, and I'm pretty sure that all of the data in the file is being loaded correctly (including animation data).

I'm now trying to reproduce the animation set contained in a sample .x file, but I can't seem to get it right. Each bone saves its matrix, children bones, the vertices it affects and their weight. Then, before drawing a mesh I update it and try to perform the transformations given by the bones. To do so, for each bone, I get the bone matrix, multiply it by the keyframe matrix (a matrix that is interpolated from two consecutive keyframes) and transform each vertex affected by the bone by the resulting matrix * the weight for that vertex.

Something like:

foreach (Bone bone in bones)
matrix boneMatrix = bone->matrix;
matrix animMatrix = animation->getCurrentMatrix();

//I'm hoping that this gives me the bone position in a given moment
matrix result = boneMatrix * animMatrix;

foreach (Vertex v in vertices)
matrix weightedMatrix = result * bone->getWeight(v);
v = weightedMatrix * v;

However, doing something like this simply destroys the mesh and the animation is nothing like what it should be. I'm probably missing something very evident here, but I can't seem to find what...

Thanks in advance...

Share this post

Link to post
Share on other sites
I'm not sure that applying the weights to the matrices is correct. In a shader, the weights are applied to the positions, not the matrices.

From an animation shader:

float3 p = float3(0.0f, 0.0f, 0.0f);
float lastWeight = 0.0f;
int n = NumVertInfluences-1;
for(int i = 0; i < n; ++i)
lastWeight += weights;
p += weights * mul(pos, (float4x3)FinalTransforms[boneIndices]);
lastWeight = 1.0f - lastWeight;

p += lastWeight * mul(pos, (float4x3)FinalTransforms[boneIndices[n]]);

You need to duplicate that algorithm. "weights" is the array of vertex weights. "FinalTransforms" is an array of final matrices, one for each bone. "boneIndices" is an array of the influence vertex indices.

That is, weights is the weight for vertex boneIndices.

The FinalTransforms are calculated first. Then, for each vertex, starting with a temporary position = (0,0,0) - apply the first influence matrix to the bone position. Then apply the weighting factor for that influence vertex. Add that weighted position to the temporary position. Continue with the rest of the influences, ensuring the total weight = 1.0

final bone position = weight[0]*( unweighted position * influenceMatrix[0] ) + weight[1]*( unweighted position * influenceMatrix[1] + ...

Share this post

Link to post
Share on other sites
I don't know what "boneMatrix" is or where it comes from, but there are at least two important matrices you need to use
for transforming skinned meshes, with or without animation:

template FrameTransformMatrix {
Matrix4x4 frameMatrix;
"Defines a local transform for a frame (and all its child objects)."

template SkinWeights {
STRING transformNodeName;
DWORD nWeights;
array DWORD vertexIndices[nWeights];
array FLOAT weights[nWeights];
Matrix4x4 matrixOffset;
"The matrix matrixOffset transforms the mesh vertices to the space of the bone. When concatenated to the
bone's transform, this provides the world space coordinates of the mesh as affected by the bone."

If you want my advice, first get the skinned mesh transformation down correctly. This does not require animation.
When that's working, try adding animation. Because, you obviously can't animate a skinned mesh if it's not tranformed correctly
in the first place.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement