I implemented Linear Interpolation (LERP) blending to blend between two different keyframes. Animation data is stored in the form of keyframes, where each keyframe denotes the local transform of each joint.
An animation file can contain animation that was sampled at different interval, but it is not likely that the game will sample them at the same interval.
To make sure the smooth transition of animation when character goes from one movement state to another, I used animation crossfading to achieve the result.
Essentially, when the transition happens from one state (P) to another state (N), then for a certain period, defined as crossfade duration, both the previous animation (Pa), and the next animation (Na) are sampled. The results of these two animations are then blended using the linear interpolation (LERP) blending.
Removing root motion data allows character movement to be governed by game's physics or character control system, rather than fixed animation scripts.
In my skeletal animation system root motion data removal happens in two stages:
In my engine when loading the animation file, 'remove root motion' attribute can be set to notify the animation controller to ignore the root motion data of the animation clip.
Manipulation of root motion data at runtime happens at three different stages. The first is when a movement state starts, the second is when the animation is being played, and finally the third is when the movement state ends.
To give my character the ability to vault over an arbitrary distance, I perform selective sampling on the root motion data.
The length of the vault is calculated based on the obstacle length. This data, combined with the forward root motion of the character, updates the global position of the character. Whereas, the upward and lateral root motion is left in the animation controller, which samples this data to update the root joint in model space for upward and lateral movement only.
The curve editing happens at the start of the movement state. This step is custom handled differently for each animation that is manipulated at runtime.
The prime example of curve editing usage is when two animations that needs to be played after each other do not match with respect to their root motion data.
Unedited curve
Edited curve
When stitching multiple animations together, if the end of the root motion data of the previous animation doesn't match the start of the next animation, another trick to solve the mismatching data is repositioning the global position of the character after the end of each animation in the stitching process.
Mismatching Z root motion curves of consecutive animations
The world position of the character changes after each animation. The above sequence is the result of 4 animations stitched one after the other.
To ensure smooth camera movement, the camera is smoothly LERPed over the delta translation of the animation curve.
Upward smooth camera movement
Lateral smooth camera movement
The obstacles of the world were detected by having multiple raycasts from the player in different directions.
I made a raycast vs Axis Aligned Bounding Box 3D (AABB3) visual testcase to test the algorithm in an isolated environment to make sure it is working properly.
I architectured a custom character controller to handle the animation and physics movement of my character. It is subdivided into movement controller and character controller.
The Animation states are defined in the XML file which is parsed at the startup. For each animation state, I decoupled the in-game name of that animation and the file name of that animation clip. I also specified explicitly what animation transitions are possible from a given state.
The Animation data was parsed from FBX file format. I used FBX because it's an industry standard.