十七、动画库tween.js
tweenjs创建threejs动画
TweenJS是一个由JavaScript语言编写的补间动画库,如果需要tweenjs辅助你生成动画,对于任何前端web项目,你都可以选择tweenjs库。
安装与引用
bash
npm i @tweenjs/tween.js@^18javascript
import TWEEN from '@tweenjs/tween.js';tweenjs改变threejs模型对象位置
javascript
//创建一段mesh平移的动画
// 写法一:
const tween = new TWEEN.Tween(mesh.position);
//经过2000毫秒,pos对象的x和y属性分别从零变化为100、50
tween.to({x: 100,y: 50}, 2000);
//tween动画开始执行
tween.start();
// 写法二:
const tween = new TWEEN.Tween(mesh.position)
.to({x: 100,y: 50}, 2000)
.start();
// 渲染循环
function render() {
TWEEN.update();
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();tweenjs相机运动动画
相机飞行动画:从一个点飞到另一个点
只改变相机位置,相机默认视线方向保持不变,如果你想重新计算相机视线方向,可以在相机位置改变的过程中不停地执行lookAt()即可。
javascript
import TWEEN from '@tweenjs/tween.js';
...
camera.position.set(202, 123, 125);
camera.lookAt(0, 0, 0);
new TWEEN.Tween(camera.position)
.to({x: 202,y: 123,z: -350}, 3000)
// tweenjs改变参数对象的过程中,.onUpdate方法会被重复调用执行
.onUpdate(function(){
camera.lookAt(0, 0, 0);
})
.start()
// 渲染循环
function render() {
TWEEN.update();
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();Tweenjs回调函数
twwenjs库提供了onStart、onUpdate、onComplete等用于控制动画执行的回调函数。
onStart:动画开始执行触发onUpdate:动画执行过程中,一直被调用执行onComplete:动画正常执行完触发
.onUpdate(function(obj){})结构中,obj对应的是new TWEEN.Tween(pos)的参数对象pos。
javascript
const tween = new TWEEN.Tween(pos).to({x: 0}, 4000)
// 开始执行:动画片段tween开始执行的时候触发onStart
.onStart(function(obj){
...
})相机圆周运动,且保持相机镜头对准坐标原点
javascript
const R = 100; //相机圆周运动的半径
new TWEEN.Tween({angle:0})
.to({angle: Math.PI*2}, 16000)
.onUpdate(function(obj){
camera.position.x = R * Math.cos(obj.angle);
camera.position.z = R * Math.sin(obj.angle);
camera.lookAt(0, 0, 0);
})
.start()点按钮,相机飞行靠近观察设备
实际开发的的时候,一个较大的三维场景,有很多不同的设备或物品,你可能希望通过UI按钮点击切换到不同视角,观察某个区域,或者说放大观察某个特定的物品或设备。
javascript
<div class="pos">
<div id="A" class="bu">设备A</div>
<div id="B" class="bu" style="margin-left: 10px;">设备B</div>
<div id="car" class="bu" style="margin-left: 10px;">停车场</div>
<div id="all" class="bu" style="margin-left: 10px;">整体</div>
</div>javascript
// 切换到设备A预览状态
document.getElementById('A').addEventListener('click', function () {
const A = model.getObjectByName('设备A标注');
const pos = new THREE.Vector3();
A.getWorldPosition(pos); //获取三维场景中某个对象世界坐标
// 相机飞行到的位置和观察目标拉开一定的距离
const pos2 = pos.clone().addScalar(30);//向量的x、y、z坐标分别在pos基础上增加30
// 相机从当前位置camera.position飞行三维场景中某个世界坐标附近
new TWEEN.Tween({
// 相机开始坐标
x: camera.position.x,
y: camera.position.y,
z: camera.position.z,
// 相机开始指向的目标观察点
tx: 0,
ty: 0,
tz: 0,
})
.to({
// 相机结束坐标
x: pos2.x,
y: pos2.y,
z: pos2.z,
// 相机结束指向的目标观察点
tx: pos.x,
ty: pos.y,
tz: pos.z,
}, 2000)
.onUpdate(function (obj) {
// 动态改变相机位置
camera.position.set(obj.x, obj.y, obj.z);
// 动态计算相机视线
camera.lookAt(obj.tx, obj.ty, obj.tz);
})
.start();
})考虑OrbitControls的影响
如果你在项目中使用了相机控件OrbitControls,希望相机looAt()指向的目标改变以后,该相机控件让然可以正常使用。需要在动画结束.onComplete()的时候重新设置controls.target,或者.onUpdate()更新controls.target。
javascript
.onUpdate(function (obj) {
...
camera.lookAt(obj.tx, obj.ty, obj.tz);
})
.onComplete(function(obj){
controls.target.set(obj.tx, obj.ty, obj.tz);
controls.update();
})缓动算法.easing(地球渐入相机动画)
javascript
// easing函数:缓动算法(运动效果)
// easing类型:定义缓动算法起作用地方
tween.easing(TWEEN.Easing.easing函数.easing类型);
// 动画开始缓动方式(类比加速启动)
tween.easing(TWEEN.Easing.Sinusoidal.In);
// 动画结束缓动方式(类比减速刹车)
tween.easing(TWEEN.Easing.Sinusoidal.Out);
// 同时设置In和Out
tween.easing(TWEEN.Easing.Sinusoidal.InOut);动画效果:地球从小到大出现
javascript
camera.position.set(3000, 3000, 3000);
camera.lookAt(0, 0, 0);
// 视觉效果:地球从小到大出现(透视投影相机远小近大投影规律)
new TWEEN.Tween(camera.position)
.to({x: 300,y: 300,z: 300}, 3000)
.start()
.easing(TWEEN.Easing.Sinusoidal.InOut)//进入和结束都设置缓动淡入淡出
淡入
javascript
// 模型淡入
material.transparent = true;//开启透明计算
material.opacity = 0.0;//完全透明
// new TWEEN.Tween(material)
new TWEEN.Tween({opacity:material.opacity})
.to({opacity:1.0}, 3000)
.onUpdate(function(obj){
material.opacity = obj.opacity
})
.onComplete(function(){
//动画结束:关闭允许透明,恢复到模型原来状态
material.transparent = false;
})
.start();淡出
javascript
// 模型淡出
// new TWEEN.Tween(material)
new TWEEN.Tween({opacity:material.opacity})
.to({opacity:0.0}, 3000)
.onStart(function(){
//动画开始:允许透明opacity属性才能生效
material.transparent = true;
})
.onUpdate(function(obj){
material.opacity = obj.opacity
})
.start();循环触发
javascript
const tween = new TWEEN.Tween(object)
.to({ x: 100 }, 1000)
.onRepeat(() => {
console.log('一次循环完成,触发执行');
})
.onComplete(() => {
console.log('整个动画最终循环完成触发');
})
.repeat(800) // 循环次数
.start();javascript
// 循环无数次
tween.repeat(Infinity)
// 循环往复
tween.yoyo(true)
// 延迟操作
tween.delay(3000)
// 循环2次
tween.repeat(2)