Skeletal animation

The skeletal animation system provided by REDsdk gives access to multiple interfaces that allow to animate a character in real-time. It gives the ability to build complex animation trees and dynamically animate any part of a skeleton.

The base interface of all the skeletal animation objects is RED::ISkeletalAnimationController. This class has many purposes:

According to the parameter set, the animations will be evaluated at each application frame by calling the RED::ISkeletalAnimationController::Update method. This function updates the animation handled by the controller and then move the skinned meshes skeletons according to it.

The skeletal animation system exposes two main objects to the user. Both of them implement the RED::ISkeletalAnimationController interface:

More details about these two objects can be found later in this chapter.

Skeletal animation system objects and interfaces

Link to the skinned mesh

Because the goal of the skeletal animation system is to animate a skeleton, it needs a skeleton to animate. In REDsdk, the skeleton definition is contained in a RED::IMeshShape object (details about skinned mesh shapes can be read here: Skinned mesh shapes).

The RED::ISkeletalAnimationController::AddSkinnedMesh associates the skinned mesh we want to animate to the animation controller. Each skeletal animation controller must be linked to at least one skinned mesh.

Note:

Because a controller animates a single skeleton, all the skinned meshes associated to it must have the same skeleton.

The RED::ISkeletalAnimationController::SetIsAppliedToSkeleton option allows to specify if the result of the animation evaluation must be applied to the associated skinned meshes or not. If not, the user can query the result for each bone with the RED::ISkeletalAnimationController::GetBoneTransform function.

Bone filtering

The RED::ISkeletalAnimationController interface provides functions to filter the bones. Sometimes, you don't want to animate the full skeleton. The bone filtering option allows to select the bone hierarchy to animate via one function: RED::ISkeletalAnimationController::SetBoneFilter.

The function lets the user choose the bone or bone hierarchy he wants to filter in or filter out.

task

Task: Filtering skeleton bones

In this task, we want to split the animation of a humanoid skeleton between two controllers: one for the upper body and one for the lower body.

Below is the skeleton we want to animate:

The skeleton and bone indices

For each controller, we will use the RED::ISkeletalAnimationController::SetBoneFilter to filter-in and filter-out the desired bones.

// RED::Object* lowerController and upperController are skeletal animation clip controllers controlling the same skeleton.
RED::ISkeletalAnimationController* ilowerController = lowerController->As< RED::ISkeletalAnimationController >();
RED::ISkeletalAnimationController* iupperController = upperController->As< RED::ISkeletalAnimationController >();

// By default, bones are unfiltered. Just filter-out the upper body.
RC_TEST( ilowerController->SetBoneFilter( 1, true, true ) );

// Filter-out all the skeleton then filter-in the upper body.
RC_TEST( iupperController->SetBoneFilter( 0, true, true ) );
RC_TEST( iupperController->SetBoneFilter( 1, false, false ) );

In the lower body controller, we have excluded the bone hierarchy from bone 1.
In the upper body controller, we first excluded all the bones then included the bone hierarchy from bone 1.

For upper body, we could also have excluded bone 0 only, then leg bones and their hierarchies:

// The lower body filtering could be done also:
RC_TEST( iupperController->SetBoneFilter( 0, true, false ) );
RC_TEST( iupperController->SetBoneFilter( 8, true, true ) );
RC_TEST( iupperController->SetBoneFilter( 11, true, true ) );

The skeletal animation clip controller

The skeletal animation clip controller is the link between the animation clip controller seen here: Basic animation and the skeletal system. Because it implements the RED::IAnimationClipController interface, it has all the clip-related functions like play, pause, stop, etc.. Added to this are the skeletal system options: associated mesh, bone filtering, root motion, etc..

User can access to each functionalities by requesting one or the other of the interfaces: RED::ISkeletalAnimationController or RED::IAnimationClipController.

The skeletal animation clip controller is created by the factory with the RED::Factory::CreateSkeletalAnimationClipController function and deleted with RED::Factory::DeleteInstance.

task

Task: Creating a skeletal animation clip controller

A skeletal animation clip controller is an object merging the animation clip controller properties to the skeletal animation system. It allows to play skeletal animation clips and apply the result to a skeleton. It is created using the RED::Factory.

// Create a skeletal animation clip controller to control a RED::AnimationClip.
RED_RC rc;
RED::Object* animController = RED::Factory::CreateSkeletalAnimationClipController( *resmgr, clip, rc );
RC_TEST( rc );

// It implements both interfaces.
RED::IAnimationClipController* iclipController = animController->As< RED::IAnimationClipController >();
RED::ISkeletalAnimationController* iskeletalController = animController->As< RED::ISkeletalAnimationController >();

The destruction of the animation controller is done like this:

// Delete the skeletal animation clip controller.
RC_TEST( RED::Factory::DeleteInstance( animController, iresmgr->GetState() ) );

The skeletal animation blender

The skeletal animation blender is the object that allows to build complex animation blend trees. Its goal is to mix several skeletal animation controllers together to produce smooth transitions between them or to merge partial skeletal animations. More details are available here: Blending skeletal animations together.

Root motion

Some animations move the skeleton in space. If the animation have to loop, the skinned mesh will jump from its last position to its first position. This is a problem if we want it to move in a continuous way in the scene.

The root motion policies are here to solve it. It exists several options to move the root bone of an animated skeleton in the scene. They can be configured thanks to the RED::ISkeletalAnimationController::SetRootMotionPolicy function.

Root bone components

Each of the skeleton root bone transformation components (RED::ROOT_MOTION_COMPONENT) can be configured individually: rotation and translations:

Splitting them allows for example to let the animation handles its rotation correctly and extract the translations to move the skeleton in the world.

Root motion policies

The policies (RED::ROOT_MOTION_POLICY) are defined like this:

The RED::RMP_DEFAULT policy is the default one: the root bone is applied like any other bone leading to the issue we described previously.

The RED::RMP_CUMULATIVE policy calculates the delta transform between each frame and cumulates it in the root bone transform. By setting this policy, we fix the issue of the position reset because translation is no more absolute but relative to the last frame.

The RED::RMP_ZERO policy sets the root bone components to zero, meaning we suppress the rotation and/or position components from the root bone.

Finally, the RED::RMP_DELTA policy applies only the delta transform between each frame to the root bone. Alone, this option is not very useful. It must be associated to the last extraction parameter.

Extraction parameter

Sometimes, it can be preferable not to move the skeleton root bone but another mesh parent shape. For instance because other objects are attached to the mesh. The 'extract' parameter of the RED::ISkeletalAnimationController::SetRootMotionPolicy function allows to do that.

If a component is defined as 'extract', its value will not be set to the skeleton root bone directly. Instead the user will be able to retrieve it via the RED::ISkeletalAnimationController::GetRootMotionMatrix function. It will then be free to apply it on the REDsdk object he wants. This is where the RED::RMP_DELTA policy become useful.

task

Task: Defining root motion policies for a walking character

In this task, let's take an example of root motion policies for a biped character walking on a ground:

// RED::Object* animController is a skeletal animation clip controller.
RED::ISkeletalAnimationController* iskeletalController = animController->As< RED::ISkeletalAnimationController >();

// Rotation is handled by the animation.
RC_TEST( iskeletalController->SetRootMotionPolicy( RED::RMC_ROTATION, RED::RMP_DEFAULT, false ) );

// Translations on X and Y axes are handled by the animation by applied on an external shape.
RC_TEST( iskeletalController->SetRootMotionPolicy( RED::RMC_POSITION_X, RED::RMP_DELTA, true ) );
RC_TEST( iskeletalController->SetRootMotionPolicy( RED::RMC_POSITION_Y, RED::RMP_DELTA, true ) );

// Translation on Z axis is handled externally.
RC_TEST( iskeletalController->SetRootMotionPolicy( RED::RMC_POSITION_Z, RED::RMP_ZERO, false ) );