Jump to content
• Advertisement

Vertex skinning, blending matrices problem

This topic is 3217 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
v2	= bone2Matrix * skeleton.Mesh.vertex

// result (weights are both 0.5)
// Store into a initial skinned vertexlist
vRes	= v1 * weight1  +  v2 * weight2;
skeleton.BasePose.skinnedVertex = 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
v2	= bone2Matrix * skeleton.BasePose.skinnedVertex

// result (weights are both 0.5)
// Store into result
vRes	= v1 * weight1  +  v2 * weight2;
skeleton.skinnedResult.vertex = 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

Share on other sites
Advertisement
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 verticesfor 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;	v2 = bone2Matrix * skeleton.BasePose.InverseMatrix[vertex.boneIndex2] * skeleton.Mesh.vertex;		// result (weights are both 0.5)	// Store into result	vRes	= v1 * weight1  +  v2 * weight2;	skeleton.skinnedResult.vertex = 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;v2 = finalMatrix[boneIndex2]*meshVert;

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-vertexboneIndex = array_of_bone_indices, usually passed in shader input per-vertexsumWeights = 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

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

Share on other sites
And with two bones it finally works as well :) Thanks again

Share this post

Share on other sites

• Advertisement
• Advertisement

• Popular Contributors

1. 1
2. 2
3. 3
Rutin
14
4. 4
khawk
11
5. 5
• Advertisement

• 9
• 9
• 11
• 11
• 23
• Forum Statistics

• Total Topics
633671
• Total Posts
3013268
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!