Sign in to follow this  

Skeletal animation math

This topic is 4684 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 in a dilemma I wrote everything and in the end I get this, It’s definitely the weights and the way I'm using them, given that I have no experience on the subject I could certainly say I did it wrong... So far I’ve just been stumbling in the dark. So I could use some illumination =D. anyway, I’m generating the weights for each bone by the distance from the child vertex to the parent pivot, using Weightbone += ( 50 / Magnitude( ParentVertex - Pivotbone ) )5 After adding all the weights together, I then make them so they all add to make 1 for any given vertice. Then I use the formula, NewVertex = Sum_of_all_bones_N ( ( Vertex*MatrixN ) * WeightN ) To do the vertex positions, I know something has to be wrong. It’s probably blatantly wrong to anyone how as experience with Skeletal Animation. If I’m not clear enough or I lacked some details I’d happy to post more information. Please help!

Share this post


Link to post
Share on other sites
When you initially skin the geometry, the vertices and bones are in the bind pose.
Each vertex has position "VertBindPos", each bone has transform "BoneBindMatrix"

To compute the world space position of a vertex attached to a single bone, you must first
put the vertex into the bind pose space of the bone, and then multiply the result by the
bones current world space matrix (you can pre-compute the bone inverse bind matrix offline and store it
ready for runtime use).

For skinning, you just perform the operation for multiple bones and take the weight into
account for each bone.

The math for computing the final skinned world space position of a vertex is then as follows:

vector3 VertSkinWorldPos( 0, 0, 0 );
for( int i = 0; i < nBones; i++)
{
vector3 VertBoneBindPos = VertBindPos * BoneInverseBindMatrix;
vector3 VertBoneWorldPos = VertBoneBindPos * BoneWorldMatrix;

VertSkinWorldPos += VertBoneWorldPos * VertBoneWeight;
}


I hope this helps.

Share this post


Link to post
Share on other sites
Quote:
Original post by sbroumley
vector3 VertBoneBindPos = VertBindPos * BoneInverseBindMatrix;
vector3 VertBoneWorldPos = VertBoneBindPos * BoneWorldMatrix;


Thanks for the response,
What exactly are the Bind matrix and the World Matrix? Could you explain how to make them?

Heres what I'm doing:
I only have 1 matrix at the time being, and I make it like this,

1. I subtract the initial pivot in object space
2. I then rotate the vertices around the pivot
3. Then I add the computed world space pivot to the final vertex after rotation

I then multiply the vertices by this matrix, and then add them up after each one is multiplied by its weight and that results in the above structure (see image)

Share this post


Link to post
Share on other sites
It is hard to tell from your figure what the problem is. How many bones are in the model? Just 2? The method for generating weights sounds fine. But looking at the image, if that is your yellow dot is the second bone and that bone should be pointing in the direction of the end, the weights are off.

As Steve said, it could be your deformation math not the weights. But if the bones are as I described, it looks like the deformation math works.

I would suggest a debug mode where you color the vertex by the dominant bone so you can visualize how your method works. Also verify the deformation math by assigning the weights rigidly to each vertex and make sure you get the expected result.

I wrote an article on automatic weighting of vertices for Game Developer several years back that I don't think I ever posted. I try to post that this week.

Share this post


Link to post
Share on other sites
I saw your reply after I posted mine. I have posted a couple of articles that explain how the bind pose and weights work. You should read those to get familiar with the technique and terms.

Skinning in opengl with weight editing and a simple bone system.
http://www.darwin3d.com/gdm1998.htm#gdm0598

Better explaination of the deformation math and DirectX code.
http://www.darwin3d.com/gdm1999.htm#gdm1099

Share this post


Link to post
Share on other sites
Quote:
Original post by JeffLander
It is hard to tell from your figure what the problem is. How many bones are in the model? Just 2?

if that is your yellow dot is the second bone


to the first, right just 2, I thought I would simplify and add more polys and just work with a simple cylinder then a human model that I was trying eariler.

second, Thats the location of the joint between the 2 bones.

thanks for the links I'll read them right away

Added:
Heres my Bone weight distribution


now that I see this I can frankly see that its bit one sided...

[Edited by - Xero-X2 on February 12, 2005 1:32:38 PM]

Share this post


Link to post
Share on other sites
bah, just got back from work. So I can work on this again, I recreated the weighting code, for this much nicer even distribution with a kind of Averaging across the vertices based on the triangle connections.


how ever, the bone still shrinks where it bends far to much, but progress has been made!

So I'll work working and I would appreciate any more help that can be givin, perhapes suggestions. Many thanks to JeffLander and sbroumley so far. =D

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
What you see is correct, your code is good now, you jus need to work on the weight distribution on the mesh itself now.
So that you can see it is correct look at the following ASCII art :) :

Green weight tries to do this:

|...|
|...|
|...|________
|...|
|...|________

Red:

|...|
|...|
___________
...........
___________

So it shrinks because the red weight makes the vertices go to the left and the green weight makes it go down.
To fix it make the weight more "sharp" on the place where it shrinks.

Share this post


Link to post
Share on other sites
Quote:
Original post by sbroumley
vector3 VertSkinWorldPos( 0, 0, 0 );
for( int i = 0; i < nBones; i++)
{
vector3 VertBoneBindPos = VertBindPos * BoneInverseBindMatrix;
vector3 VertBoneWorldPos = VertBoneBindPos * BoneWorldMatrix;

VertSkinWorldPos += VertBoneWorldPos * VertBoneWeight;
}


Is that correct? Shouldn't you be looping weights per vertex instead?
for(int i=0; i < nWeights; i++) {
}

Or maybe you mean bones per vertex?

Share this post


Link to post
Share on other sites
Pinching at the joints as well as it collapsing when the bones twist is a known problem with this skinning method. There are lots of ways to fix it, use a set of small bones at the joint to soften the crease, add a bone at the joint that scales up and/or moves as the limb angle shrinks, etc. Most apps just sharped the falloff so in configs like yours it looks more like a fold.

To answer Raydog, the math ends up the same. You can even apply the weights to the matrices and then just multiply the matrix times the vertex once. That is how most vertex shader implementations do this technique.

Also, to optimize Steve's code a little:
Pre-multiply the BoneInverseBindMatrix * BoneWorldMatrix, then you only have one vertex * matrix. Also, do this once for all your bones each frame and store it in a "matrix palette" so you don't re-multiply the matrices for each vertex.

Share this post


Link to post
Share on other sites
Hmm I can't seem to make progress on the shrinking, at the moment Ive got it making a good simulation of what happens to a straw when you bend it... but that dosn't help in simulating a human skeleton, let alone any other skeleton.

Any Tips on it, I dont like the idea of adding "sub" bones to the joints because it is already quite demanding as it is with just the regular skeleton. and I dont quite understand what you mean by Sharpening, to me that sounds like a step back to when I first started... but perhapes im not seeing it in the right light.

Quote:
Original post by raydog
"is that correct? Shouldn't you be looping weights per vertex instead?"

The number of weights = numberofbones. unless you drop bones because of lack of infulence.

Share this post


Link to post
Share on other sites
By sharpening, I just meant make the falloff sharper so that the blend isn't spread out over such a large area. This causes creasing but that is what you want for an elbow or knee.

Most artists create the mesh with this in mind and concentrate extra vertices around the joints. The arm skinning app I mentioned earlier that I did in 1998 shows this. In that app you can also see the problem when you twist the bones.

RE: "adding extra bones" You are right, it is a bit expensive and most people just don't bother. We just live with the limitations. But in the right case or for a key character it works well. I have used an extra bicep bone to have a procedural muscle bulge for instance and it looked great.

But I think you have all the tech right. From now on it is just an art and design problem. Build the model right and adjust the weights so it looks as good as possible.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Another technique that helps is to build the model at the half way of the max deflected position and weighted there. That way the error will be more evenly distributed.

Share this post


Link to post
Share on other sites

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