3D Engine – Animation Basics

I guess by now, some of you are getting a bit impatient to see some actual code put together for this, and it is almost time to get down with the practical side of things, but before we do, there’s ome more thing we need to look into: animation. So far, we’ve got models and lights which can be moved around, and in a way that’s all we need for making simple animations through code. However, we have no means of animating characters within a 3D modelling package and have them played back in the engine. This is where morphs and skinning comes into play.

renderer_morphs

Morphs is a quite straightforward concept: you take a mesh, move its vertices around in the modelling package (without removing or adding any vertices), deforming it into the desired shape. You then compare the new mesh with the original one, and for each vertex you calculate a delta value, which is the difference between the old and the new vertex positions. In the engine, you can apply the morph by adding each delta to its vertex, to deform the mesh on the fly. By scaling each delta as it is applied, you can smoothly transition from the original mesh to the deformed shape.

This technique is especially useful for animating character expressions, as pictured above. We could do other animations this way too, like maybe the walk cycle of the character, by saving each keyframe of the animation as a set of morph deltas. However, morph deltas require a lot of memory – we’re basically duplicating the mesh for each keyframe of animation, and there’s no way to reuse animations between different characters.

renderer_skinning

That’s why we’ll use skinning. The concept of skinning is a bit more complex than morphs, but the advantages makes them worth it in a lot of cases. Basically, what we do is build a "skeleton" (a series of connected bones) for the model (the black lines forming long triangular shapes in the arm at the top of the image above). Once we’ve created the skeleton, we bind all the vertices of the model to different bones. Most vertices are only bound to one bone, but some vertices, near the joints, are connected to more than one bones, and usually we use different weighting values for how much influence each of the bones have on the vertex. This might sound a bit complicated, but it’s all set up in the modelling package, and it’s actually quite straightforward. The important bit for us right now, is that when using skinning, we get a hierarchy of bones, information about which vertices are bound to which bone,  and weighting values for those vertices that are bound to multiple bones.

When we have this information, we can easily animate the hierarchy of bones, the skeleton, by simply rotating bones relative to their parent bones. In the above image, you can see an example of bending the arm at the elbow, by simply rotating the forearm bone. as you can see, we get a smooth deformation of the elbow, as those vertices are bound to both adjacent bones. Animation data for the hierarchy of bones is tiny – simply a rotational value for each bone, making it quite memory-efficient to store a lot of animations, at the cost of calculating the vertex positions in the engine. Using morphs on the other hand, takes a lot of memory, but is faster to apply.

In my indie engine, I’ll support both morphs and skinning, as I believe they are both very useful concepts, as well as quite simple to implement. As with all the other components of the engine, I’ll make a clear distinction between instances and definitions, and next time I will go into more detail about how morphs and skinned animations will be implemented in my engine.

Leave a Reply

You must be logged in to post a comment.