Threejs进阶之十二:Threejs与Tween.js结合创建动画 您所在的位置:网站首页 threejs切换场景 Threejs进阶之十二:Threejs与Tween.js结合创建动画

Threejs进阶之十二:Threejs与Tween.js结合创建动画

2023-12-24 10:50| 来源: 网络整理| 查看: 265

tween.js介绍

Tween.js是一个可以产生平滑动画效果的js库,其官方地址为:https://github.com/tweenjs/tween.js/,可以将源码下载后,可以在tween.js/dist/文件夹下找到相应的js代码,在HTML中进行引用;也可以通过npm命令在终端控制台中安装tween.js模块 npm install @tweenjs/tween.js 然后在相应的页面引用Tween.js import * as TWEEN from '@tweenjs/tween.js'

tween.js的使用方法

tween.js的使用非常简单,只需要三步就可以完成一个补间动画 1、在创建Tween实例的时候将想要修改的变量作为参数传递给Tween 2、使用TWEEN.Tween().to()方法,传入结束点的最终值,以及动画花费多少时间两个参数 3、使用Tween().start()方法,启动动画,tween引擎就可以计算从开始动画点到结束动画点之间值,来产生平滑的动画效果

tween.js的核心方法 .to()方法

控制补间的运动形式及方向 .to() , 当tween启动时,Tween.js将读取当前属性值并 应用相对值来找出新的最终值

.start(time) 方法

补间动画启动的方法, .start 方法接受一个参数 time , 如果加入这个参数,那么补间不会立即开始直到特定时刻才会开始

.stop()方法

关闭补间动画 .stop() , 关闭这个正在执行的补间动画

.repeat()方法

使用该方法可以使动画重复执行,它接受一个参数 , 描述需要重复多少次

.delay()方法

延迟执行动画的方法 .delay() , 接受一个参数用于控制延迟的具体时间,表示延迟多少时间后才开始执行动画

.pause()方法

暂停动画.pause() , 暂停当前补间运动,与resume方法配合使用

.resume()方法

恢复动画 .resume() , 恢复这个已经被暂停的补间运动

.yoyo() 方法

控制补间重复的模式 .yoyo() , 这个功能只有在使用 repeat 时才有效果 ,该动画像悠悠球一样来回运动 , 而不是重新开始

.update()方法

更新补间动画 TWEEN.update() , 动态更新补间运动一般配合 window.requestAnimationFrame 使用

.chain()方法

链式补间动画,当我们顺序排列不同的补间动画时,比如我们在上一个补间结束的时候立即启动另外一个补间动画,使用 .chain() 方法来做。

//tweenB动画在tweenA动画完成后执行 tweenA.chain(tweenB);

在一些情况下,可能需要将多个补间链接到另一个补间,以使它们(链接的补间)同时开始动画:

tweenA.chain(tweenB,tweenC);

注意:调用 tweenA.chain(tweenB) 实际上修改了tweenA,所以tweenA总是在tweenA完成时启动。 chain 的返回值只是tweenA,不是一个新的tween。

.getAll()方法

获取所有的补间组 TWEEN.getAll()

.removeAll()方法

删除所有的补间组 TWEEN.removeAll()

.add()方法

新增补间 TWEEN.add(tween) ,添加一个特定的补间 var tween=new TWEEN.Tween()

.remove()方法

删除补间 TWEEN.remove(tween),删除一个特定的补间var tween=new TWEEN.Tween()

.Group()方法

新增一个补间组, var Group=TWEEN.Group() , new TWEEN.Tween({ x: 1 }, Group) , 将已经配置好的补间动画进行分组 , TWEEN.update()和TWEEN.removeAll() , 不会影响到已经分好组的补间动画

tween.js回调函数 .onStart()补间动画开始时执行,只执行一次

new TWEEN.Tween().onStart((obj)=>{}) , 补间开始时执行,只执行一次, 当使用 repeat() 重复补间时,不会重复运行 , onStart((obj)=>{}) obj 补间对象作为第一个参数传入

.onStop() 停止补间动画时执行

new TWEEN.Tween().onStop((obj)=>{}) , 当通过 onStop() 显式停止补间时执行,但在正常完成时并且在停止任何可能的链补间之前执行补间,onStop((obj)=>{}) obj 补间对象作为第一个参数传入

.onUpdate() 每次更新时执行

new TWEEN.Tween().onUpdate((obj)=>{}) , 每次补间更新时执行,返回实际更新后的值, onUpdate((obj)=>{}) obj 补间对象作为第一个参数传入

.onComplete() 补间动画完成时执行

new TWEEN.Tween().onComplete((obj)=>{}) , 当补间正常完成(即不停止)时执行 , onComplete((obj)=>{}) obj 补间对象作为第一个参数传入

.onRepeat() 重复补间动画时执行

new TWEEN.Tween().onRepeat((obj)=>{}) , 当补间动画完成,即将进行重复动画的时候执行 , onComplete((obj)=>{}) `obj 补间对象作为第一个参数传入

TWEEN.Easing 缓动函数

tween.js为我们封装好了常用的缓动动画,如线性,二次,三次,四次,五次,正弦,指数,圆形,弹性,下落和弹跳等缓动函数 以及对应的缓动类型:In (先慢后快) ;Out (先快后慢) 和 InOut (前半段加速,后半段减速) 常见的缓动动画如下 Linear:线性匀速运动效果; Quadratic:二次方的缓动(t^2); Cubic:三次方的缓动(t^3); Quartic:四次方的缓动(t^4); Quintic:五次方的缓动(t^5); Sinusoidal:正弦曲线的缓动(sin(t)); Exponential:指数曲线的缓动(2^t); Circular:圆形曲线的缓动(sqrt(1-t^2)); Elastic:指数衰减的正弦曲线缓动; Back:超过范围的三次方缓动((s+1)t^3 – st^2); Bounce:指数衰减的反弹缓动。 以上每个效果都分三个缓动类型,分别是: easeIn:从0开始加速的缓动,也就是先慢后快; easeOut:减速到0的缓动,也就是先快后慢; easeInOut:前半段从0开始加速,后半段减速到0的缓动。

在Threejs中使用Tween.js库

继续在前面章节的代码基础上进行实现,由于我们是基于vue开发的,所以这里我们使用npm的方式安装tween.js库

在vue中安装并引入tween.js库

打开控制器,输入npm install @tweenjs/tween.js进行安装,在components文件夹新建TweenView.vue文件,在该文件中引入tween.js import * as TWEEN from '@tweenjs/tween.js'

初始化场景

在使用tween.js实现动画之前,先将threejs的初始化环境搭建好,并创建一个立方体

import * as THREE from 'three' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' import * as TWEEN from '@tweenjs/tween.js' import { onMounted } from 'vue' let scene,camera,renderer,controls onMounted(()=>{ init() }) function init() { initScene() initCamera() initAxesHelper() initLight() initRenderer() initControls() initMesh() animate() window.addEventListener('resize',onWindowResize.bind(this)) } // 初始化场景 function initScene() { scene = new THREE.Scene() } // 初始化相机 function initCamera() { camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000) camera.position.set(0,2,2) } // 辅助轴 function initAxesHelper() { const axesHelper = new THREE.AxesHelper(1) scene.add(axesHelper) } // 灯光 function initLight() { const hesLight = new THREE.HemisphereLight(0xffffff,0x444444) hesLight.intensity = 0.3 scene.add(hesLight) const dirLight = new THREE.DirectionalLight() dirLight.position.set(5,5,5) scene.add(dirLight) const pointLight = new THREE.PointLight(0xffffff,1.5) pointLight.position.set(0,100,90) scene.add(pointLight) pointLight.color.setHSL(Math.random(),1,0.5) } // 初始化渲染器 function initRenderer() { renderer = new THREE.WebGLRenderer({antialias:true}) renderer.setPixelRatio(window.devicePixelRatio) renderer.setSize(window.innerWidth,window.innerHeight) document.querySelector('#scene').appendChild(renderer.domElement) renderer.shadowMap.enable = true } // 初始化轨道控制器 function initControls() { controls = new OrbitControls(camera,renderer.domElement) controls.minPolarAngle = 0 controls.maxPolarAngle = 80 / 360 * 2 * Math.PI controls.update() } // Mesh function initMesh() { const boxGeometry = new THREE.BoxGeometry(0.3,0.3,0.3) const boxMaterial = new THREE.MeshPhongMaterial({color:0x00ff00}) const boxMesh = new THREE.Mesh(boxGeometry,boxMaterial) scene.add(boxMesh) } function animate() { const delta = clock.getDelta() renderer.render(scene,camera) controls.update(delta) requestAnimationFrame(animate) } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth,window.innerHeight) } 实例化Tween对象

实例化Tween对象并将物体当前的位置作为参数传入该对象

const tween = new TWEEN.Tween(mesh.position) 使用.to()方法指定移动终点和时间

使用.to()方法指定移动的终点和时间

tween.to({x:3,y:0,z:0},2000) 调用.onUpdate()方法更新动画,

调用.onUpdate()方法更新动画,在回调函数中设置相机的.lookAt()方法,

tween.onUpdate(function(){ camera.lookAt(0,0,0) }) 开启动画

使用.start()方法开启动画

tween.start()

刷新查看浏览器, 发现物体已经按照我们给定的终点坐标进行了移动 在这里插入图片描述

给场景添加地面辅助线

为了更好的看到效果,给场景中添加地面辅助线,定义initGridHelper()方法,在init()函数中调用

// 辅助地面 function initGridHelper () { const gridHelper = new THREE.GridHelper(10,10) scene.add(gridHelper) } 使用.chain()方法对多段动画进行串联执行

继续对上面的物体运动进行研究,我们在物体移动到指定位置后,再给定一个目标点位置,使其继续移动; 新建一个tween2对象,仍然将mesh.position作为参数传入,调用tween2.to方法,指定终点坐标和时间 然后通过调用.chain()方法,将tween2作为参数传递给tween.chain()方法,这样tween在执行完第一段代码后,会接着执行tween2的代码,实现多段动画的连续执行

const tween2 = new TWEEN.Tween(mesh.position) tween2.to({x:3,y:0,z:3},2000) tween.chain(tween2) tween.start() 使用tween执行缩放动画

tweenjs不仅仅能实现移动动画,它能实现很多动画功能,这里我们接着上面的动画在物体移动到tween2指定的终点时,再对齐进行一个缩放动画 我们先定义一个对象,里面给一个参数s为1,代表当前的缩放比例是1

const scaleParam = { s:1}

我们创建一个新的tween3对象 然后我们创建一个新的tween3对象,将上面的scaleParam 作为参数传入

const tween3 = new TWEEN.Tween(scaleParam)

调用.to方法 调用tween3.to()方法,将对象s设置为10,时间设置为2000

tween3.to({s:10},2000)

调用.onUpdate()方法 调用.onUpdate()方法,在.onUpdate()方法的回调函数中设置mesh在x轴的缩放值为s

tween3.onUpdate(function(){ mesh.scale.x = scaleParam.s })

调用.chain()方法 调用tween2.chain()方法,将tween3作为参数传入,表示tween2动画执行完后执行tween3动画

tween2.chain(tween3) tween.start()

刷新浏览器,可以看到物体按照我们预期的效果实现了动画 在这里插入图片描述

使用缓动动画

使用缓动动画可以是我们的动画看起来更真实自然,前面讲过,tweenjs已经为我们封装了常见的缓动动画,我们使用使只需要调用就可以了,常见的缓动动画曲线如下图所示 在这里插入图片描述 给立方体运动的动画添加缓动动画 我们可以给上面的立方体添加缓动动画,使其看起来更真实,我们在立方体的第一段动画(tween)和第二段动画(tween2)时让其先快后慢

const tween = new TWEEN.Tween(mesh.position) tween.to({x:3,y:0,z:0},2000) tween.onUpdate(function(){ camera.lookAt(0,0,0) }).easing(TWEEN.Easing.Sinusoidal.InOut) const tween2 = new TWEEN.Tween(mesh.position) tween2.to({x:3,y:0,z:3},2000).easing(TWEEN.Easing.Sinusoidal.InOut) tween.chain(tween2) const scaleParam = { s:1} const tween3 = new TWEEN.Tween(scaleParam) tween3.to({s:10},2000) tween3.onUpdate(function(){ mesh.scale.x = scaleParam.s }) tween2.chain(tween3) tween.start()

刷新浏览器看效果,符合我们的要求 在这里插入图片描述 好了,关于tweenjs和threejs结合创建动画就先说到这里,其实关于tween和threejs结合的动画还有很多,比如可以结合tween实现物体颜色的变化、透明度的变化等,具体各位小伙伴可以自己摸索。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有