Sign in to follow this  
spek

Vertex skinning, blending matrices problem

Recommended Posts

I'm doing something wrong here with the skeleton animations, using matrices. Most vertices have only 1 bone, but where 2 bones are used it goes wrong. If I use them seperately the result is correct. So, either I initialize the skeleton wrong, or the blending goes wrong. In case 2 bones are used on a vertex, they both have a weight of 0.5 so far. The sum of the weights is always one.
// initialize all vertices via the INVERSE MATRIX of the base pose
for each vertex
	m4x4 bone1Matrix	= skeleton.BasePose.InverseMatrix[ vertex.boneIndex1 ];
	m4x4 bone2Matrix	= skeleton.BasePose.InverseMatrix[ vertex.boneIndex2 ];
	
	// Multiply matrices with the basepose world vertices
	v1	= bone1Matrix * skeleton.Mesh.vertex[i]
	v2	= bone2Matrix * skeleton.Mesh.vertex[i]
	
	// result (weights are both 0.5)
	// Store into a initial skinned vertexlist
	vRes	= v1 * weight1  +  v2 * weight2;
	skeleton.BasePose.skinnedVertex[i] = vRes;
Next step would be animating with the base data:
// Transform all vertices
for each vertex
	m4x4 bone1Matrix	= skeleton.currentFrame.Matrix[ vertex.boneIndex1 ];
	m4x4 bone2Matrix	= skeleton.currentFrame.Matrix[ vertex.boneIndex2 ];
	
	// Multiply current matrices with the skinned vertices
	// from the initial stage.
	v1	= bone1Matrix * skeleton.BasePose.skinnedVertex[i]
	v2	= bone2Matrix * skeleton.BasePose.skinnedVertex[i]
	
	// result (weights are both 0.5)
	// Store into result
	vRes	= v1 * weight1  +  v2 * weight2;
	skeleton.skinnedResult.vertex[i] = vRes;
I think it goes wrong because the initial vertex was made by two matrices. The two seperate transformations in the second step go wrong. I could fix this by storing TWO sets of initial skinned vertices, but maybe it can be fixed alot more easy. I mean, skinning shaders only have 1 set of vertices either so... Rick

Share this post


Link to post
Share on other sites
You could use 2 arrays of pre-calculated vertices, I suppose. But, for large meshes, those arrays could be pretty big.

Perhaps the most straightforward way would be to just use the inverse matrix to calculate the final vertex positions.


// Transform all vertices
for each vertex
m4x4 bone1Matrix = skeleton.currentFrame.Matrix[ vertex.boneIndex1 ];
m4x4 bone2Matrix = skeleton.currentFrame.Matrix[ vertex.boneIndex2 ];

// Multiply current matrices with the inverse matrix and vert
v1 = bone1Matrix * skeleton.BasePose.InverseMatrix[vertex.boneIndex1] * skeleton.Mesh.vertex[i];
v2 = bone2Matrix * skeleton.BasePose.InverseMatrix[vertex.boneIndex2] * skeleton.Mesh.vertex[i];

// result (weights are both 0.5)
// Store into result
vRes = v1 * weight1 + v2 * weight2;
skeleton.skinnedResult.vertex[i] = vRes;

Does that work?

Because several vertices may be influenced by the same bone, you can also calculate an array of
// finalMatrix = array of size(numBones)
finalMatrix[boneIndex] = boneMatrix[boneIndex]*inverseMatrix[boneIndex]
...
Then, in your loop, calculate:
v1 = finalMatrix[boneIndex1]*meshVert[i];
v2 = finalMatrix[boneIndex2]*meshVert[i];

Quote:
skinning shaders only have 1 set of vertices either

Not sure what you mean by this. Shaders can be written to use multiple bone indices and matrices. Is that your concern?

A common algorithm to use with a shader is to calculate an array of finalMatrices = boneMatrix * inverseMatrix for each bone, as mentioned above.
...
The vertex position is calculated in the shader, given an array of those finalMatrices:

pos = vector4( 0, 0, 0, 1);
v = input_mesh_vertex;
numWeights = number_of_weights_for_this_vertex;
weight[numWeights] = array_of_weights, usually passed in shader input structure per-vertex
boneIndex = array_of_bone_indices, usually passed in shader input per-vertex
sumWeights = 0;
for( int n=0; n < numWeights-1; n++)
{
pos += finalMatrix[ boneIndex[n] ] * v * weight[n];
sumWeights += weight[n];
}
pos += finalMatrix[ boneIndex[numWeights-1]] * v * ( 1 - sumWeights );

This shader code, by the way, may have to have the order of multiplications reversed. I.e., pos += weight[n] * v * finalMatrix[boneIndex[n]], etc.

[Edited by - Buckeye on February 19, 2010 8:39:26 AM]

Share this post


Link to post
Share on other sites
Thanks for all the info!

What I meant to say was that shaders only make use of 1 set of vertices, and 1 set of matrices. The problem is that I make an initial list of vertices that are multiplied with their inverse bone matrix. But it seems to go wrong when I create an initial vertex that is assigned to 2 bones.

You showed how to make "final matrices", sounds what I need. If I understand it properly, instead of making this "initial mesh" I'll apply the base pose at runtime on the resulting matrices. So I can use the original set of vertices.

I gave it a quick try with just 1 weight. A few times I got "The Thing" as a result, but now he's walking like a charm again :). I'll try it with multiple bones now.

Thanks!
Rick

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