Threejs與Tween.js結(jié)合創(chuàng)建動(dòng)畫(huà)的詳細(xì)圖文教程
tween.js介紹
Tween.js是一個(gè)可以產(chǎn)生平滑動(dòng)畫(huà)效果的js庫(kù),其官方地址為:https://github.com/tweenjs/tween.js/,可以將源碼下載后,可以在tween.js/dist/文件夾下找到相應(yīng)的js代碼,在HTML中進(jìn)行引用;也可以通過(guò)npm命令在終端控制臺(tái)中安裝tween.js模塊
npm install @tweenjs/tween.js然后在相應(yīng)的頁(yè)面引用Tween.js
import * as TWEEN from '@tweenjs/tween.js'
tween.js的使用方法
tween.js的使用非常簡(jiǎn)單,只需要三步就可以完成一個(gè)補(bǔ)間動(dòng)畫(huà)
1、在創(chuàng)建Tween實(shí)例的時(shí)候?qū)⑾胍薷牡淖兞孔鳛閰?shù)傳遞給Tween
2、使用TWEEN.Tween().to()方法,傳入結(jié)束點(diǎn)的最終值,以及動(dòng)畫(huà)花費(fèi)多少時(shí)間兩個(gè)參數(shù)
3、使用Tween().start()方法,啟動(dòng)動(dòng)畫(huà),tween引擎就可以計(jì)算從開(kāi)始動(dòng)畫(huà)點(diǎn)到結(jié)束動(dòng)畫(huà)點(diǎn)之間值,來(lái)產(chǎn)生平滑的動(dòng)畫(huà)效果
tween.js的核心方法
.to()方法
控制補(bǔ)間的運(yùn)動(dòng)形式及方向 .to() , 當(dāng)tween啟動(dòng)時(shí),Tween.js將讀取當(dāng)前屬性值并 應(yīng)用相對(duì)值來(lái)找出新的最終值
.start(time) 方法
補(bǔ)間動(dòng)畫(huà)啟動(dòng)的方法, .start 方法接受一個(gè)參數(shù) time , 如果加入這個(gè)參數(shù),那么補(bǔ)間不會(huì)立即開(kāi)始直到特定時(shí)刻才會(huì)開(kāi)始
.stop()方法
關(guān)閉補(bǔ)間動(dòng)畫(huà) .stop() , 關(guān)閉這個(gè)正在執(zhí)行的補(bǔ)間動(dòng)畫(huà)
.repeat()方法
使用該方法可以使動(dòng)畫(huà)重復(fù)執(zhí)行,它接受一個(gè)參數(shù) , 描述需要重復(fù)多少次
.delay()方法
延遲執(zhí)行動(dòng)畫(huà)的方法 .delay() , 接受一個(gè)參數(shù)用于控制延遲的具體時(shí)間,表示延遲多少時(shí)間后才開(kāi)始執(zhí)行動(dòng)畫(huà)
.pause()方法
暫停動(dòng)畫(huà).pause() , 暫停當(dāng)前補(bǔ)間運(yùn)動(dòng),與resume方法配合使用
.resume()方法
恢復(fù)動(dòng)畫(huà) .resume() , 恢復(fù)這個(gè)已經(jīng)被暫停的補(bǔ)間運(yùn)動(dòng)
.yoyo() 方法
控制補(bǔ)間重復(fù)的模式 .yoyo() , 這個(gè)功能只有在使用 repeat 時(shí)才有效果 ,該動(dòng)畫(huà)像悠悠球一樣來(lái)回運(yùn)動(dòng) , 而不是重新開(kāi)始
.update()方法
更新補(bǔ)間動(dòng)畫(huà) TWEEN.update() , 動(dòng)態(tài)更新補(bǔ)間運(yùn)動(dòng)一般配合 window.requestAnimationFrame 使用
.chain()方法
鏈?zhǔn)窖a(bǔ)間動(dòng)畫(huà),當(dāng)我們順序排列不同的補(bǔ)間動(dòng)畫(huà)時(shí),比如我們?cè)谏弦粋€(gè)補(bǔ)間結(jié)束的時(shí)候立即啟動(dòng)另外一個(gè)補(bǔ)間動(dòng)畫(huà),使用 .chain() 方法來(lái)做。
//tweenB動(dòng)畫(huà)在tweenA動(dòng)畫(huà)完成后執(zhí)行 tweenA.chain(tweenB);
在一些情況下,可能需要將多個(gè)補(bǔ)間鏈接到另一個(gè)補(bǔ)間,以使它們(鏈接的補(bǔ)間)同時(shí)開(kāi)始動(dòng)畫(huà):
tweenA.chain(tweenB,tweenC);
注意:調(diào)用 tweenA.chain(tweenB) 實(shí)際上修改了tweenA,所以tweenA總是在tweenA完成時(shí)啟動(dòng)。 chain 的返回值只是tweenA,不是一個(gè)新的tween。
.getAll()方法
獲取所有的補(bǔ)間組 TWEEN.getAll()
.removeAll()方法
刪除所有的補(bǔ)間組 TWEEN.removeAll()
.add()方法
新增補(bǔ)間 TWEEN.add(tween) ,添加一個(gè)特定的補(bǔ)間 var tween=new TWEEN.Tween()
.remove()方法
刪除補(bǔ)間 TWEEN.remove(tween),刪除一個(gè)特定的補(bǔ)間var tween=new TWEEN.Tween()
.Group()方法
新增一個(gè)補(bǔ)間組,var Group=TWEEN.Group() , new TWEEN.Tween({ x: 1 }, Group) , 將已經(jīng)配置好的補(bǔ)間動(dòng)畫(huà)進(jìn)行分組 , TWEEN.update()和TWEEN.removeAll() , 不會(huì)影響到已經(jīng)分好組的補(bǔ)間動(dòng)畫(huà)
tween.js回調(diào)函數(shù)
.onStart()補(bǔ)間動(dòng)畫(huà)開(kāi)始時(shí)執(zhí)行,只執(zhí)行一次
new TWEEN.Tween().onStart((obj)=>{}) , 補(bǔ)間開(kāi)始時(shí)執(zhí)行,只執(zhí)行一次, 當(dāng)使用 repeat() 重復(fù)補(bǔ)間時(shí),不會(huì)重復(fù)運(yùn)行 ,onStart((obj)=>{}) obj 補(bǔ)間對(duì)象作為第一個(gè)參數(shù)傳入
.onStop() 停止補(bǔ)間動(dòng)畫(huà)時(shí)執(zhí)行
new TWEEN.Tween().onStop((obj)=>{}) , 當(dāng)通過(guò) onStop() 顯式停止補(bǔ)間時(shí)執(zhí)行,但在正常完成時(shí)并且在停止任何可能的鏈補(bǔ)間之前執(zhí)行補(bǔ)間,onStop((obj)=>{}) obj 補(bǔ)間對(duì)象作為第一個(gè)參數(shù)傳入
.onUpdate() 每次更新時(shí)執(zhí)行
new TWEEN.Tween().onUpdate((obj)=>{}) , 每次補(bǔ)間更新時(shí)執(zhí)行,返回實(shí)際更新后的值, onUpdate((obj)=>{}) obj 補(bǔ)間對(duì)象作為第一個(gè)參數(shù)傳入
.onComplete() 補(bǔ)間動(dòng)畫(huà)完成時(shí)執(zhí)行
new TWEEN.Tween().onComplete((obj)=>{}) , 當(dāng)補(bǔ)間正常完成(即不停止)時(shí)執(zhí)行 , onComplete((obj)=>{}) obj 補(bǔ)間對(duì)象作為第一個(gè)參數(shù)傳入
.onRepeat() 重復(fù)補(bǔ)間動(dòng)畫(huà)時(shí)執(zhí)行
new TWEEN.Tween().onRepeat((obj)=>{}) , 當(dāng)補(bǔ)間動(dòng)畫(huà)完成,即將進(jìn)行重復(fù)動(dòng)畫(huà)的時(shí)候執(zhí)行 , onComplete((obj)=>{}) `obj 補(bǔ)間對(duì)象作為第一個(gè)參數(shù)傳入
TWEEN.Easing 緩動(dòng)函數(shù)
tween.js為我們封裝好了常用的緩動(dòng)動(dòng)畫(huà),如線性,二次,三次,四次,五次,正弦,指數(shù),圓形,彈性,下落和彈跳等緩動(dòng)函數(shù)
以及對(duì)應(yīng)的緩動(dòng)類(lèi)型:In (先慢后快) ;Out (先快后慢) 和 InOut (前半段加速,后半段減速)
常見(jiàn)的緩動(dòng)動(dòng)畫(huà)如下
- Linear:線性勻速運(yùn)動(dòng)效果;
- Quadratic:二次方的緩動(dòng)(t^2);
- Cubic:三次方的緩動(dòng)(t^3);
- Quartic:四次方的緩動(dòng)(t^4);
- Quintic:五次方的緩動(dòng)(t^5);
- Sinusoidal:正弦曲線的緩動(dòng)(sin(t));
- Exponential:指數(shù)曲線的緩動(dòng)(2^t);
- Circular:圓形曲線的緩動(dòng)(sqrt(1-t^2));
- Elastic:指數(shù)衰減的正弦曲線緩動(dòng);
- Back:超過(guò)范圍的三次方緩動(dòng)((s+1)t^3 – st^2);
- Bounce:指數(shù)衰減的反彈緩動(dòng)。
- 以上每個(gè)效果都分三個(gè)緩動(dòng)類(lèi)型,分別是:
- easeIn:從0開(kāi)始加速的緩動(dòng),也就是先慢后快;
- easeOut:減速到0的緩動(dòng),也就是先快后慢;
- easeInOut:前半段從0開(kāi)始加速,后半段減速到0的緩動(dòng)。
在Threejs中使用Tween.js庫(kù)
繼續(xù)在前面章節(jié)的代碼基礎(chǔ)上進(jìn)行實(shí)現(xiàn),由于我們是基于vue開(kāi)發(fā)的,所以這里我們使用npm的方式安裝tween.js庫(kù)
在vue中安裝并引入tween.js庫(kù)
打開(kāi)控制器,輸入npm install @tweenjs/tween.js進(jìn)行安裝,在components文件夾新建TweenView.vue文件,在該文件中引入tween.jsimport * as TWEEN from '@tweenjs/tween.js'
初始化場(chǎng)景
在使用tween.js實(shí)現(xiàn)動(dòng)畫(huà)之前,先將threejs的初始化環(huán)境搭建好,并創(chuàng)建一個(gè)立方體
<template>
<div id="scene"></div>
</template>
<script setup>
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))
}
// 初始化場(chǎng)景
function initScene() {
scene = new THREE.Scene()
}
// 初始化相機(jī)
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)
}
</script>
<style scoped>
</style>
實(shí)例化Tween對(duì)象
實(shí)例化Tween對(duì)象并將物體當(dāng)前的位置作為參數(shù)傳入該對(duì)象
const tween = new TWEEN.Tween(mesh.position)
使用.to()方法指定移動(dòng)終點(diǎn)和時(shí)間
使用.to()方法指定移動(dòng)的終點(diǎn)和時(shí)間
tween.to({x:3,y:0,z:0},2000)
調(diào)用.onUpdate()方法更新動(dòng)畫(huà),
調(diào)用.onUpdate()方法更新動(dòng)畫(huà),在回調(diào)函數(shù)中設(shè)置相機(jī)的.lookAt()方法,
tween.onUpdate(function(){
camera.lookAt(0,0,0)
})
開(kāi)啟動(dòng)畫(huà)
使用.start()方法開(kāi)啟動(dòng)畫(huà)
tween.start()
刷新查看瀏覽器, 發(fā)現(xiàn)物體已經(jīng)按照我們給定的終點(diǎn)坐標(biāo)進(jìn)行了移動(dòng)

給場(chǎng)景添加地面輔助線
為了更好的看到效果,給場(chǎng)景中添加地面輔助線,定義initGridHelper()方法,在init()函數(shù)中調(diào)用
// 輔助地面
function initGridHelper () {
const gridHelper = new THREE.GridHelper(10,10)
scene.add(gridHelper)
}
使用.chain()方法對(duì)多段動(dòng)畫(huà)進(jìn)行串聯(lián)執(zhí)行
繼續(xù)對(duì)上面的物體運(yùn)動(dòng)進(jìn)行研究,我們?cè)谖矬w移動(dòng)到指定位置后,再給定一個(gè)目標(biāo)點(diǎn)位置,使其繼續(xù)移動(dòng);
新建一個(gè)tween2對(duì)象,仍然將mesh.position作為參數(shù)傳入,調(diào)用tween2.to方法,指定終點(diǎn)坐標(biāo)和時(shí)間
然后通過(guò)調(diào)用.chain()方法,將tween2作為參數(shù)傳遞給tween.chain()方法,這樣tween在執(zhí)行完第一段代碼后,會(huì)接著執(zhí)行tween2的代碼,實(shí)現(xiàn)多段動(dòng)畫(huà)的連續(xù)執(zhí)行
const tween2 = new TWEEN.Tween(mesh.position)
tween2.to({x:3,y:0,z:3},2000)
tween.chain(tween2)
tween.start()
使用tween執(zhí)行縮放動(dòng)畫(huà)
tweenjs不僅僅能實(shí)現(xiàn)移動(dòng)動(dòng)畫(huà),它能實(shí)現(xiàn)很多動(dòng)畫(huà)功能,這里我們接著上面的動(dòng)畫(huà)在物體移動(dòng)到tween2指定的終點(diǎn)時(shí),再對(duì)齊進(jìn)行一個(gè)縮放動(dòng)畫(huà)
我們先定義一個(gè)對(duì)象,里面給一個(gè)參數(shù)s為1,代表當(dāng)前的縮放比例是1
const scaleParam = { s:1}
我們創(chuàng)建一個(gè)新的tween3對(duì)象然后我們創(chuàng)建一個(gè)新的tween3對(duì)象,將上面的scaleParam 作為參數(shù)傳入
const tween3 = new TWEEN.Tween(scaleParam)
調(diào)用.to方法調(diào)用tween3.to()方法,將對(duì)象s設(shè)置為10,時(shí)間設(shè)置為2000
tween3.to({s:10},2000)
調(diào)用.onUpdate()方法調(diào)用.onUpdate()方法,在.onUpdate()方法的回調(diào)函數(shù)中設(shè)置mesh在x軸的縮放值為s
tween3.onUpdate(function(){
mesh.scale.x = scaleParam.s
})
調(diào)用.chain()方法調(diào)用tween2.chain()方法,將tween3作為參數(shù)傳入,表示tween2動(dòng)畫(huà)執(zhí)行完后執(zhí)行tween3動(dòng)畫(huà)
tween2.chain(tween3) tween.start()
刷新瀏覽器,可以看到物體按照我們預(yù)期的效果實(shí)現(xiàn)了動(dòng)畫(huà)

使用緩動(dòng)動(dòng)畫(huà)
使用緩動(dòng)動(dòng)畫(huà)可以是我們的動(dòng)畫(huà)看起來(lái)更真實(shí)自然,前面講過(guò),tweenjs已經(jīng)為我們封裝了常見(jiàn)的緩動(dòng)動(dòng)畫(huà),我們使用使只需要調(diào)用就可以了,常見(jiàn)的緩動(dòng)動(dòng)畫(huà)曲線如下圖所示

給立方體運(yùn)動(dòng)的動(dòng)畫(huà)添加緩動(dòng)動(dòng)畫(huà)我們可以給上面的立方體添加緩動(dòng)動(dòng)畫(huà),使其看起來(lái)更真實(shí),我們?cè)诹⒎襟w的第一段動(dòng)畫(huà)(tween)和第二段動(dòng)畫(huà)(tween2)時(shí)讓其先快后慢
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()
刷新瀏覽器看效果,符合我們的要求

好了,關(guān)于tweenjs和threejs結(jié)合創(chuàng)建動(dòng)畫(huà)就先說(shuō)到這里,其實(shí)關(guān)于tween和threejs結(jié)合的動(dòng)畫(huà)還有很多,比如可以結(jié)合tween實(shí)現(xiàn)物體顏色的變化、透明度的變化等,具體各位小伙伴可以自己摸索。
總結(jié)
到此這篇關(guān)于Threejs與Tween.js結(jié)合創(chuàng)建動(dòng)畫(huà)的文章就介紹到這了,更多相關(guān)Threejs與Tween.js創(chuàng)建動(dòng)畫(huà)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript將數(shù)組轉(zhuǎn)換為鏈表的方法
這篇文章主要介紹了JavaScript將數(shù)組轉(zhuǎn)換為鏈表的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
java前端javascript生成動(dòng)態(tài)表格示例演示
這篇文章主要為大家介紹了java前端javascript生成動(dòng)態(tài)表格的實(shí)現(xiàn)示例及演示,2022-03-03
微信小程序用swiper實(shí)現(xiàn)滑動(dòng)刻度尺
這篇文章主要為大家詳細(xì)介紹了微信小程序用swiper實(shí)現(xiàn)滑動(dòng)刻度尺,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
Javascript隨機(jī)標(biāo)簽云代碼實(shí)例
這篇文章主要分享一個(gè)Javascript隨機(jī)標(biāo)簽云代碼實(shí)例,需要的朋友可以參考下。2016-06-06
JS實(shí)現(xiàn)三個(gè)層重疊點(diǎn)擊互相切換的方法
這篇文章主要介紹了JS實(shí)現(xiàn)三個(gè)層重疊點(diǎn)擊互相切換的方法,涉及JavaScript動(dòng)態(tài)操作頁(yè)面定位屬性的相關(guān)技巧,需要的朋友可以參考下2015-10-10

