本文已参与「新人创作礼」活动,一起开启掘金创作之路。
2022-04-07 最新发现 之前的方案会因为拖拽过快 计算遗漏导致最后几帧的模型一直停留 解决方案也很让我难以接受只需要几行代码即可 😭
const setProgress = (percent: number, clear?: boolean) => {
const t = ((maxDuration + 1) / 100) * percent;
for (var i = 0; i < mixer._actions.length; i++) {
const animate = mixer._actions[i];
animate.stop();
animate.play();
}
mixer.setTime(t);
};
前提是动画的循环次数是一次 AnimationClip.setLoop(THREE.LoopOnce)
gltf.animations.forEach((animate: THREE.AnimationClip) => {
mixer
.clipAction(animate)
.setLoop(THREE.LoopOnce,1)
.play();
if (animate.duration > maxDuration) maxDuration = animate.duration;
});
只需要调用 stop 然后 调用play
如果只调用 play方法 不会有变化 原因可能是播放次数是1导致不会再更新模型 stop会reset动画状态
查看源码
我参考的代码 - 527行左右
部分源码:
- 在载入动画时获取最长的动画所需时间
- 调用
mixer.setTime(t);方法设置动画进度 - 动画如果不设置
LoopOnce只播放一次 会不断重复播放该模型的动画 - 可以通过当前设置时间是否比该模型的总播放时长要长,长就调用
stop方法否则就调用play方法允许播放
逻辑
javascript
/**
* 将百分比传入 内部转换成具体时间
* @param {number} percent 进度百分比
*/
const setProgress = (percent) => {
const t = (maxDuration / 100) * percent;
for (var i = 0; i < mixer._actions.length; i++) {
const animate = mixer._actions[i];
const { duration } = animate.getClip();
if (duration > t) {
animate.play();
} else animate.stop();
}
mixer.setTime(t);
};
typescript
/**
* 进度蓝将百分比传入 内部转换成具体时间
* @param {number} percent 进度百分比
*/
const setProgress = (percent: number) => {
// if (percent > 100) return console.warn("进度大于100--" + percent);
const t = (maxDuration / 100) * percent;
//@ts-ignore
for (var i = 0; i < mixer._actions.length; i++) {
//@ts-ignore
const animate = mixer._actions[i] as THREE.AnimationAction;
const { duration } = animate.getClip();
//多次计算存在误差 +0.5是防止最后一帧动画元素 可以触发play方法 弊端就是有的动画时长不足0.5s会‘闪现’ 也可以在maxDuration+1
if (duration > t + 0.1) {
animate.play();
} else animate.stop();
}
mixer.setTime(t);
};
/**
* 适用于手动设置动画进度后 从当前进度开始播放 只要循环调用 setProgress即可
*/
const play = (callback: (percent: number) => void) => {
if (!mixer) return;
stop();
let sum = mixer.time || 0;
const clock = new THREE.Clock();
const animate = () => {
if (sum > maxDuration) return;
timer = requestAnimationFrame(animate);
const t = clock.getDelta();
sum += t;
const percent = (sum / maxDuration) * 100;
setProgress(percent);
callback(percent);
};
animate();
};