Three.js杂记(十五)—— 汽车展览(下)

在上一篇文章Three.js杂记(十四)------ 汽车展览·上 - 掘金 (juejin.cn)中主要对切换相机不同位置和鼠标拖拽移动相机焦点做了简单的应用。

那么现在聊聊该如何实现汽车模型自带的三种动画展示了,实际上可以是两种汽车前后盖打开汽车4车门打开,最后一种只是将前两种结合起来了。

关于ThreeJs中动画可以参考:

ThreeJs动画是关键帧动画,在汽车模型导入时,可以从gltf中查找到AnimationClip动画剪辑。

在查找动画这一步上面,我卡了很久,一直没找到动画。原因是我从gltf.sceneanimations上开始查找的,没有找到,甚至还递归遍历内部元素寻找animations。但是最后发现,直接gltf.animations就可以找到三种动画,白白绕了一大圈。

找到模型动画后,使用AnimationMixer函数生成一个动画混合器。当场景中的多个对象独立动画时,每个对象都可以使用同一个动画混合器。

接下来将gltf.scene关键帧动画模型的父对象作为参数传入。获得混合器实例mixerclipAction方法获取获取动画剪辑,然后使用play方法播放此动画。可以对循环次数进行限制。

gltfLoader.load中添加以下代码:

ts 复制代码
// 模型动画
const modelAnimationArr = gltf.animations;
//包含关键帧动画的模型作为参数创建一个播放器
mixer = new THREE.AnimationMixer(gltf.scene);
const clipAction = mixer.clipAction(modelAnimationArr[0]);
clipAction.play(); //播放动画
//不循环播放
clipAction.loop = THREE.LoopOnce; 

当然,现在动画还是不会生效。因为没有执行混合器的update方法,推进混合器时间并更新动画。需要在animate中进行添加,可以使用ThreeJsClock时钟,用于跟踪时间,当然也可以直接使用new Date()

ts 复制代码
// 如果想播放动画,需要周期性执行`mixer.update()`更新AnimationMixer时间数据
const clock = new THREE.Clock();
function animate() {
	if (mixer) {
		//clock.getDelta()方法获得loop()两次执行时间间隔
		let frameT = clock.getDelta();
		// 更新播放器相关的时间
		mixer.update(frameT);
	}
	// ...
}

这样一来,汽车第一个动画效果就运行起来了。


三种动画切换

在成功运行了第一种动画后,接下来就只是一些完善性的工作了。

在原先的面板上添加三种动画的切换按钮吧。

然后动画的切换比较重要,这里官网API:AnimationAction -- three.js docs (threejs.org)

  1. 对于当前所属动画可以设置curIndex,然后如果动画尚未结束,那么先用stop方法结束动画
  2. 判断动画是否结束,可以在混合器上绑定finished监听事件。在动画事件结束之后,重新将curIndex设置为-1
  3. 动画启动时,设置curIndex的值为当前动画的index序号,然后使用play函数进行播放。
  4. 根据我的观察,当前汽车模型的动画最后会把打开的车门又关闭,但是我不希望关闭,可以设置剪辑对象的结束时间,并通过clampWhenFinished让动画停止在最后一帧。
ts 复制代码
// 切换改变当前汽车动画
let curIndex = -1;
const changeAnimation = (num: number) => {
	if (curIndex > -1) {
		// 结束原先动画
		mixer.clipAction(modelAnimationArr[curIndex]).stop();
	}
	curIndex = num;
	const clipAction = mixer.clipAction(modelAnimationArr[num]);
	clipAction.time = 2;  // 剪辑对象起始时间
	clipAction._clip.duration = 10; //剪辑对象设置播放结束时间
	clipAction.clampWhenFinished = true; // 是否在动画结束时停止播放
	
	clipAction.play(); //播放动画
	//不循环播放
	clipAction.loop = THREE.LoopOnce; 
	mixer.addEventListener( 'finished', function(e:any) {
		curIndex = -1;
	});
}

效果:

这样一个简单的汽车3D展览就完成啦!

相关推荐
前端大卫12 小时前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘12 小时前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare12 小时前
浅浅看一下设计模式
前端
Lee川12 小时前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix12 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人12 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl12 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅13 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人13 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼13 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端