Tween.js在Three.js中的应用:为3D动画添加流畅过渡

前言

Web开发领域,Three.js已经成为构建精彩3D内容的首选库之一。它让开发者能够轻松地在浏览器中创建和展示复杂的3D场景。然而,要让这些场景栩栩如生,平滑的动画效果是必不可少的。这就引入了Tween.js——一个轻量级但功能强大的JavaScript库,专门用于在Web应用中创建平滑的补间动画。本文将探讨如何在Three.js项目中集成并利用Tween.js来增强3D对象的动画表现。

简介

Tween.js 是一个简单易用的库,专注于数值的平滑插值(interpolation),非常适合于实现动画效果。无论是简单的颜色渐变、对象位置移动,还是复杂的序列动画,Tween.js都能轻松应对。在与Three.js结合时,它能显著提升3D场景的互动性和视觉吸引力。

安装Tween.js

官方地址为:https://github.com/tweenjs/tween.js

npm install tween.js

当然three.js包中自带的包含tween.js,其中three.js得tween地址为:node_moduls>three>examples>jsm>libs>tween.module.js

导入补间动画

import * as TWEEN from 'three/examples/jsm/libs/tween.module.js'

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 (前半段加速,后半段减速)
Tween.js在Three.js中的应用:为3D动画添加流畅过渡

常见缓动动画

  1. Linear:线性匀速运动效果;
  2. Quadratic:二次方的缓动(t^2)
  3. Cubic:三次方的缓动(t^3)
  4. Quartic:四次方的缓动(t^4)
  5. Quintic:五次方的缓动(t^5)
  6. Sinusoidal:正弦曲线的缓动(sin(t))
  7. Exponential:指数曲线的缓动(2^t)
  8. Circular:圆形曲线的缓动(sqrt(1-t^2))
  9. Elastic:指数衰减的正弦曲线缓动;
  10. Back:超过范围的三次方缓动((s+1)t^3 – st^2)
  11. Bounce:指数衰减的反弹缓动。

以上每个效果都分三个缓动类型,分别是:
easeIn:从0开始加速的缓动,也就是先慢后快;
easeOut:减速到0的缓动,也就是先快后慢;
easeInOut:前半段从0开始加速,后半段减速到0的缓动。

Tween.JS和Three.js示例

Tween.js在Three.js中的应用:为3D动画添加流畅过渡

  1. 导入动画组件库
import * as TWEEN from "three/examples/jsm/libs/tween.module.js"
  1. 创建一个圆柱几何
const sphere1 =  new THREE.Mesh(
new THREE.CylinderGeometry(1, 1, 1, 64),
  new THREE.MeshBasicMaterial( {color: 0xffff00} )
)
sphere1.position.set(0, 10, 0)
sphere1.position.x = 0      
sphere1.position.y = 0      
sphere1.position.z = 0
sphere1.scale.set(-1, -1, 1) 
sphere1.rotation.z = -Math.PI/2 
this.scene.add(sphere1)
  1. 创建tween实例和tween动画
const tween = new TWEEN.Tween(sphere1.position)      
const tweenXZ = new TWEEN.Tween(sphere1.rotation)
const tween2 = new TWEEN.Tween(sphere1.position)
const tween3 = new TWEEN.Tween(sphere1.position)
const tween4 = new TWEEN.Tween(sphere1.position)
//移动
tween.to({x:4},300).onUpdate(()=>{})
//旋转
tweenXZ.to({y:-Math.PI/2},150).onUpdate(()=>{})
//移动
tween2.to({y:-4},300).onUpdate(()=>{})
//移动
tween3.to({x:0},300).onUpdate(()=>{})
//移动
tween4.to({y:0},300).onUpdate(()=>{})
// 一边移动一边旋转,动画在tween动画完成后执行tween2,并带有旋转效果
tween.chain(tween2,tweenXZ)
tween2.chain(tween3,tweenXZ)
tween3.chain(tween4,tweenXZ)      
tween4.chain(tween,tweenXZ)

  1. 设置动画速度运行曲线
tween.easing(TWEEN.Easing.Quadratic.Inout) 
  1. 开启动画
 tween.start()

  1. 开启动画后还不能完全动起来,还需要逐帧更新动画
 animate() {
      this.controls.update()
      TWEEN.update()
      requestAnimationFrame( this.animate );
      this.renderer.render( this.scene, this.camera );
    }

完整代码:

<template>
  <div id="container">
    
  </div>
</template>

<script>
import * as THREE from 'three'
// webGL兼容
import WebGL from 'three/examples/jsm/capabilities/WebGL.js';
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
// 轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"
//导入RGBRload加载器
import { RGBELoader } from  "three/examples/jsm/loaders/RGBELoader.js"
//导入场景模型加载器
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader.js"
//导入模型解压器
import {DRACOLoader} from "three/examples/jsm/loaders/DRACOLoader.js"
//导入Tween动画组件库
import * as TWEEN from "three/examples/jsm/libs/tween.module.js"
export default {
  name: 'Three9',
  components: {
  },
  mounted(){
    this.init()
  },
  data(){
    return {
      camera: null,  //相机对象
      scene: null,  //场景对象
      renderer: null,  //渲染器对象
      mesh: null,  //网格模型对象Mesh
      mesh2:null,
      controls:null, //轨道控制器
      material2:null, //父元素
      planeMesh:null, //平面
      rgbeLoacer:null,
    }
  },
  methods:{
    //随机生成十六进制颜色
    color16(){//十六进制颜色随机
			var r = Math.floor(Math.random()*256);
			var g = Math.floor(Math.random()*256);
			var b = Math.floor(Math.random()*256);
			var color = '#'+r.toString(16)+g.toString(16)+b.toString(16);
			return color;
    },
    init(){
      let container = document.body;
      //创建一个场景
      this.scene = new THREE.Scene()
      //透视摄像机
      this.camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,700)
      //创建渲染器
      this.renderer = new THREE.WebGLRenderer();
      //渲染器尺寸
      this.renderer.setSize( window.innerWidth,  window.innerHeight );    
      
      // 创建三个球
      const sphere1 =  new THREE.Mesh(
        new THREE.CylinderGeometry(1, 1, 1, 64),
        new THREE.MeshBasicMaterial( {color: 0xffff00} )
      )
      sphere1.position.set(0, 10, 0)
      sphere1.position.x = 0      
      sphere1.position.y = 0      
      sphere1.position.z = 0
      sphere1.scale.set(-1, -1, 1) 
      sphere1.rotation.z = -Math.PI/2 
      this.scene.add(sphere1)
      const tween = new TWEEN.Tween(sphere1.position)      
      const tweenXZ = new TWEEN.Tween(sphere1.rotation)
      const tween2 = new TWEEN.Tween(sphere1.position)
      const tween3 = new TWEEN.Tween(sphere1.position)
      const tween4 = new TWEEN.Tween(sphere1.position)
      //移动
      tween.to({x:4},300).onUpdate(()=>{})
      //旋转
      tweenXZ.to({y:-Math.PI/2},150).onUpdate(()=>{})
      //移动
      tween2.to({y:-4},300).onUpdate(()=>{})
      //移动
      tween3.to({x:0},300).onUpdate(()=>{})
      //移动
      tween4.to({y:0},300).onUpdate(()=>{})
      // 一边移动一边旋转,动画在tween动画完成后执行tween2,并带有旋转效果
      tween.chain(tween2,tweenXZ)
      tween2.chain(tween3,tweenXZ)
      tween3.chain(tween4,tweenXZ)      
      tween4.chain(tween,tweenXZ)
      //动画运行速度曲线
      tween.easing(TWEEN.Easing.Quadratic.Inout) 
      tween.start()
      this.scene.background=new THREE.Color(0x999999)
      // 设置相机位置
      this.camera.position.z = 15;   
      this.camera.position.y =2;  
      this.camera.position.x = 2; 
      // 看的方向 
      this.camera.lookAt(0,0,0)
      //添加世界坐标辅助器
      const axesHelper = new THREE.AxesHelper(3) 
      this.scene.add( axesHelper );
      //添加轨道控制器
      this.controls = new OrbitControls(this.camera,this.renderer.domElement)
      //添加阻尼带有惯性
      this.controls.enableDamping = true
      //设置阻尼系数
      this.controls.dampingFactor = 0.05
      //元素中插入canvas对象
      container.appendChild(this.renderer.domElement); 
      if ( WebGL.isWebGLAvailable() ) {
        this.animate();
      } else {
        const warning = WebGL.getWebGLErrorMessage();
        document.getElementById( document.body ).appendChild( warning );
      }
    },
    //旋转起来
    animate() {
      this.controls.update()
      TWEEN.update()
      requestAnimationFrame( this.animate );
      this.renderer.render( this.scene, this.camera );
    }
  }
}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/674210.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis核心对象

MyBatis核心类对象主要有俩个&#xff1a; 1&#xff1a;对相关配置文件信息进行封装的Configuration对象 2&#xff1a;用来执行数据库操作的Executor对象。 核心对象----存储类对象Configuration Configuration对象主要有三个作用&#xff1a; 1&#xff1a;封装MyBatis…

linux进程加载和启动过程分析

我们的源代码通过预处理,编译,汇编,链接后形成可执行文件,那么当我们在终端敲下指令$ ./a.out argv1 argv2 后,操作系统是怎么将我们的可执行文件加载并运行的呢? 首先知道,计算机的操作系统的启动程序是写死在硬件上的,每次计算机上电时,都将自动加载启动程序,之后…

R语言数据分析-针对芬兰污染指数的分析与考察

1. 研究背景及意义 近年来&#xff0c;随着我国科技和经济高速发展&#xff0c;人们生活质量也随之显著提高。但是&#xff0c; 环境污染问题也日趋严重&#xff0c;给人们的生活质量和社会生产的各个方面都造成了许多不 利的影响。空气污染作为环境污染主要方面&#xff0c;更…

重生之我要精通JAVA--第七周笔记

文章目录 IO流字符流字符流原理解析flush和close方法 文件拷贝代码文件加密解密修改文件中的数据 缓冲流字节缓冲流字符缓冲流例题 转换流序列化流序列化流/对象操作输出流 反序列化流序列化流/反序列化流的细节汇总打印流字节打印流字符打印流 解压缩流压缩流Commons-io常见方…

代码随想录--哈希表--两数之和

题目 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素不能使用两遍。 示例: 给定 nums [2, 7, 11, 15], t…

【RuoYi】如何解决Postman无法访问RuoYi中的接口数据

一、前言 最近&#xff0c;写项目要求需要将数据返回&#xff0c;指定的接口&#xff0c;并且需要使用Postman来测试接口数据&#xff0c;看是否能够请求到数据。然后项目用的是RuoYi的框架&#xff0c;RuoYi使用了SpringSecurity来做的安全框架&#xff0c;所以在访问的时候&a…

【C语言】编译与链接:深入理解程序构建过程

&#x1f525;引言 本篇将深入理解程序构建过程&#xff0c;以便于我们在编写程序的过程同时&#xff0c;理解底层是如何从程序的创建到生成可执行程序的。 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专…

django使用fetch上传文件

在上一篇文章中&#xff0c;我包装了fetch方法&#xff0c;使其携带cookie。但是之前fetch传递的是json数据&#xff0c;现在有了一个上传文件的需求&#xff0c;因此需要进行修改&#xff1a; const sendRequest (url, method, data) > {const csrftoken Cookies.get(cs…

【Effective Python教程】(90个有效方法)笔记——第1章:培养pythonic思维——7:尽量用enumerate取代range

文章目录 第1章&#xff1a;培养pythonic思维第7条 尽量用enumerate取代range&#xff08;移位操作、位掩码&#xff09;要点enumerate函数可以用简洁的代码选代iterator&#xff0c;而且可以指出当前这轮循环的序号。不要先通过range指定下标的取值范围&#xff0c;然后用下标…

Linux eBPF:网络、系统监控和安全领域的创新

扩展 Berkeley Packet Filter&#xff08;eBPF&#xff09;是Linux内核中的一项强大技术&#xff0c;最初用于网络数据包过滤。随着时间的推移&#xff0c;eBPF的功能和应用场景不断扩展&#xff0c;如今已成为网络、系统监控和安全等领域的重要工具。eBPF可以在Linux内核中安全…

Halcon 双相机标定与拼图(一)

二、算子解释 get_calib_data camera-pose 获得基于第一个相机的第二个相机的Pose get_calib_data (CalibDataID, camera, 1, pose, RelPose2) *relative 相对 * To get the absolute pose of the second camera, its relative pose needs * to be inverted and combined…

2024 cicsn magicvm

文章目录 参考检查逆向vm::runvm::vmvm_alu::set_inputvm_mem::set_inputvm_id::runvm_alu::runvm_mem::run 漏洞思路参考的exp 参考 https://forum.butian.net/share/3048 https://akaieurus.github.io/2024/05/20/2024%E5%9B%BD%E8%B5%9B%E5%88%9D%E8%B5%9Bpwn-wp/#SuperHea…

【Nacos_bugs】java.lang.IllegalStateException: Failed to load ApplicationContext

报错原因 找不到配置文件。 Bug 排查 如果使用 Nacos 管理配置文件&#xff0c;需要检查本地 bootstrap.yml 配置是否出现问题&#xff1a; 检查点&#xff1a; 检查 Nacos 服务的地址有没有配置错误&#xff0c;如上图 ①&#xff0c;格式严格为 IP:端口号" 检查 D…

Mongodb的数据库简介、docker部署、操作语句以及java应用

Mongodb的数据库简介、docker部署、操作语句以及java应用 本文主要介绍了mongodb的基础概念和特点&#xff0c;以及基于docker的mongodb部署方法&#xff0c;最后介绍了mongodb的常用数据库操作语句&#xff08;增删改查等&#xff09;以及java下的常用语句。 一、基础概念 …

WebPack插件实现:打包之后自动混淆加密JS文件

在WebPack中调用JShaman&#xff0c;实现对编译打包生成的JS文件混淆加密 一、插件实现 1、插件JShamanObfuscatorPlugin.js&#xff0c;代码&#xff1a; class JShamanObfuscatorPlugin { apply(compiler) { compiler.hooks.emit.tapAsync(JShamanObfuscatorPlugin, (comp…

【Python网络爬虫】详解python爬虫中正则表达式、BeautifulSoup和lxml数据解析

&#x1f517; 运行环境&#xff1a;PYTHON &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

SpringMVC日期格式处理 分页条件查询

实现日期格式处理 实现分页条件查询&#xff1a; 分页条件查询 和 查询所有 是两个不同的方法&#xff0c;使用同一个mapper的查询功能&#xff0c;但是两个不同的业务方法 ​​​​​​​

2024年5月2日 Go生态洞察:Go 1.22中的安全随机性

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a;…

切勿大意!痉挛性斜颈治疗中的三个重要“禁忌”,后果堪忧!

今天&#xff0c;要给大家讲一个非常重要的话题——痉挛性斜颈的治疗。痉挛性斜颈是一种常见的神经肌肉疾病&#xff0c;患者在日常生活中可能会遇到许多困扰和不便。因此&#xff0c;及早治疗对患者来说至关重要。 然而&#xff0c;在治疗痉挛性斜颈的过程中&#xff0c;千万切…

计算机网络学习实践:模拟RIP动态路由

计算机网络学习实践&#xff1a;模拟RIP动态路由 模拟动态路由RIP协议 1.实验准备 实验环境&#xff1a;华为模拟器ENSP 实验设备&#xff1a; 3个路由器&#xff0c;3个二层交换机&#xff08;不是三层的&#xff09;&#xff0c;3个PC机 5个网段 192.168.1.0 255.255.…