three.js项目如何实现关键帧之间的平滑插值过渡效果
three.js 关键帧动画平滑过渡实现方案
1. 核心原理
你当前的问题是只在时间完全匹配关键帧时才更新位置,缺少关键帧之间的插值计算。我们需要通过线性插值(Lerp)计算两个相邻关键帧之间任意时间点的位置,实现平滑过渡。
2. 第一步:预处理关键帧数据
首先把JSON里的对象结构转成按时间升序排列的关键帧数组,避免遍历顺序混乱的问题:
// 预处理右侧物体的位置关键帧 const positionKeyframes = Object.entries(json.right.position) .map(([timeStr, pos]) => ({ time: parseFloat(timeStr), position: new THREE.Vector3(pos[0], pos[1], pos[2]) })) .sort((a, b) => a.time - b.time); // 按时间从小到大排序
3. 第二步:每一帧计算当前插值位置
在你的渲染循环里,每次更新时按如下逻辑计算当前位置,替换原有直接匹配时间的逻辑:
function updateObjectPosition(obj, currentSeconds, keyframes) { const frameCount = keyframes.length; // 边界情况:时间小于第一个关键帧,直接用第一帧位置 if (currentSeconds <= keyframes[0].time) { obj.position.copy(keyframes[0].position); return; } // 边界情况:时间大于最后一个关键帧,直接用最后一帧位置 if (currentSeconds >= keyframes[frameCount - 1].time) { obj.position.copy(keyframes[frameCount - 1].position); return; } // 找到当前时间所在的前后两个关键帧 let prevFrame = keyframes[0]; let nextFrame = keyframes[frameCount - 1]; for (let i = 0; i < frameCount - 1; i++) { if (currentSeconds >= keyframes[i].time && currentSeconds <= keyframes[i+1].time) { prevFrame = keyframes[i]; nextFrame = keyframes[i+1]; break; } } // 计算插值因子 范围0~1 const alpha = (currentSeconds - prevFrame.time) / (nextFrame.time - prevFrame.time); // 线性插值计算当前位置 obj.position.lerpVectors(prevFrame.position, nextFrame.position, alpha); } // 调用示例,放在你的渲染循环中执行 updateObjectPosition(obj, seconds, positionKeyframes);
4. 原有代码问题说明
你原有代码的判断条件存在逻辑错误:if(seconds === json.position.right[key]) 里 json.position.right[key] 是位置数组,不是时间值,应该匹配的是parseFloat(key)才对,这也是你之前只有刚好命中时间点才会更新位置的原因之一。
扩展优化
如果需要更自然的运动效果,可以把线性插值换成缓动函数,比如平方缓动、立方缓动,只需要把计算出来的alpha值传入缓动函数做一次转换即可。
内容的提问来源于stack exchange,提问作者ARMN88
相关产品推荐
相关产品推荐

