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

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

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

关于ThreeJs中动画可以参考:

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

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

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

接下来将gltf.scene关键帧动画模型的父对象作为参数传入。获得混合器实例mixer,clipAction方法获取获取动画剪辑,然后使用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中进行添加,可以使用ThreeJs的Clock时钟,用于跟踪时间,当然也可以直接使用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展览就完成啦!

相关推荐
Csvn37 分钟前
WASM
前端
修己xj2 小时前
我用 AI 给自己写了一个 Markdown 编辑器,然后把它开源了
前端
FRing032 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
幸运小猿2 小时前
模拟慢上传-处理超时重试image 丢失线上问题
前端·javascript·html
moshuying4 小时前
网购能买Token了!
前端
h_65432104 小时前
echarts实现柱状图加一条横线
前端·echarts
风骏时光牛马4 小时前
生成一个后端标题,只需要一个标题,不需要其他的任何文本。
前端
子非鱼@Itfuture4 小时前
关于前后端联调中登录状态/登录信息失效?
java·前端
郭小李4 小时前
openFeign入门
java·开发语言·前端
馒头不想说话5 小时前
AI当运营,帮你省人力
前端