Gillius's Programming

Computer Graphics - Algorithms and Techniques

Mid-Quarter Update
Skeletal Animation Project

Changes to Project Scope

More research has slightly changed the project scope from the proposal document, as well as differing requirements for the 3D game project. The main requirement change is that I wanted the animation system to affect only portions of the skeleton, so that I can control the parts separately, making the task for the animator much simpler, and animation quality better. Mainly I will be splitting the animations up around the waist of the character, so that the top part of his body and bottom part do separate things.

For example consider a character who can stand, walk, and attack (swing sword). There are then 4 possibilities for animation, standing, walking, stand and attack, walk and attack. Without allowing for "blended animation" the animator would have to animate all 4 cases, and even then the results cannot be perfect because the character can start swinging at any time during the walk cycle.

By creating a system allowing for blended animations, the animator chooses branches of the skeleton to animate sections for at a time. For human characters, the animator would choose to split the player model at the waist. Then the animator would animate 4 parts of animation: the legs standing still, the legs walking, torso with arms swinging, torso with swinging sword. While still 4 animations exist, keep in mind the animator is only animating half of the body in each animation, and overall work is less. In code, the two parts of the skeleton would be treated separately. The code system will be generically defined to split the model into 1 or more parts, but the typical use will be to split at the waist. This requires the animator to name his joints, and then provide the information needed in an accompanying file. The X file format I am using allows all of the meshes, joints, and animations to be named, and I will use this information for two purposes. The first since the modeler gives names of the joints to split the animation, and second as meta data so code can address bones by name, and provide meaningful bone names to the user for interactive control.

The second change to the original proposal is that I will not be implementing an IK system. It will be too complicated for me to implement within the given timeframe. I do still hope to implement the head tracking, since that involves the control of only 1 joint (neck joint).

Technical Implementation

So far I have not written any code for the project, but I have done a great deal of research into the topic, enough to be able to come up with a design. Through studying of examples I have found on the internet, I believe I am now ready to start writing the actual code. This UML diagram shows the design that I propose. Some methods like trivial get methods are not shown, and loader methods are not shown for clairity reasons, but the main methods are listed. Detailed discussion follows the diagram.

Classes

ResourceRepository

This class will be used to manage the memory of the resources in the program. For the skeletal animation project solely as it is for the CG project, this class is not needed, but in the context of the 3D game engine, it is used to manage resources. It is responsible for the allocation, loading, and deallocation of key program resources. Placing the resource management in this central location will help to stop memory leak errors and also help to split out some nastier loading code from game logic (for example I'd rather not have AbstractModel have to worry about application paths and file system, etc). Having a ResourceRepository also allows for easy transition to loading from data archives if desired someday. This class currently does not exist, but its code already exists in parts of other classes (thus this class will be a result as of refactoring in the 3D game project).

AbstractModel

When the skeletal animation is merged with the game code, this class will provide a common interface to the different models and implement shared functionality between StaticModel and SkinnedModel. In the CG3-specific project implementation, this class may not exist.

StaticModel

This is the pre-existing static model class I developed for the 3D game engine I am working on for Phelps's class. I used it in my other CG assignments, but it will not appear in the CG project.

SkinnedModel

This is the root of the core work that I am doing specific to the CG3 project -- this class, its children, and the classes they use. The SkinnedModel class is a model that is defined by a mesh attached to a skeleton. By itself it neither contains nor implements any animation, but the Skeleton can be addressed directly to modify the skeleton, and the mesh will be rendered using the changes made to the Skeleton.

Skeleton

A Skeleton is a collection on Bone objects. Bones can be addressed by name, or by an index (as in an array). Other than acting as a linear container for bones, the Skeleton has no functionality. The Skeleon class is responsible for the memory of the bones. The usefulness of the Skeleton comes from the fact that you can get a sequential list of bones, or get the "root" bone and traverse the tree. When rendering the mesh or generating a list of bones, the linear access is well-suited, when applying/calculating transforms, tree traversal is well-suited.

Bone

The Bone class is a node in the skeleton tree. An alternate name for the Bone class could be Joint, as these terms are interchangeable as defined in this project. The tree formed by the Bone objects is a n-size tree. Each Bone has 0 or more children, and a parent. These links can be traversed publically. Bones act as containers for the transformation data, but do no other significant work. Each Bone has 3 matrices: a Bone offset matrix, a "reference pose" for the bone, and the current (post-transform) matrix.

AnimatedModel

The AnimatedModel class extends the functionality of the SkinnedModel class to include animations on the skeleton. It is important to note that from the perspective of the program, it is the skeleton that is being animated, and not the skin or mesh. The SkinnedModel simple renders around the skeleton. Thus the AnimatedModel focuses on tying sets of animation to groups of joints in the Skeleton alone, and through the fact the skeleton is moving, the functionality in the SkinnedModel will not need to "know" about animation.

The animations for a model are split up into sets of animations. Each AnimationSet cooresponds to a logical section of the model. For example if a humanoid character was split at the waist, the two animation sets would be "torso animations" and "leg animations." There is no limit on the number of splits on a model (except that an animation set must contain at least one joint). The number of active animations in an AnimatedModel is at most equal to the number of sets it contains, since each AnimatedSet has a currently active animation. In the previous example, the humanoid character would have at most two active animations, one for the legs and one for the torso, that both operate independently.

AnimationSet

The AnimationSet contains a set of SkeletalAnimation objects. It also contains a looping flag (set if the animation is to loop), the current time offset into the animation, and the currently active animation. It also takes update events and passes them to the active animation, which will modify the matrices of the bones to which it is attached. An exmaple of an AnimationSet would be a set of atomic animations for legs, walking, running, and standing.

SkeletalAnimation

The SkeletalAnimation represents a atomic animation component. It contains a list of BoneInterpolator objects under a common name and an animation length. An example of a single SkeletalAnimation would be a walk cycle.

BoneInterpolator

The BoneInterpolator does the real work of joint keyframing. Each BoneInterpolator object references a single Bone (or joint), and all of the keyframes for a single animation. The functionality of this class is limited to simply calculating the position of a single bone given a time value.

The Keyframe class is defined as part of BoneInterpolator, and thus is a private component under BoneInterpolator.