requestAnimationFrame()方法:
动画原理:
// 移动物体:实现在x轴的旋转效果
move() {
this.cube.rotation.x += 0.01
},
// 渲染下一针的时候就会调用 render
render() {
this.move()
this.renderer.render(this.scene, this.camera)
},
// 帧动画
animate(time) {
// 默认会传一个`time`,单位是ms
// 根据时间和速度计算移动距离
// 原本5是只渲染一次, 当相机通过轨道查看几何物体时,是按帧渲染的
let t = (time / 1000) % 5
this.cube.position.x = t * 1
// 运动就是在每一帧渲染的时候坐标轴的位置变化
// 小方块每帧在X轴上向前运动0.01,当运动到大于5时回到原点
if (this.cube.position.x >= 5) {
// 2. 移动距离
this.cube.position.x = 0
}
//使用渲染器,通过相机将场景渲染进来
this.render()
requestAnimationFrame(this.animate)
},
requestAnimationFrame()和 clock 的结合使用:
// 设置时钟
this.clock = new THREE.Clock()
// 渲染下一针的时候就会调用 render
render() {
this.renderer.render(this.scene, this.camera)
},
// 帧动画
animate() {
// requestAnimationFrame 会默认传入进来time ,单位ms
// 浏览器刷新率是60帧/s,16帧/ms
// 获取时钟运行的总时长
// let totalTime = clock.getElapsedTime();
// 间隔时间,即oldtime到当前时间的秒数,同时将oldtime设置为当前时间
// oldtime :存储时钟最后一次调用start ,getElapsedTime或者getDelta方法 的时间
// let deltaTime = clock.getDelta();//两帧的时间差,这一帧到下一帧的时间差
// console.log('间隔时间',deltaTime)//0 此时为0 ,把clock.getElapsedTime()注释掉,则可以得到真正的间隔时间,大概是8ms,那么1000/8 大概是125帧/s
// 获取时钟运行的总时长
let clockTime = this.clock.getElapsedTime()
// 配合 Math.sin 和 Math.cos 会有更好的动画效果
this.smallBall.position.x = Math.sin(clockTime) * 3
this.smallBall.position.z = Math.cos(clockTime) * 3
this.smallBall.position.y = 2 + Math.sin(clockTime * 10)
this.render()
requestAnimationFrame(this.animate)
},
gsap是一款以javascript实现方式实现的动画库,主要功能就是节省上面的运算时间, 需要你来设置在x, y, z轴上的变化。
默认情况下,GSAP 将使用 px 和度数进行变换,但可以使用其他单位,例如 vw、弧度,甚至可以进行自己的 JS 计算或相对值!
安装:
npm i --save gsap
引入使用:
// 导入动画库
import gsap from 'gsap'
添加动画:
gsap.to() – 这是最常见的补间类型。是设置当前元素或者变量的状态,到设置的状态的补间动画。所谓的补间动画,就是2个关键帧(即2种物体的状态)有了,框架自带计算出中间某个时刻的状态,从而填补2个状态间,动画的空白时刻,从而实现完整动画。
gsap.to有2个参数,第一个是目标元素或者变量。如果传入的是.box之类的css字符串选择器,GSAP 在后台使用document.querySelectorAll()
选中页面的匹配的元素。当第一个目标是对象时,GSAP就会对其属性值进行修改来实现补间动画。
// 设置动画
let animate1 = gsap.to(
// 需要执行动画的参数对象
this.cube.position,
// 执行动画的目标参数
{
// 使盒子移动到 x 轴为 5 的位置
x: 10,
// 需要的时间,5秒
duration: 5,
// 动画执行方式
ease: 'power1.inOut',
// 循环次数,无限制循环是-1
repeat: -1,
// 往返运动
yoyo: true,
// 延迟两秒执行
delay: 2,
// 动画完成时执行的函数
onComplete: () => {
console.log('动画完成')
},
// 动画开始时执行的函数
onStart: () => {
console.log('动画开始')
},
}
)
添加双击暂停和开启动画:让双击画面,控制立方体动画暂停和恢复动画,前面创建的animate1这个动画实例,有isActive方法,可以用来获取当前动画是暂停还是播放状态,播放状态时isActive方法返回为true,暂停时为false,根据这个状态来调用pause方法来暂停动画和恢复动画。
window.addEventListener('dblclick', () => {
if (animate1.isActive()) {
// 暂停
animate1.pause()
} else {
// 恢复
animate1.resume()
}
})
gsap内建了requestAnimationFrame,因此不比手动更新动画,但是如果想看到立方体移动的效果,还是需要每帧重渲染场景。
tween.js在three.js中有很多使用场景,比如粒子动画,相机转场动画,物体运动。
tween.js可以平滑的修改元素的属性值。在配合动画函数实现动画效果
安装:
npm install @tweenjs/tween.js --save
引入:
import TWEEN from '@tweenjs/tween.js';
创建补间:
//创建tween对象并告诉它初始位置
const tween = new TWEEN.Tween(group.position)
指定过渡形式:
tween.easing(TWEEN.Easing.Sinusoidal.InOut);
依次执行多个动画:如果在程序中需要多个动画,并且有一定的先后顺序。那么就可以通过tween.chain()方法实现。
例如已经创建了tween1和tween2两个TWEEN对象。希望tween1结束后tween2开始。那么可以这样使用:tween1.chain(tween2);
如果你希望tween1结束后tween2开始,tween2结束后tween1开始,往复调用,那么可以这样写代码:tween1.chain(tween2);tween2.chain(tween1);
const tween = new TWEEN.Tween(group.position).to(
{ z: this.setting.maxZ },
5000);
tween.easing(TWEEN.Easing.Sinusoidal.InOut);
var tweenBack = new TWEEN.Tween(group.position).to(
{ z: this.setting.minZ },
5000);
tweenBack.easing(TWEEN.Easing.Sinusoidal.InOut);
tween.chain(tweenBack);
tweenBack.chain(tween);
补间动画功能:
//通过tween对象的to()方法告诉它目标位置和所需时间
tween.to(
{ z: this.setting.maxZ },
// 指定动画时间 5s
5000
);
tween.repeat(10)
tween.start();
tween.stop()
yoyo:控制补间重复的模式 , new TWEEN.Tween().yoyo()
, 这个功能只有在使用 repeat 时才有效果 , 补间的 行,为将像悠悠球一样来回运动 , 而不是重新开始
tween.yoyo()
delay:控制补间开始前的延迟 new TWEEN.Tween().delay()
, 补间开始之前的延迟时间接受一个参数用于控制具 体时间
tween.delay(2)
pause:暂定补间动画 new TWEEN.Tween().pause()
, 暂停当前补间运动
tween.pause()
resume :恢复补间动画 new TWEEN.Tween().resume()
, 恢复这个已经被暂停的补间运动
tween.resume()
tween回调函数:
由于Tween对象的每个函数调用都返回一个tween对象。所以也支持链式调用。以下代码与上一个例子实现同样的功能:
new TWEEN.Tween(group.position)
.to(
{
z: this.setting.maxZ
},
// 指定动画时间 5s
5000)
.easing(TWEEN.Easing.Linear.None)
.onComplete(function () {
console.log('测试');
console.log(_this.scene.children);
console.log(intersects[0].object);
});
.start()
调用Tween.update():为了实现平滑的动画效果,我们需要在一个循环动画中调用TWEEN.update方法,一般会把它放入在帧动画里循环,
// 帧动画
animate() {
this.render();
// 更新控制器
this.controls.update();
TWEEN.update();
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(this.animate);
},