Skip to main content
GameDev.net gamedev.net
🔒 Locked

Problems with skinning

Started by simpeman Dec 6, 2005 at 7:19 AM 12 replies 1.4k views
Original Post
simpeman
simpeman
Hi! I'm trying to handle skinned models with joints in my current application. However, I seem to fail to grasp how the position updates to vertices are done based on their weights and the joints they are based upon. I've also tried searching for a good tutorial or article to explain this, though none of those I've found actually gives me a good description of this. It's always some uncommented code-example or similiar that takes hours and hours to figure out and still seem to fail. What I do (which seems to fail) is: I iterate through all my skinclusters, where I iterate through each indice, where an indice is basically a 3-integer where each integer represents a vertice in a list. Each indice describes one triangle. Each vertice contains up to 4 influences. Where each influence is a weight and an integer that points to a joint in a list. So what I do each update is that a vertice's position is: first calculate the position of the vertice multiplied by the world-matrix for each joint that influences that vertice, named P. I then multiply P by its weight. I then take the position of the vertice, and updates it to the current position multiplied by P, for each joint. for each joint influencing vert with world matrix W and weight w: P = vert.pos * W; P = P * w; vert.pos *= P; Though this doesn't seem to work. All help is greatly appriciated. Edit: I thought I might add that some of my vertices gets undefined position values (which in opengl is drawn as 0, 0, 0) Best regard, Simon. [Edited by - simpeman on December 6, 2005 7:53:45 AM]
TomBlind
TomBlind
Hi,

Are you factoring in the bind position of the joints? It doesn't sound like it. If your skin is warping outwards in weird ways, there is a good chance that you need to remove the joints' initial transformation from their current world transformation, before multiplying the vert by them.

Also, you didn't mention if you were summing up the weighted vert positions.
simpeman
simpeman
Well, it's all in bind-pose I just want it to show up correctly. Though I'm not removing the joints bind-pose position from their current position, no. I guess that's a part of the problem. I'm also writing a maya-exporter which I'm having a few difficulties to see if I really export all correctly. I mean, I can get the model and draw it up as it looks like in maya. And I can draw the bones correctly so I'm hoping that the only problem has to do with the skinning info, which I'm not sure if I'm exporting properly.

Yeah, I'm summoning up the weighted vert positions.

I'm wondering though, is there any place where I can get a good article or how-to about skinning? The algorithms needed, information needed etc. I know there are a few different methods out there but isn't there one method that's sort of common? Anyway, if there's anyone that knows where there is anything similiar, I would be really grateful.

And thanks for the answer TomBlind :)

Best regards,
Simon.
TomBlind
TomBlind
Hmmm... To be honest, I've never really seen a good article on skinning. I think it's one of those guarded secrets or something. But anyway, if you've got the mesh and skeleton rendering correctly, you're probably pretty close. Here's what I do:

1.) Multiply the joint's current transformation (world space) by the inverse of the joint's bind transformation (world space). This removes the bind.

2.) Transform the vert by the resulting matrix from #1. If you were only using 1 influence, you would be done here.

3.) Scale the result from #2 by the weight of that vert on that joint.

4.) Repeat for each joint weighted to the vert. Sum the weighted verts together to get the final vert position.

I hope this is helpful!

simpeman
simpeman
Hi again Tom :)

And thanks for the answer!

I've now tried what you said, to inverse the bindpose position for all joints and multiply the current joint position for each joint position when I calculate the new position for each vertice. However I'm uncertain wether I should use the bindpose position for the vertice or their last position? Anyway, as it looks like now I get the original skin at the first frame and then it all just goes away. However I haven't debugged this to see what actually happens, though I will do that as soon as I get the time.

Edit:

After some debugging, it seems as if I get very big negative Z values. (really too big) though the other values for the position seems to be correct. Could this be due to me thinking in rows major instead of column major somewhere? I know for a fact that the matrix multiplication is done column major so that should be correct. However I'm uncertain about how to calculate the inverse of a matrix such as this. But I thought that the matrixes in opengl are orthonormal base and such the inverse is equal to the transpose of a matrix? Which is pretty much turning a column major matrix into a rows major matrix isn't it?

Any help is greatly appriciated.

Once again, thanks for helping out :)

Best regards,
Simon.

[Edited by - simpeman on December 8, 2005 4:56:03 PM]
Trienco
Trienco
Careful there. The transposed of the _rotational_ part is the inverse of _rotational_ part, if it's orthonormal, if your matrices include the translation you can't just transpose the whole thing. You would have to transform the translation/position part with the transposed rotation part as well.

I'm also confused about how you update your vertices, as you were talking about indices. I hope you don't step through all indices, and pick the vertices from that or you will end up transforming a lot of vertices multiple times.

Also, a basic thing to consider is what your vertices look like before you do anything to them. I assume they already are in their bind pose, if only their z is looking wrong. But keep in mind that for the bind pose you are pretty much replacing all bones with identity matrices which isn't all that exciting. But at least it's easier to check for errors, if any bone is NOT the identity when you apply the transformation then something is wrong.

Think of what you are doing as subtracting the bind pose from the current pose to get the difference. As all your vertices seem to come in their bind pose this difference is what you want. So obviously you always apply it to the original set of vertices.

optional bla bla and ramblings ahead:

Alternatively (though this might get messy) you could always use the inverse of the last bone matrix to get the difference between this and the last frame. This would then be applied to the current vertex data.

The benefit of that would be that storing your animations will likely require less space, as at some point most joints will be different from their bind pose (seeing how the bind pose isn't exactly natural). By storing only the difference between the animation "frames" you would be doing what video compression does. The downside is that by only storing differences you could never "reset" the model or force it into a pose, especially if you want to apply "on the fly" changes (ragdoll physics or whatever) that would be ugly to combine with prepared animations. Unless you do what videos do and store are a "complete" keyframe with absolute (or relative to bind pose) matrices.

But before you start doing clever things to optimize away, I would store the inverse of the bind pose for each bone, it's position/orientation relative to its parent and the resulting absolute data. After applying all local changes (to the relative to parent data) you traverse the skeleton, calculate the absolute data based on the parent and then do a second pass applying the inverse to the absolute data to get what you want to transform the vertices with.
f@dzhttp://festini.device-zero.de
TomBlind
TomBlind
I'd be willing to bet the inverse is your problem. Like Trienco said, orthonormal matrices can be inverted with a transpose, but only the rotational part. If you are not doing any scaling (which I doubt you would need to) you want to:

1.) Store the position part of the matrix.
2.) Zero out the position in the matrix.
3.) Transpose to invert the rotation,
4.) Subtract the stored position from the position in the transposed matrix.
Trienco
Trienco
I don't think simply subtracting will work. Unless I'm completely wasting time on three dot products between the three axes and the negated position. Unless of course you meant "multiply a matrix with the negated translation to the result".
f@dzhttp://festini.device-zero.de
Stevieboy
Stevieboy
Hi, this is for xfiles, on Frank Lunas site, but the explanations also quite good, some of the links will open pdf files which you can save.

http://www.moon-labs.com/ml_resources.htm
TomBlind
TomBlind
You're probably right, Trienco. Transforming by a negated translation matrix would be the proper way of doing it. Just subtracting does work, the way I have implented it. I should look into why that is...
simpeman
simpeman
Thanks for all the responses! They're helping out :) I'm having problems with getting my mathematical classes working, and it's a very very weird compiler problem. I'm getting syntax errors (in a header file) in a library that I've already compiled. And the only thing I'm including in that header file is windows.h, glu.h, ostream and cmath.

But once again, thanks for all the responses! You guys are great!
simpeman
simpeman
Ah wow, finally it works somehow.

Edit:
At this moment, the model is standing and "vibrating", in other words, rotating a little bit around x, then jumping back in a very high speed. I'm not sure what's happening. Also, I'm not sure how but the joints are somehow "multiplied" when I rotate them. It's very weird and I'm not sure what on earth I'm doing to make this happen. When the rotated joints approaches alignment with Y, two sets of joints appear close to each others, and then one of them goes away. It's always the "new" set of joints that stays. I did not code anything like this, and still it happens :P

Thanks for all the help guys, I'll probably solve this eventually.

Simon.

[Edited by - simpeman on December 14, 2005 6:19:06 AM]
TomBlind
TomBlind
Are you somehow doing cross-products to build your matrices using the world y-axis? That would cause the issue when joints become aligned with it. You shouldn't have to do that, depending on how you store your key-frames.
simpeman
simpeman
Actually I haven't done any "real" animation yet. I've just rotated the joints myself. However there seems to be one problem, one part of my model becomes inverted. But only a part of it. And it seems as if it doesn't bind to the joint but instead they're drawn to 0/0/0. It's probably some error with my code though, so I'll solve it eventually. Though now everything seems to work, and the error with the weirdness earlier was that I was multiplying my Quaternions wrong. Though it seems as if it's all up and running now :)

Well, except the fact that my joints are mirrored to my model, instead of following them :P

Thanks for all the help!

Simon.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.