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

如何为Babylon JS关键帧动画的每个关键帧配置缓动函数

如何为BabylonJS关键帧动画的每个关键帧关联缓动函数?

假设我定义了如下类似的BabylonJS关键帧动画(为简洁起见省略了辅助代码):

const animation = new BABYLON.Animation(
    "positionAnimation",
    "position.x",
    30,
    BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);

const keys = [];
keys.push({
    frame: 0,
    value: box.position.x,
});
keys.push({
    frame: 60,
    value: box.position.x - 2,
   
});

animation.setKeys(keys);

目前我可以通过animation.setEasingFunction(anEasingFunction)为整个动画定义缓动函数,但希望在关键帧级别配置,以便按需在动画中应用多个缓动函数。这是否可行?若不可行,有无类似效果的替代方案?


核心结论

BabylonJS的单条Animation对象本身不支持为单个关键帧单独设置缓动函数,它的缓动函数是作用于整个动画周期的。不过可以通过以下几种替代方案实现类似效果:

方案1:拆分动画为多个独立的Animation对象

把需要不同缓动效果的关键帧段拆分成多个单独的动画,分别设置对应的缓动函数,再通过AnimationGroup把它们组合起来同步执行。

示例代码:

// 第一段动画:帧0到帧30,使用弹性缓动
const anim1 = new BABYLON.Animation(
    "anim1",
    "position.x",
    30,
    BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT
);
anim1.setKeys([
    { frame: 0, value: box.position.x },
    { frame: 30, value: box.position.x - 1 }
]);
anim1.setEasingFunction(new BABYLON.ElasticEase());

// 第二段动画:帧30到帧60,使用回弹缓动
const anim2 = new BABYLON.Animation(
    "anim2",
    "position.x",
    30,
    BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT
);
anim2.setKeys([
    { frame: 30, value: box.position.x - 1 },
    { frame: 60, value: box.position.x - 2 }
]);
anim2.setEasingFunction(new BABYLON.BounceEase());

// 组合动画组
const animGroup = new BABYLON.AnimationGroup("multiEaseGroup");
animGroup.addTargetedAnimation(anim1, box);
animGroup.addTargetedAnimation(anim2, box);

// 播放动画组
animGroup.start(true);

方案2:使用自定义插值函数

通过Animation.setCustomInterpolateFunction自定义插值逻辑,在函数内部根据当前帧所在的区间应用不同的缓动算法。

示例代码:

const animation = new BABYLON.Animation(
    "positionAnimation",
    "position.x",
    30,
    BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);

const keys = [
    { frame: 0, value: box.position.x },
    { frame: 30, value: box.position.x - 1 },
    { frame: 60, value: box.position.x - 2 }
];
animation.setKeys(keys);

// 定义不同区间的缓动函数
const ease1 = new BABYLON.ElasticEase();
const ease2 = new BABYLON.BounceEase();

// 设置自定义插值函数
animation.setCustomInterpolateFunction((currentFrame, startValue, endValue, startFrame, endFrame) => {
    // 计算当前帧在区间内的进度(0到1)
    const progress = (currentFrame - startFrame) / (endFrame - startFrame);
    
    // 判断当前区间,应用对应缓动
    let easedProgress;
    if (startFrame === 0 && endFrame === 30) {
        easedProgress = ease1.ease(progress);
    } else if (startFrame === 30 && endFrame === 60) {
        easedProgress = ease2.ease(progress);
    } else {
        easedProgress = progress; // 默认线性插值
    }
    
    // 计算最终值
    return startValue + (endValue - startValue) * easedProgress;
});

// 播放动画
box.animations.push(animation);
scene.beginAnimation(box, 0, 60, true);

方案3:使用关键帧的easingFunction属性(进阶)

从BabylonJS 5.0版本开始,部分动画系统支持直接为关键帧对象添加easingFunction属性(需确保使用的是FrameAnimation或对应支持的动画类型)。不过这个特性并非所有动画场景都兼容,建议先测试验证:

示例代码:

const keys = [];
const ease1 = new BABYLON.ElasticEase();
const ease2 = new BABYLON.BounceEase();

keys.push({
    frame: 0,
    value: box.position.x,
    easingFunction: ease1 // 为该关键帧到下一关键帧的区间设置缓动
});
keys.push({
    frame: 30,
    value: box.position.x - 1,
    easingFunction: ease2 // 为该关键帧到下一关键帧的区间设置缓动
});
keys.push({
    frame: 60,
    value: box.position.x - 2
});

animation.setKeys(keys);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:25:03