It’s rare I have the time to write development blog entries. Somehow, programming always feels more productive, but I figured I would start a series on our skeletal animation system. XNA, the framework we are building Party of Sin with, doesn’t provide any skeletal animation support out of the box. There are samples for getting skinned models loaded, there even exists an XNA Animation Library, but there is a big lack of information on higher level animation concepts, like blending, transitioning and layering of different animations. This series will walk you through the intricacies of our animation system in Party of Sin, in the hopes of making it easier to build your own, should you choose to.
Here is a video with the final result, slowed down to show you the smooth transitioning between animations and layering of upper and lower body.
Things will get a little bit technical, but I will try to make sense of it all. This assumes you have basic knowledge of 3D graphics and you know how vectors, matrices and vertices work. Let’s begin with some terms. This first part will be an introduction to the problem and an overview of our design.
A Glossary Skinned Model: A model which has a skeleton to which vertices are skinned. Vertices are attached to bones in the skeleton by a series of weights. When the bone moves, the vertex will move in a similar fashion. Weights allow vertices to be attached to multiple bones, for smoother deformation (for instance at your shoulder).
Quaternion: A 4-dimensional complex number which represents the orientation of a bone. For more information see this reference. All you need to know is quaternions represent orientation and they can be smoothly interpolated.
Graph: Nodes connected by edges. Graphs can be used for a lot of different things. If you’re programming, you should know for a graph is.
Problem Statement One key decision to make when programming any system in a game engine is whether you want to install a third-party component into your game, or roll your own system. The first step in making this decision is analyzing your needs. With Party of Sin, we knew our animation system needed to handle the following:
- Skeletal animation we could import from 3dsmax and Maya
- Support for layering of upper and lower body animations
- Smooth blending between animations (including walking / running)
- Game control of specific bones (aiming for instance)
- Ability to attach objects to characters (armor, weapons)
Number 1 is essential for us, since our animator Liz uses Maya and the others use Max. Number 2 would allow us to cut our animation work by many orders of magnitude, since we would only need one set of lower body animations. This also saves a ton of memory. One feature we intentionally left out was inverse kinematics. IK is an advanced feature (visible in Overgrowth here) which allows characters to plant their feet on the ground and react to changing elevation in the terrain. We considered it, but for our 2D gameplay it felt like overkill.
Looking at these 5 features, we can see we have our work cut out for us. None of this is provided by the default XNA framework, and it’s all pretty math heavy. My first instinct was to look for existing libraries which could meet our needs. A quick google search turned up the XNA Animation Component and XNAnimation. This was a good start and both provided source code, which was nice. They do the basic skeletal animation stuff we want. It’s quickly apparent though that these don’t do everything we need. There’s no way to layer upper and lower body animations in either of these (a key feature). There is rudimentary blending, but not something we could roll out to an entire game. Probably the biggest problem is integrating these libraries with our existing code. Libraries can be great, but they have hidden costs. You must learn how it works, since you didn’t build it. You have to make it coexist with your existing code and you have to figure out how to extend it if it doesn’t provide all the features you need. Ultimately I decided to roll my own animation system. This gave me unlimited control over the system and I learned quite a bit along the way.
Animation Graphs So now we know we need an animation system, and we’ve decided to write one on our own. We could begin coding right away, but this would be foolish. The first step when designing anything is RESEARCH. We know WHY we are building it and we have an idea of WHAT we need, the final step is HOW. This is a problem many games have solved before ours, how do they go about it? My prior experience with the Source Engine gave me some idea of what was involved, but it always helps to get a second perspective. What were other games doing? One particularly interesting article that turned up in my research was about MechWarrior 4. Their animation system resolves around a tree/graph structure. The leaves of this graph were individual animations, and each node performed an operation on the animations. This was the design I chose. It made a lot of sense, and could handle all our features.
What would these graphs look like? Here is what our player animation graph for Envy looks like right now. This graph has gone through many iterations and changes whenever we add new animations. Blue nodes are animations (raw frames with the model moving in time). Yellow nodes blend between multiple animations, either by composing them (combining them to form a hybrid animation) or by blending them based on speed (walk, run, idle). Purple nodes are state machines, these serve as switching points for the animation. Depending on the state of the game, the state machine will switch states and start playing a new branch of the graph. Our state machines also allow transitions (like crouch to standing), but this is not shown here. Finally there are nodes marked “On Demand”, this is where we play our various one-shot animations like Melee Attacks and Grenade Throws. On-Demand nodes play the default animation when they’re not active, or play an on-demand animation if one is queued up.
Hopefully this gives you an idea of the final system. We will be delving into each of the different nodes in more detail and looking at some code in the next instalments.