Skeleton Animation reference pose

Started by
5 comments, last by FireViper 16 years, 1 month ago
As far as I know, a models reference pose shouldn't affect the model's animation, as long as you store the inverse matrix of the reference pose during the binding process, and multiply it with the Bone's transformation matrix during the rendering process. When i searched the net and found the vertex transformation code looks something like, v = v` * M^-1 * M * w where v = untransformed vertex M = transformation matrix M^-1 = inverse of M w = bone's weigth i = number of bones influenced by v In the reference pose, the model is spreading its arms, to form a 'T' shape. However, during the an animation, when I rotate the arm bones by 90 degrees in the z axis. The arm bones get transformed just fine, but the arm vertices are transformed down to the models knees. I'm not sure if its my code, or the reference pose that Im makimg a mistake with.
Advertisement
Just to clarify, M^-1 should be the inverse of the bone's reference pose transform in model space, not the inverse of M. Also, M is the animated transform in model space... true? Otherwise, at a glance, everything seems maybe correct... you have your v and v' on the wrong sides of the equation, you didn't explicitly state that you were summing the weighted matrices, you may have been mixing up your indices (see the difference between i and B below), and I generally write my vectors &#111;n the right side of a matrix transformation.<br><br>Here's how I'd write it (not meaning to be pedantic, just hoping the error might become clear):<br><br>v' = sum_for_each_vertex_weight_i( W<span style="font-weight:bold;"> * M[ B<span style="font-weight:bold;"> ] * Mref[ B<span style="font-weight:bold;"> ]^-1 ) * v;<br><br>v' := animated vertex in model space<br>W<span style="font-weight:bold;"> := i'th vertex bone weight, where w[0]…w[N-1] sum to 1<br>B<span style="font-weight:bold;"> := the master bone index corresponding to the i'th vertex weight<br>Mref[ B<span style="font-weight:bold;"> ]^-1 := inverse of the reference pose transform in model space of B<span style="font-weight:bold;">'th bone<br>M[ B<span style="font-weight:bold;"> ] := animated transform in model space of B<span style="font-weight:bold;">'th bone<br>v := model space vertex<br><br>Hope that helps.<br><br>[EDIT: changed order of matrix multiplication in equation]<br><br><!–EDIT–><span class=editedby><!–/EDIT–>[Edited by - emeyex on March 3, 2008 12:44:20 PM]<!–EDIT–></span><!–/EDIT–>
Quote:Original post by emeyex
v' = sum_for_each_vertex_weight_i( W * Mref[ B ]^-1 * M[ B ] ) * v;


so the program would loop through the number of weights influenced by the vertex, multiply (float)W with (matrix4x4)Mref[ B ]^-1, which would give another 4x4 matrix, which is then multipled by M[ B], and the result is stored in another matrix, which is multiplied by v when the loop ends.
Alright, I think I got it, but its been a while since I did matrix math, and can't remember how to multiply a float to matrix. So when I multiply W * Mref[ B ]^-1, I just scale all of Mref[ B ]'s values by W?

The first step should be to get the skinning matrix array, let's call it S, where each element in S is a transformation matrix. The size of S should be equal to the total number of bones in your skeleton. Each element of S should be computed as:

S = M * Mref^-1

S := the resulting skinning matrix
M := the animated bone transform in model space
Mref^-1 := inverse of the reference pose transform in model space of i'th bone

Generally you resolve this array S before doing any rendering for the frame. Now that you have it, you can go and skin your model. Usually this is done in a vertex shader on the gpu, but you can also do this in software, which leads us back to the equation your were mentioning for a given vertex. We can now express it in terms of the skinning matrix S:

v' = sum_for_each_vertex_weight_i( W * S[ B ] ) * v;

So now your program (whether a vertex shader or cpu code) would loop through all the weights affecting the vertex v, multiply W (a float) by S[ B ] (a transformation matrix), yielding another matrix. This multiplication should be component-wise (multiply W by each element of S[ B ]). You add all those weighted multiplications together (again, add component-wise for the matrices), then multiply your vertex v by this resulting matrix....

Also, note that I changed the order of the M * Mref^-1 multiplication from what I posted originally. It all depends on how you store your matrices, and how you multiply your vectors by your matrices.

Hope I didn't just confuse you more :).
Well you didnt confuse me....much. I tried to do what you said, but I the same results.
Here my rendering code:

int maxBones;         int maxTri;           //maxTrianglesBones[maxBones];      //Holds Transform & Inverse matrixVertSkin[maxTri];     //Class holds skin influence data (bone IDs & Weights)matrix4 SkinMat[maxBones]; // skinning matrixvector3 Vertex[maxVertices]; //holds list of vertices (float x,y,z)polygon Polygon[maxTri];     //holds triangle indices (int a,b,c)for(i=0; i < maxBones; i++) //loop through i'th bones{  //Calculate skinning matrix  SkinMat = Bone.Transform * Bone.InverseBind;}for(i=0; i<maxTri; i++) //Loop through i'th triangles{ vector3 v1 = Vertex[Polygon.a]; //untransformed point int maxInfluences; //# of bones that influence v  matrix4 M; //holds sum of weights //loop through j'th weights for(int j=0; j < maxInfluences; j++) {    int boneID   = VertSkin[ Polygon.a ].ID[j];     float weight = VertSkin[ Polygon.a ].Weight[j];    if(j==0)      M = SkinMat[ boneID ] * weight;    else       M = M+(SkinMat[ boneID ] * weight); } //transform v1 by the sum of all weights v1 = M * v1; ... // Calculate v2 & v3 ... // Render Triangle}



Im not sure if im making a mistake in the rendering code, or my matrix multiplication code.

Heres a screenshot of simple skinned mesh in its reference pose:


And here is a screenshot once i rotate the arm bones,
Things that I would verify:

1) you're using the exact same Bone.Transform matrix to render your bone lines as the actual skinned mesh, and not manipulating it in some way
2) ensure your Bone.InverseBind is correct (after you compute the inverse of the reference pose, invert the matrix again and ensure it's "equal" to the reference pose)
3) to simplify things, I'd make sure there is no scaling in any of your bone matrices (reference pose or animations)
4) depending on how you've defined your matrix multiplications, it's always worth trying to swap the order and see if that works :).
5) this one is just on the off-chance that your pseudo-code doesn't exactly represent what you're doing: you're looping through all the triangles of your mesh, and then all the vertices for each triangle. while this is natural for the way you're rendering each triangle one at a time, it means you're actually re-skinning certain vertices (because the vertices are indexed). If you were to store the result of the first visit and somehow re-use it the next time, that would cause a problem. Like I said, it doesn't actually seem like you're doing this, but it's worth a mention... performance could also be improved by visiting all the verts and skinning them first, and then rendering the triangles...

I'll think a little longer and re-post if anything else jumps out at me.
Quote:Original post by emeyex
2) ensure your Bone.InverseBind is correct (after you compute the inverse of the reference pose, invert the matrix again and ensure it's "equal" to the reference pose)


well Im not sure if it makes a difference, but the way I calcualte the Inverse matrix is, during the Binding function, I loop through all the bones, Set the Inverse matrix to the Transpose of the Bone's Transform matrix. However, thats shouldnt really matter, because when i multiply the Transform by its Inverse, I get its Identity.

Quote:
I'll think a little longer and re-post if anything else jumps out at me.


Thanks, that would really help.

This topic is closed to new replies.

Advertisement