Three.js Animation Transition with crossFadeTo

This article provides a practical guide on how to smoothly transition a character’s animation from walking to running in Three.js using the AnimationAction.crossFadeTo() method. You will learn how to set up your animation actions, configure the crossfade parameters, and ensure a seamless blend between different movement states.

To implement a smooth transition in Three.js, you utilize the AnimationMixer and AnimationAction APIs. When transitioning from a walk to a run, you gradually decrease the influence (weight) of the walking animation while simultaneously increasing the weight of the running animation.

Step 1: Initialize the Animations

Before you can transition between clips, both the walk and run animations must be registered with your AnimationMixer and set to play. Even if an animation has a weight of zero (meaning it is invisible), it must be actively playing in the mixer for a crossfade to work.

// Initialize the mixer for your 3D model
const mixer = new THREE.AnimationMixer(characterModel);

// Extract clips and create AnimationActions
const walkClip = THREE.AnimationClip.findByName(clips, 'walk');
const runClip = THREE.AnimationClip.findByName(clips, 'run');

const walkAction = mixer.clipAction(walkClip);
const runAction = mixer.clipAction(runClip);

// Start both actions, but set the run action's weight to 0 initially
walkAction.play();

runAction.setEffectiveWeight(0);
runAction.play();

Step 2: Trigger the crossFadeTo Method

The crossFadeTo() method smoothly transfers weight from one action to another over a specified duration in seconds. The syntax is:

currentAction.crossFadeTo(targetAction, durationInSeconds, warp);

Step 3: Implement the Transition Function

To trigger the transition during gameplay or user input, create a function that configures the target action and executes the crossfade:

function transitionToRun(duration = 0.5) {
    // 1. Ensure the target action is enabled and reset
    runAction.enabled = true;
    runAction.time = 0; // Optional: start the run cycle from the beginning
    
    // 2. Adjust the weight of the target action to be fully active
    runAction.setEffectiveWeight(1.0);

    // 3. Smoothly fade out the walk action and fade in the run action
    walkAction.crossFadeTo(runAction, duration, true);
}

Step 4: Update the Mixer in the Loop

For the transition to render, you must continuously update the AnimationMixer in your application’s main animation loop using a clock delta:

const clock = new THREE.Clock();

function animate() {
    requestAnimationFrame(animate);

    const delta = clock.getDelta();
    if (mixer) {
        mixer.update(delta);
    }

    renderer.render(scene, camera);
}