Sign in to follow this  
FireViper

Skeleton Animation reference pose

Recommended Posts

FireViper    129
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[i]^-1 * M[i] * w[i] where v = untransformed vertex M[i] = transformation matrix M[i]^-1 = inverse of M w[i] = 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.

Share this post


Link to post
Share on other sites
emeyex    382
Just to clarify, M[i]^-1 should be the inverse of the bone's reference pose transform in model space, not the inverse of M[i]. Also, M[i] 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[ i ] below), and I generally write my vectors on the right side of a matrix transformation.

Here's how I'd write it (not meaning to be pedantic, just hoping the error might become clear):

v' = sum_for_each_vertex_weight_i( W[i] * M[ B[i] ] * Mref[ B[i] ]^-1 ) * v;

v' := animated vertex in model space
W[i] := i'th vertex bone weight, where w[0]...w[N-1] sum to 1
B[i] := the master bone index corresponding to the i'th vertex weight
Mref[ B[i] ]^-1 := inverse of the reference pose transform in model space of B[i]'th bone
M[ B[i] ] := animated transform in model space of B[i]'th bone
v := model space vertex

Hope that helps.

[EDIT: changed order of matrix multiplication in equation]

[Edited by - emeyex on March 3, 2008 12:44:20 PM]

Share this post


Link to post
Share on other sites
FireViper    129
Quote:
Original post by emeyex
v' = sum_for_each_vertex_weight_i( W[i] * Mref[ B[i] ]^-1 * M[ B[i] ] ) * v;


so the program would loop through the number of weights influenced by the vertex, multiply (float)W[i] with (matrix4x4)Mref[ B[i] ]^-1, which would give another 4x4 matrix, which is then multipled by M[ B[i]], 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[i] * Mref[ B[i] ]^-1, I just scale all of Mref[ B[i] ]'s values by W[i]?

Share this post


Link to post
Share on other sites
emeyex    382
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[i] = M[i] * Mref[i]^-1

S[i] := the resulting skinning matrix
M[i] := the animated bone transform in model space
Mref[i]^-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[i]:

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

So now your program (whether a vertex shader or cpu code) would loop through all the weights affecting the vertex v, multiply W[i] (a float) by S[ B[i] ] (a transformation matrix), yielding another matrix. This multiplication should be component-wise (multiply W[i] by each element of S[ B[i] ]). 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[i] * Mref[i]^-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 :).

Share this post


Link to post
Share on other sites
FireViper    129
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; //maxTriangles
Bones[maxBones]; //Holds Transform & Inverse matrix
VertSkin[maxTri]; //Class holds skin influence data (bone IDs & Weights)
matrix4 SkinMat[maxBones]; // skinning matrix
vector3 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[i] = Bone[i].Transform * Bone[i].InverseBind;
}

for(i=0; i<maxTri; i++) //Loop through i'th triangles
{
vector3 v1 = Vertex[Polygon[i].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[i].a ].ID[j];
float weight = VertSkin[ Polygon[i].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,

Share this post


Link to post
Share on other sites
emeyex    382
Things that I would verify:

1) you're using the exact same Bone[i].Transform matrix to render your bone lines as the actual skinned mesh, and not manipulating it in some way
2) ensure your Bone[i].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.

Share this post


Link to post
Share on other sites
FireViper    129
Quote:
Original post by emeyex
2) ensure your Bone[i].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.

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