Sign in to follow this  

Vertex skinning, blending matrices problem

This topic is 2852 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 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

This topic is 2852 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.

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