
Crafting immersive experiences that bridge players and game worlds.
Gameplay and Engine programmer
Animation Toolkit
"Real-time Animation toolkit with blending, root motion control, interruption, events, and layering" is my thesis topic. Based on FBX Importing and 3D model rendering, the thesis is aiming for creating a robust animation toolkit that integrates most commonly used 3D animation techniques.
The final outcome of this project is a playable 3D third person combat game with additional gameplay system.
Why animation?
My enthusiasm in 3D animation didn't come from nowhere. Action game has always been one of my favorite game themes, capitivated by the expressiveness of the character movement. It is the animation that bring the characters to life, making their every attack, dodge, and reaction feel impactful and realistic. This led me to choose 3D animation as my thesis topic as I want to explore more about this game system that accompanied my for years and fulfill my goal to create an action game all by myself.
3D Model Rendering:
Characters are designed in a unreal engine-like structure where they derive from the Actor class, each owns a skeletal mesh component which holds a skeletal mesh reference, and each skeletal mesh owns all the joints and is responsible for updating the joints each frame according to on going animations, could be one or more.

Model Constant:
Character, as an Actor, exists in the world with a world transformation, which is the actor world transform matrix; skeletal mesh component decides the relative transformation of the skeletal mesh relative to the character root. Production of these two matrices is the model constant, which determines where the character mesh will be rendered and presented in the game world. Joints, on the other hand, determine how the skeletal mesh itself will be rendered.
Joint Constant:
Joints, on the other hand, determine how the skeletal mesh itself will be rendered. In short, every frame skeletal mesh updates all its joints' global transformation (by global means those matrices are relative to the skeletal mesh instead of to parent joint), and passes those data into shader to update the vertices.



Quaternions:
In order to implement animation blending and other animation techniques, an upgrade from Euler Angle to quaternions is necessary. Quaternions is relatively expensive on calculation but is very accurate for 3D rotation and interpolation and free from gimbal lock issues.
NLERP and SLERP:
When rotating an object with Euler Angles, or to say combining multiple rotations in Euler Angles, the total effect is a sum of all the rotations. And when interpolating, value on each axis is interpolated separately and linearly, which does not consider the 3D rotation as a whole and may result in a non-smooth movement.
Quaternions, however, is able to handle the 3D rotation and interpolation so that the rotation goes smoothly and evenly following the shortest arc path on a spherical surface.

Animation Update:
Animation controller:
Owned by Character.
Animation Controller makes decisions about which animation should be played and passes that decision to state machine for update. Player input or AI changes or maintains the “state” of the character every frame, and animation controller receive those states and pick the pre-determined animations to play.


Animation state machine:
Owned by animation controller.
Animation State machine is where animation updates take place. Animation State Machine itself does not make decisions on what animation to play, but it controls the animations that are currently playing (and previously played animation for blending). Every frame Animation State machine updates the timer for each available animation and transits them if necessary.
Animation Blending:
Animation blending is the process of smoothly transitioning between two or more animations, combining their movements to create a more smooth and natural result.
The Animation State machine keeps an eye on all the animations that are been played, including those that are recently transited to other animations. We are intentionally memorizing those old animations for what we are interpolating from. For both current animation and previous animation, we want to check on the timer for each and determine the exact frame we are at. It will not be an integer value, so we are going to first interpolate between two adjacent frames on the same animation based on time.

In the figure above we are interpolating frame 21 and frame 22 first, on current animation with a factor of whatever portion timer has traveled from frame 21 to frame 22. That should give us the most accurate pose from current animation. Then we do the same for the previous animation. Now we are interpolating the previous animation pose and the current animation pose. When we transit animation, we give it a duration for how long the transition lasts. Therefore, the interpolation factor gradually rises from zero to one based on how much time elapsed since transition started.

Animation Interruption:
Animation interruption is very similar to animation blending. It still needs to transit to the next animation, the only difference is after transitting, animation state machine no longer advance the animation timer on the previous animation as it's considered "interrupted". Transition duration can still be customized depending on use case whether an abrupt stop or a smooth transition is favored.
Animation Layering:
Animation Layering is a process of combining multiple animations to play at the same time and having each affecting different parts of an actor.

In this case, drinking is taking over the upper body of the character while walking is taking over the lower body. When updating, we need to know on the skeleton hierarchy where should each animation start controlling so all the entire sub tree on the hierarchy knows which animation they are responding to. Walking animation is starting from the root joint, attempting to control the entire body, but the upper body part of the skeleton tree is overwriten by drinking animation which is starting from the spine joint. As shown in the figure below:

Root Motion Control:
Root motion is an animation technique where the actor’s movement comes directly from the animation itself rather than being handled by the game system. This is usually what we do not want because it will cause the actor’s visual location to shift away from its actual location. That’s why we need to extract root motion from the animation, or at least part of it.
Root Motion Extraction:
Root motion can be interpreted as the local transformation on the root joint. Because in the skeleton system local transformation on one joint is passed onto all the children joints, translation and rotation on the root node will cause the entire skeleton to move and rotate. Very rare we touch scale, but it also follows the same rule.

For each frame N (N >= 1), root transformation at frame N is:
Therefore, it is trival to fully or partically remove the root motion from all the joints (or only from root joint if joints are using local transformation matrices).
Root Motion Reapplication:
The root motion extracted from the animation is reapplied back to the actor when the animation is played. Game clock does not tick perfectly at the beginning or end of an animation frame, so it is necessary to calculate root motion on each frame delta second covers. The sum will be the best approximation of root motion for this current game frame.

In the figure above, the total root motion of this frame is the sum of X% of frame 21 total root motion and Y% of frame 22 total root motion.
Animation Notify (Event):
Events can be registered on animation to achieve a more complex gameplay. The most common use case is to toggle on and off collision components on the character to ensure a reasonable "hit window".

In the figure above, attack collision components (red) are toggled on and off at specific playback time (scaled with playback speed) during an animation.
Blending and Interruption:
When an animation is interrupted or is transitted into another animation, we need to specify what we want to do with the events registered on the original animation.
For example, cancelation:

Drink potion succeeded (restore health)

Animation interrupted (no hp restored)
Or not......
Attack collision components are toggled off also by events. When an attack is interrupted, we want to make sure that the collision is turned off properly. In this case, those events "persist" through transition and take effect when they need to.
Credit:
-
Paladin(player character) model and animations sourced from Mixamo.com, by Adobe
-
Boar model and animations sourced from Monster Hunter Rise, by Capcom
-
Environmental Assets sourced from Monster Hunter Rise, by Capcom
-
UI Asset sourced from Monster Hunter Rise, by Capcom