Skeletal Animation in 2D (Part 2: Construction)

Okay so here’s an update on my implementation on skeletal animation in 2D… Basically… it works! :D

Above are some screenshots showing skeletal animation working hand in hand with the scenegraph I programmed for Project Warpy. These are some of the first development screenshots I’ve actually posted and although I’m not supposed to reveal game-play, I should be able to release screenshots as long as they do not reveal game-play (such as these).

Okay so first things first, how does the skeletal animation actually work:

  1. Create skeletal animation in maya
  2. Export to .X format
  3. Parse .X format with XNA’s X importer
  4. Custom processor to serialize bones and animations
  5. Parse bone transformations and convert to scenegraph
  6. Animation controller updates the bone nodes
  7. Interpolate between keyframes
  8. Attach sprites to bone nodes

Voila! This technique closely mimicks rigid binding and requires some knowledge of matrices and hierarchical transformation.

So before you can get any bone animation working in 2D you’ll need some kind of hierarchical system (in my case, a scenegraph). I create “nodes” that contain position, scale and rotation and use the following formula to obtain a transformation (in world space).

transform = Matrix.Identity;
transform *= Matrix.CreateScale(new Vector3(scale.X, scale.Y, 1));
transform *= Matrix.CreateRotationZ(rotation);
transform *= Matrix.CreateTranslation(new Vector3(position.X, position.Y, 0));
transform *= parent.transform;

transform represents the transformation matrix of the current node in world space. It is created by multiplying the local scale, rotation and translation followed by its parent’s transformation. This is done down the hierarchical chain (with parent first multiplying its transformation, followed by its children) just prior to rendering. The result is nodes that translate, scale and rotates according to its parent’s transformation, in layman terms, when the parent moves the child node moves in accordance.

Because bones are usually stored with transformations relative to its parent bone its easy to adapt it to such a system and therefore the only thing I do in the model processor is read in bones and animations and decompose the matrix into translation, rotation and scale (as used later in the application described above).

// process the bindpose matrices..
for (int i = 0; i < bindPose.Count; i ++ )
{
    Vector3 trans, scal;
    Quaternion rot;

    bindPose[i].Decompose(out scal, out rot, out trans);

    float rs = (float)Math.Sqrt(rot.X * rot.X + rot.Y * rot.Y + rot.Z * rot.Z);

    // make sure we dont get a divisable by 0 error.
    if (rs == 0)
        rs = 1;

    float z = rot.Z / rs;
    float angle = 2.0f * (float)Math.Acos((double)rot.W) * z;

    this.bindPose.Add(new Transform(new Vector2(trans.X, trans.Y), new Vector2(scal.X, scal.Y), angle));
}

I also store a list of parents for each bone, so I know how to parent them after they are loaded:

IList<BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton);

foreach (BoneContent bone in bones)
    hierarchy.Add(bones.IndexOf(bone.Parent as BoneContent));

Once these values are stored the skeleton simply has to be reconstructed using the nodes in the scenegraph.

// contains a list of attached joints.
joints = new List<SkeletonJoint>();

// constructs the bones straight away!
for (int i = 0; i < data.bindPose.Count; i++)
{
    SkeletonJoint joint = new SkeletonJoint();
    joint.position = data.bindPose[i].translation;
    joint.rotation = data.bindPose[i].rotation;
    joint.scale = data.bindPose[i].scale;
    joints.Add(joint);
}

// go through that list again to parent joints..
for (int i = 0; i < data.hierarchy.Count; i++)
{
    // check if this is the root joint..
    if (data.hierarchy[i] == -1)
    {
        addChild(joints[i]);
    }
    else
        joints[data.hierarchy[i]].addChild(joints[i]);
}

Now that the skeleton is built (in your scenegraph), the only thing left to do is animation! I will be releasing an article describing keyframe animation and interpolation in part 3 of the article. Hope you enjoyed reading this.

p.s. This article has been left intentionally vague, sorry for not publishing complete code samples but there shouldn’t be a problem implementing this if you get the theory! :P

1 Response to “Skeletal Animation in 2D (Part 2: Construction)”


Leave a Reply