4
votes

I'm lost with skeletal animation. I've read some things about this, but their is still one thing I don't understand. This is conclusions I have. I saw 3 ways to animate a mesh with bones :

  • I have a Mesh class that contains vertices, vertex buffer, index buffer and texture Shader, and transform matrix. I could use class for each bone, add weight and it could me easy to animate the model. But that means use too much memory because some things stored are used some time when they have to be only once.

  • Use vertex shader. Add weight and bone index in the input vertex parameter, and use a matrix array as a global variable, so in the shader I just have to use the matrix of the bone. This solution seems more efficient for me, but I remember that on the directx 11 tutorial ( from Rastertek ) he said that HLSL should be fast because its used a lot of time, and I think this would be too heavy. Anyway this is the solution I'll try, at least to know if that works or not.

  • Use matrix and inverse matrix for each bones. As far as a read, this is the way to take. But this is the way I didn't understand. Why are matrix inverse used here, and how matrices are "linked" to vertices. I mean if I move the matrix for the right hand bone, what said in the code that only right hand vertices will be used?

So my questions are :

  • Is the second way viable? or it will be too much for the GPU with some mesh and animations?
  • Can someone explain the way matrices are linked to vertices and why are matrix inverse used? Or link me something about this.

I hope you did understand me, because I'm not sure i explained well. And please excuse my english, I did as good as I could. Thanks in advance.

1

1 Answers

8
votes

The first approach can work if there are only rigid parts in the model. As soon as there are deformable parts you get holes or other artifacts. E.g. if you have a model of an arm and you rotate the forearm, there will be a hole at the elbow and overlapping triangles at the crook.

For the second approach - well, I don't really know how you intend to do this. The pixel shader is definitely the wrong place to do it. Everything that needs to be done can be done in the vertex shader.

Which leads us to approach 3.

I admit that skeleton based animations are a bit tricky to understand. Let's consider the above example: a model of an arm, consisting of upper arm and forearm. For this model we need two bones: One from shoulder to elbow and one from elbow to the hand.

Each vertex should be linked to at least one bone. This is done with vertex weights. Let's assume that there are some shoulder vertices that are influenced by the shoulder only. The elbow vertices are influenced by both bones and the hand vertices are influenced by the forearm bone only. That yields the following weights:

bone:               | upper arm bone | forearm bone
--------------------+----------------+--------------
shoulder vertices:  |       1        |       0
elbow vertices:     |       0.5      |       0.5
hand vertices:      |       0        |       1

The first thing to do is to calculate the position and orientation of all bones. This is done with a matrix for each bone. Usually an animator is responsible for calculating these matrices. This matrix would place a bone from some reference position to its current position. The reference position is the same for all bones and can be chosen freely.

The next thing to do is to calculate the resulting vertex positions. We know that the vertices move together with their bones. Therefore, we need the vertex positions in a local coordinate system of the bone. However, usually the vertex positions are given in world coordinates in the bind pose. That's what the inverse matrix is for. It transforms vertices from world space (bind pose) to a bone's local space. There is one inverse matrix for each bone.

When we have the vertex in the bone's local system we have to transform them according to the bone's movement. For shoulder vertices and hand vertices this task is trivial. We can use the bone's matrices and multiply those to the inverse matrices.

For the elbow vertices this is not that easy. In fact there are a variety of methods to calculate the transformation. We need to blend the two bones' transformations with the given weights. The easiest way to do this is to multiply the matrices by their weights and add them together. This gives the final transformation that can be used to transform the vertex position.

The steps are (for one influencing bone only):

  1. Transform the vertex position from bind pose to local bone system.
  2. Calculate the bone transformation matrix with the animator.
  3. Transform the vertex position from local bone system to animated position with the bone matrix.

If there is more than one influencing bone, the matrices have to be blended. The link of bones and vertices is achieved with vertex weights. Usually, a vertex does not save weights for all bones. Instead the maximum number of influencing bones is restricted to e.g. 4. Then the vertex stores the indices of the first 4 most influencing bones and their weights.