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 分钟前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^2 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie2 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic3 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿3 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具3 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
qq_390161774 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test5 小时前
js下载excel示例demo
前端·javascript·excel
Yaml45 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事5 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro