Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Cold_Steel

Skeltal Animation implementation choices

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

Okay, here''s the deal. I''ve designed my own skeletal animation model format. It''s quite simple, but it has the whole bone hierarchy thing. My problem is that I have a couple of choices on how to implement it. What I want to do is use vertex shaders to do the skinning with the bone weights, but I think I might have a problem. Currently, the way I designed it, each bone has its own mesh. The way I designed it is to have 1 vertex buffer per model, and one index buffer for each bone to index into the main vertex buffer. Each vertex per bone can have five bones total act on it. So, when I actually draw, it would go something like this: 1. set the vertex shader for all models. 2. Go to the first bone and set the five matrices as constants in the vertex shader. 3. Draw the bone mesh with the index buffer Go to the second bone, do the same thing ... With this system, I can have as many bones in a model as I want, just no bone can have more than 3 children, and 1 parent. The problem I see with this though is, say I have 10 bones per model, and 10 models on the screen. For each frame I would be switching the index buffer 100 times, and switching the vertex buffer 10 times. This seems like it could be really slow. The other way to do this would be to use on VB and one IB and set the vertex shader constant register once with all of the matrices for the model, and have the vertices index into the matrix palette. With this, I would be limited in the total number of bones because the vertex shader constant reg is not large enough to hold too many bones. What should I do? Does anybody have any suggestions on a better way to implement this? I don''t know how fast all the directX functions are, but I would think switching index buffers 100-200 times per frame would kill the frame rate. Am I right?

Share this post


Link to post
Share on other sites
Advertisement
I did my model class a bit differently. The milkshape file format (and I assume other file formats too) have the models consisting of several meshes. eg One for head, one for each leg, one for hand, etc. You could even group all of them into a single mesh. Each mesh can have a texture for itself (hence why you might want to divide your model into several meshes)

Now meshes and bones are not really related to each other at all. The only relation is that each vertex contains the index of the bone it is attached to. I don''t know what you meant by 5 bones per vertex, because really, each vertex should only need to be attached to a single bone.

During animation time, you update the bone transformation matrices. During render time go through each mesh, and for each vertex in the mesh you apply the correct transformation using the matrix of the bone that vertex is attached to. Finally, all you need to do is make a single DrawIndexedPrimitive() for each mesh (you can set the vertex/pixel shader for each mesh). So if your model uses a single texture, you can make the whole model into one mesh, and render in a single DrawIndexedPrimitive() call.

Sorry if that doesn''t answer your question at all. Notice that the above implementation requires bone related transformation of the vertices to be done on the CPU. I''ve been thinking of how to move this onto the GPU using vertex shaders. Never the less, I think you should still be making the DrawIndexedPrimitive() calls on a per-mesh basis and not per-bone.

Share this post


Link to post
Share on other sites
quote:

Now meshes and bones are not really related to each other at all. The only relation is that each vertex contains the index of the bone it is attached to. I don''t know what you meant by 5 bones per vertex, because really, each vertex should only need to be attached to a single bone.



Now this isn''t really true when you use indexed vertex blending, as described in the SDK. In this case, eg the upper arm has vertices belonging to it, the lower arm as well. In the elbow area, some vertices have weights 0.8 upper - 0.2 lower, 0.5 upper - 0.5 lower, etc. This makes them move eg. 50%, this gives you a stretchable appearance. If you have just separate meshes, you get the old-fashioned moving cylinder effect, where a hole appears on the outside and overlapping parts on the inside as soon as the arm moves.

quote:

During animation time, you update the bone transformation matrices. During render time go through each mesh, and for each vertex in the mesh you apply the correct transformation using the matrix of the bone that vertex is attached to. Finally, all you need to do is make a single DrawIndexedPrimitive() for each mesh (you can set the vertex/pixel shader for each mesh). So if your model uses a single texture, you can make the whole model into one mesh, and render in a single DrawIndexedPrimitive() call.

Sorry if that doesn''t answer your question at all. Notice that the above implementation requires bone related transformation of the vertices to be done on the CPU. I''ve been thinking of how to move this onto the GPU using vertex shaders. Never the less, I think you should still be making the DrawIndexedPrimitive() calls on a per-mesh basis and not per-bone.


This can be done in a vertex shader yes. For each vertex specify a variable (eg. an extra texture) which in reality holds weights. Eg. the upper arm has (1,0,0,0), the elbow (0.5,0.5,0.0), the lower arm (0,1,0,0), the hand (0,0,0,1), then in the vertex shader you use this to multiply the first matrix with the upper arm, the second matrix with the lower arm, etc. The elbow gets 0.5 * upper arm matrix + 0.5 * lower arm matrix, then the end result gets multiplied with the combined world/view/projection matrix to transform it into 2D.

But consult the SDK. Their D3DXSkinnedMesh class supports bones, I believe every vertex can be influenced by 4 bones max and you can have 32 bones. This should be enough for a walking human. You can render this in one go with a vertex shader.

Share this post


Link to post
Share on other sites
quote:
Original post by Poya
Now meshes and bones are not really related to each other at all. The only relation is that each vertex contains the index of the bone it is attached to. I don''t know what you meant by 5 bones per vertex, because really, each vertex should only need to be attached to a single bone.



The above only applies to the current version of Milkshape
which only supports one bone per vertex. However, most
other 3D modeling programs, Max for example, have multiple
bone weigth influences assigned to a single vertex.
Bone weights will be supported in Milkshape version 2.



_________________
Best regards,
Sherman Chin
www.Sherman3D.com

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Can anyone explain to me, why to use weighted bones ?
I see no difference, beside more calculations, to "hidden" faces
that rotate out of the model and ''round'' the edges.

nils.gramberg@gmx.de

Share this post


Link to post
Share on other sites
The reason you use indexed blending is so that when you do a rotation of a bone attached to another bone, the vertices around the join bend smoothely, and no sharp edges are produced, in theory. Without indexed blending, you get sharp edges and creases at joints. If you want to see the difference with an extreme example, look at the skinned mesh example, and then look at a game like Grand Theft Auto 3. In GTA, you can see creases at every join in the model. In don''t know how GTA does the modelling, but this is something like it would look without blending.

As for using the vertex shader, that is sort of my idea. True, you can get 32 matrices in a model with a vertex shader, but that''s it from my calculation. That means no lighting, or anything. If you use 4x3 matrices, 32 of them takes up 96 constant registers, which is all of the constant registers, I believe(at least version 1.1) I guess 20 would be more realistic. That''s only 60 slots in constant register memory, and that should leave enough for decent lighting. Actually, I should be able to model pretty decent models with only 15(45 regs). Thanks for clearing some of that stuff up for me.

I guess 200 drawIndexedPrimitive calls per frame would be completely nuts I should try it to see how bad it really is, though it must absolutely kill performance I would imagine, considering one article I read said they made a good optimization by remove one drawIndexedPrimitive call

Share this post


Link to post
Share on other sites
Thanks for clearing that up guys. I really have to look into this multiple weight bone thing. Fidelio_ : What you said about overlapps/holes in the model when animating, is not neccessarily true. Connectivity of the meshes even after animation is preserved by attaching two overlapping vertices of two meshes to the same bone. I can import all Half-life models into my game without any animation issues.

But I can understand what you and Cold_Steel are saying about stretched polys (which will look sharp) around the joints. I would assume this would especially look noticable if you have a low number of vertices around the joints.

I will look into this more, but I''m still inclined to think the animation part and rendering should not inter-relate, ie once the vertices are transformed to their final position we can just call DrawIndexedPrimitive() once per mesh. Using vertex shaders will complicate this though.

Thanks again,
Poya

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!