# skeleton animation

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

## Recommended Posts

Hy. I'm starting to implement a skeleton animation , and i have a doubt: I use a collada file and i have this node hierarchie:
&lt;node name="joint2" sid="joint2" type="JOINT"&gt;
&lt;translate sid="translate"&gt;0 30 0&lt;/translate&gt;
&lt;rotate sid="jointOrientZ"&gt;0 0 1 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientY"&gt;0 1 0 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientX"&gt;1 0 0 0&lt;/rotate&gt;
&lt;node name="joint3" sid="joint3" type="JOINT"&gt;
&lt;translate sid="translate"&gt;0 30 0&lt;/translate&gt;
&lt;rotate sid="jointOrientZ"&gt;0 0 1 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientY"&gt;0 1 0 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientX"&gt;1 0 0 0&lt;/rotate&gt;
&lt;node name="joint4" sid="joint4" type="JOINT"&gt;
&lt;translate sid="translate"&gt;0 30 0&lt;/translate&gt;
&lt;rotate sid="jointOrientZ"&gt;0 0 1 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientY"&gt;0 1 0 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientX"&gt;1 0 0 0&lt;/rotate&gt;
&lt;node name="joint5" sid="joint5" type="JOINT"&gt;
&lt;translate sid="translate"&gt;0 30 0&lt;/translate&gt;
&lt;rotate sid="jointOrientZ"&gt;0 0 1 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientY"&gt;0 1 0 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientX"&gt;1 0 0 0&lt;/rotate&gt;
&lt;rotate sid="rotateZ"&gt;0 0 1 1.22906&lt;/rotate&gt;
&lt;node name="joint6" sid="joint6" type="JOINT"&gt;
&lt;translate sid="translate"&gt;0 30 0&lt;/translate&gt;
&lt;rotate sid="jointOrientZ"&gt;0 0 1 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientY"&gt;0 1 0 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientX"&gt;1 0 0 0&lt;/rotate&gt;
&lt;node name="joint7" sid="joint7" type="JOINT"&gt;
&lt;translate sid="translate"&gt;0 30 0&lt;/translate&gt;
&lt;rotate sid="jointOrientZ"&gt;0 0 1 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientY"&gt;0 1 0 0&lt;/rotate&gt;
&lt;rotate sid="jointOrientX"&gt;1 0 0 0&lt;/rotate&gt;
&lt;/node&gt;
&lt;/node&gt;
&lt;/node&gt;
&lt;/node&gt;
&lt;/node&gt;
&lt;/node&gt;
&lt;/node&gt;


why i have one or more transform for each node? Is that the bind pose? because i must get the transformation matrix in the animation section , for the frame key current is correct? Then this is a start keyframe? Thanks.

##### Share on other sites
It kind of looks like what you posted is actually the skeleton hierarchy, which shows which joints are children of which other joints. There doesn't appear to be any real transformation data except for joint5, which has a z-rotation, all the other JointOrientZYZ things just seem to be defining the handedness of the coordinate system for that joint's change of frame transformation (they all have a 30 unit translation on the y-axis though, which is kind of weird).

Typically a skeleton hierarchy will have transformation matrices at each node which when combined with the skinning data would place the model in "bind" position. You still need to know which vertices are influenced by which bones (joints) and with what weight, without knowing that it doesn't help much to have a skeleton hierarchy. Sometimes when providing this information the model will also have a per bone offset matrix that transforms any vertices attached to that bone even more than just the skeleton hierarchy transformation.

So the formula to compute a given vertices position in model space is as follows:

A = bone offset matrix (there is one for each bone, so its an array)
B = matrix concatentation of all parent joints in the hierarchy above this joint, sometimes called the "toRoot" transform.
C[] = Array of bones that influence this vertex (usually maxed at 4 for hardware skinning), C[0] holds the bone index of the first bone that influences this vertex.
D[] = Array of bone weight influences for this vertex (usually just 3 are provided and final weight is given as 1.0f - sum of other weights).
E(t, b) = matrix computed from interpolating keyframe data for this channel (this joint), given a particular time t and a particular bone b.

v = original vertex position in model file
V = final vertex position in model space

M = v * (A[C[0]] * D[0] + A[C[1]] * D[1] + A[C[2]] * D[2] + A[C[3]] * D[3]) * B;

V = M * E(t, C[0]) * D[0] +
M * E(t, C[1]) * D[1] +
M * E(t, C[2]) * D[2] +
M * E(t, C[3]) * D[3];

I just included 4 D[] components for simplicity above.

What this basically says is to start with the original vertex, move it by the bone offsets of all the bones that influence it and then move it up the skeleton hierarchy into the root space. This gives you the vector M.

Now take that vector and multiply it by all the E matrices for a given time t and a given bone C of each bone that influences it (using the weighted averages specified in D[]).

That final step can be done on the GPU using hardware skinning BTW.

Then you would take V and multiply it by World View Projection to get it into your scene.

You would also need to do that weighted averaging with the normals too.

##### Share on other sites
Thanks.
Quote:
 M = v * (A[C[0]] * D[0] + A[C[1]] * D[1] + A[C[2]] * D[2] + A[C[3]] * D[3]) * B;V = M * E(t, C[0]) * D[0] +M * E(t, C[1]) * D[1] +M * E(t, C[2]) * D[2] +M * E(t, C[3]) * D[3];

I'm not understand what is M(matrix?) and why multiply it for the vertex weight two times:

M * E(t, C[0]) * D[0] and
A[C[0]] * D[0]

and why:
Quote:
 B = matrix concatentation of all parent joints in the hierarchy above this

I must moltiply for the parents bone final matrix?
The result of all for bone matrixes multiplycation(M)?

##### Share on other sites
M is the original vertex, transformed by the bone offsets of all the bones that influence it and then transformed up the skeleton hierarchy to the "root" space. It is also the input to your hardware-skinning vertex shader ;-)

You don't multiply it by the vertex weight two times, you use the vertex weight to average two different quantities into the final vertex position.

The first use of the vertex weights is to average all the bone offset matrices that influence this vertex together to transform the original vertex by the bone offset transform (this moves the vertex from bind space to bone space).

(A[C[0]] * D[0] + A[C[1]] * D[1] + A[C[2]] * D[2] + A[C[3]] * D[3])

Here the array D holds the vertex weights
The array C holds the bone index 0..numBones of the bone that influences this vertex (up to 4 bones can influence any particular vertex).
The array A is an array of bone offsets, one for each of your model's bones.

So A[C[0]] is going to find the bone index for the first bone that influences this vertex and look up that bone index in the bone offset array A. By multiplying it by D[0] we are "weighting" it so that we don't use 100% of that bone offset (unless D[0] is 1.0f)

Now the vertex is in "bone space", after that you need to get it into "root" space by multiplying it by the toRoot transform. The definition of the toRoot transform for a bone 'i' is given by the following recurrence relation:

toRoot(i) = toParent(i) * toRoot(p) where 'p' is the bone index of the parent of bone 'i'. EDIT: I don't remember if you also have to weighted average all the toRoot transforms of each bone that influences the vertex here also..

Now comes the second use of the vertex weights (in the hardware skinning shader) averages all the animation bone transforms that influence this vertex, given a certain time t.

V = M * E(t, C[0]) * D[0] +
M * E(t, C[1]) * D[1] +
M * E(t, C[2]) * D[2] +
M * E(t, C[3]) * D[3];

Typically E(t, 0..numBones) will be precomputed on the cpu and then loaded to the gpu via shader constants registers. The vertex weights and bone indices are provided to the vertex shader per-vertex in the vertex buffer (directX)

1. 1
2. 2
3. 3
4. 4
Rutin
15
5. 5

• 13
• 26
• 10
• 11
• 9
• ### Forum Statistics

• Total Topics
633722
• Total Posts
3013550
×