You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Three.js中crossFadeTo()切换动画时角色回到T姿的问题

Mixamo动画切换时角色回到T姿的解决方案

核心问题分析

  • crossFadeTo参数误用:第三个reset参数设为true会强制目标动画重置到初始状态(也就是Mixamo动画的T姿基准态),这是切换时跳回T姿的直接原因。
  • 重复创建AnimationAction:每次切换时调用mixer.clipAction生成新Action,没有复用已创建的实例,导致动画状态管理混乱。
  • 未更新当前Action引用:切换后没把this.action更新为新动画的Action,后续操作会基于旧Action重复执行过渡,引发冲突。

修复步骤

  1. 提前预创建所有AnimationAction:在加载完成后一次性生成所有动画对应的Action并存储,避免每次切换重复创建。
  2. 调整crossFadeTo参数:将第三个reset参数改为false,让目标动画从角色当前骨骼状态平滑过渡,而非重置到T姿。
  3. 切换后更新当前Action引用:完成过渡后将当前Action替换为新的,确保后续操作基于正确的动画实例。
  4. 优化事件监听:如果动画非循环,建议监听finished事件而非loop,确保触发时机准确。

修改后的代码

loadAnimations(){
    const loader = new FBXLoader();
    var that = this;
    for(var i=0;i<this.animationFiles.length;i++){
        loader.load(that.animationFiles[i],
            function(animObj){
                that.animations.push(animObj.animations[0]);
            },
            function(){
                console.log(Math.round(100*((that.animations.length+1)/that.animationFiles.length))+'% loaded');
                if((that.animations.length+1)==that.animationFiles.length) {
                    that.finishedLoading();
                }
            }
        );
    }
}

finishedLoading(){
    console.log(this.animations);
    this.mixer = new THREE.AnimationMixer(this.tpose);
    // 预创建所有动画的Action并存在Map里
    this.actionMap = new Map();
    this.animations.forEach((clip, index) => {
        const action = this.mixer.clipAction(clip);
        action.setEffectiveTimeScale(1);
        action.setEffectiveWeight(1);
        this.actionMap.set(index, action);
    });
    // 初始化播放指定动画
    this.currentAction = this.actionMap.get(1);
    this.currentAction.play();
    // 非循环动画用finished监听,循环动画改回loop即可
    this.mixer.addEventListener('finished', this.animationEnd.bind(this));
}

animationEnd(){
    console.log('animation end');
    var randomIndex = Math.floor(Math.random()*this.animations.length);
    console.log('playing animation#'+randomIndex);
    const nextAction = this.actionMap.get(randomIndex);
    
    // 避免重复切换到当前正在播放的动画
    if(nextAction === this.currentAction) return;

    // 平滑过渡,关闭reset避免回到T姿
    this.currentAction.crossFadeTo(nextAction, 1, false);
    // 更新当前Action引用
    this.currentAction = nextAction;
    // 确保新动画处于播放状态
    this.currentAction.play();
}

补充说明

  • 预创建actionMap可以复用Action实例,避免每次创建新实例带来的状态重置问题。
  • 关闭reset参数后,目标动画会基于角色当前的骨骼位置开始过渡,完全避免T姿跳转。
  • 增加的重复动画判断可以防止无意义的过渡操作,优化性能。

内容的提问来源于stack exchange,提问作者iPadDeveloper2011

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 18:13:17