three.js 缓动算法.easing(渐入相机动画)

效果:淡入,靠近物体

代码:

<template><div><el-container><el-main><div class="box-card-left"><div id="threejs" style="border: 1px solid red"></div><div class="box-right"><el-button type="primary" @click="lookFor('设备A')">设备A</el-button><el-button type="primary" @click="lookFor('设备B')">设备B</el-button><el-button type="primary" @click="lookAll">整体</el-button><el-button type="primary" @click="saveImg">保存图片</el-button></div></div></el-main></el-container></div>
</template>
<script>
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import TWEEN from "@tweenjs/tween.js";export default {data() {return {scene: null,camera: null,renderer: null,mesh: null,geometry: null,group: null,material: null,clock: null,mixer: null,};},created() {},mounted() {this.name = this.$route.query.name;this.init();// 监听点击事件this.addClickEventListener();},methods: {goBack() {this.$router.go(-1);},init() {// 创建场景对象this.scene = new this.$three.Scene();this.group = new this.$three.Group();this.createMesh({x: 50,y: 50,z: 50,name: "设备A",});this.createMesh({x: -50,y: 50,z: 50,name: "设备B",});this.scene.add(this.group);const axesHelper = new this.$three.AxesHelper(150);this.scene.add(axesHelper);// 创建环境光对象const ambientLight = new this.$three.AmbientLight(0xffffff);this.scene.add(ambientLight);// 创建相机对象this.camera = new this.$three.PerspectiveCamera();this.camera.position.set(300, 300, 300);this.camera.lookAt(0, 0, 0);// 创建渲染器对象this.renderer = new this.$three.WebGLRenderer({preserveDrawingBuffer: true, // 把画布内容保存为图片时,需要设置为true});this.renderer.setSize(1000, 800);this.renderer.render(this.scene, this.camera);window.document.getElementById("threejs").append(this.renderer.domElement);// 创建相机空间轨道控制器对象this.controls = new OrbitControls(this.camera, this.renderer.domElement);this.controls.addEventListener("change", () => {this.renderer.render(this.scene, this.camera);console.log(" this.camera.position",this.camera.position.x,this.camera.position.y,this.camera.position.z);});},// 创建网格模型的方法createMesh(obj) {// 创建立方缓冲几何体对象const geometry = new this.$three.BoxGeometry(obj.x, obj.y, obj.z);// 创建材质对象const material = new this.$three.MeshLambertMaterial({color: this.randomColor(),transparent: true,//开启透明计算opacity: 0.0//完全透明});const mesh = new this.$three.Mesh(geometry, material);mesh.position.set(obj.x, obj.y, obj.z);mesh.name = obj.name;if (this.group) {this.group.add(mesh);}},lookFor(name) {if (this.scene && this.scene.getObjectByName(name)) {// 通过 getObjectByName() 方法获取name为设备A的模型const equipment_A = this.scene.getObjectByName(name);// 创建Vector3类型的位置对象const position = new this.$three.Vector3();// 获取设置A的世界坐标并赋值到position对象中equipment_A.getWorldPosition(position);// 向量x,y,z坐标值在position的基础上增加50,const position_scalar = position.clone().addScalar(100);// 创建TWEEN对象并调用Tween方法new TWEEN.Tween({x: this.camera.position.x,y: this.camera.position.y,z: this.camera.position.z,px: this.controls.target.x,py: this.controls.target.y,pz: this.controls.target.z,opacity: equipment_A.material.opacity//完全透明}).to({x: position_scalar.x,y: position_scalar.y,z: position_scalar.z,px: equipment_A.position.x,py: equipment_A.position.y,pz: equipment_A.position.z,opacity: 1.0},3000).onUpdate((obj) => {// 设置相机位置this.camera.position.set(obj.x, obj.y, obj.z);// 设置控制器指向this.controls.target.set(obj.px, obj.py, obj.pz);// 更新控制器this.controls.update();equipment_A.material.opacity = obj.opacity;}).onComplete(obj => {equipment_A.material.transparent = false;}).start().easing(TWEEN.Easing.Sinusoidal.InOut); //使用二次缓动函数;/**easing()语法格式* // easing函数:缓动算法(运动效果)// easing类型:定义缓动算法起作用地方tween.easing(TWEEN.Easing.easing函数.easing类型); // easing类型  In , Out , InOutLinear:默认效果可以不设置,可以理解为没有加速过程直接进入匀速状态,或者说没有减速过程,直接刹车Quadratic:二次方的缓动(t^2)Cubic:三次方的缓动(t^3)Quartic:四次方的缓动(t^4)Quintic:五次方的缓动(t^5)Sinusoidal:正弦曲线的缓动(sin(t))Exponential:指数曲线的缓动(2^t)启动非常慢,后面快Circular:圆形曲线的缓动(sqrt(1-t^2))会有弹性衰减往复运动感Elastic:指数衰减的正弦曲线缓动;TWEEN.Easing.Elastic.inout 会有弹性衰减往复运动感Back:超过范围的三次方缓动((s+1)*t^3 – s*t^2)会有弹性衰减往复运动感Bounce:指数衰减的反弹缓动。会有弹性衰减往复运动感*  */this.loop();}},loop() {this.renderer.render(this.scene, this.camera);TWEEN.update();window.requestAnimationFrame(this.loop);},lookAll() {/*** 查看整体的思路:* 用包围盒 Box3, 将场景中所有的模型包裹起来,计算出* (box3.min.x + box.max.x) / 2 = centerX* (box.min.y + box.max.y) / 2 = centerY* (box.min.z + box.max.z) / 2 = centerZ* , 计算出 centerX, centerY, centerZ  整体的中心坐标,*  为了显示包围盒的边界,可以使用Box3Helper辅助对象;* 相机的位置position要从当前位置定位到**  */// 创建包围盒对象const box3 = new this.$three.Box3();// 设置包围盒中的对象const groupBox = box3.expandByObject(this.group);console.log(groupBox);const box3Helper = new this.$three.Box3Helper(box3, 0xffffff);this.scene.add(box3Helper);let max_x = groupBox.max.x;let max_y = groupBox.max.y;let max_z = groupBox.max.z;let min_x = groupBox.min.x;let min_y = groupBox.min.y;let min_z = groupBox.min.z;let center_x = (max_x + min_x) / 2;let center_y = (max_y + min_y) / 2;let center_z = (max_z + min_z) / 2;//let increment_x =Math.abs(max_x) > Math.abs(min_x) ? Math.abs(max_x) : Math.abs(min_y);let increment_y =Math.abs(max_y) > Math.abs(min_y) ? Math.abs(max_y) : Math.abs(min_y);let increment_z =Math.abs(max_z) > Math.abs(min_z) ? Math.abs(max_z) : Math.abs(min_z);new TWEEN.Tween({x: this.camera.position.x,y: this.camera.position.y,z: this.camera.position.z,px: this.controls.target.x,py: this.controls.target.y,pz: this.controls.target.z,}).to({x: center_x + increment_x * 2,y: center_y + increment_y * 2,z: center_z + increment_z * 2,px: center_x,py: center_y,pz: center_z,},1200).onUpdate((obj) => {this.camera.position.set(obj.x, obj.y, obj.z);this.controls.target.set(obj.px, obj.py, obj.pz);this.controls.update();}).start();this.loop();},saveImg() {const link = document.createElement("a");const canvas = this.renderer.domElement;link.href = canvas.toDataURL("image/png");link.download = "threejs.png";link.click();},randomColor() {const numbers = Array.from({ length: 255 }, (_, i) => i);const color = [...numbers];// 要生成min-max之间的随机数,公式为:Math.random()*(max-min+1)+minlet i = Math.floor(Math.random() * (color.length - 0 + 1) + 0);let j = Math.floor(Math.random() * (color.length - 0 + 1) + 0);let k = Math.floor(Math.random() * (color.length - 0 + 1) + 0);return new this.$three.Color("rgb(" + i + ", " + j + ", " + k + ")");},// 在canvas画布上添加监听点击的事件addClickEventListener() {// 获取id 是 threejs 的元素;const dom = window.document.getElementById("threejs");const canvasWidth = dom.clientWidth; // 获取元素的宽度const canvasHeight = dom.clientHeight; // 获取元素的高度dom.addEventListener("click", (e) => {const x = e.offsetX; // 获取鼠标当前点击的点距离dom元素左上角原点  在x轴方向上的距离const y = e.offsetY; // 获取鼠标当前点击的点距离dom元素左上角原点  在y轴方向上的距离console.log(x, y);// 由于canvas画布上的坐标值与普通2d页面的坐标值是不一样的;// 在canvas画布上的坐标轴是以画布的中心点为原点,左右x轴,值 -1 ~ 1,,上下y轴,值-1 ~ 1;// 坐标需要进行坐标转换const pos_x = (x / canvasWidth) * 2 - 1; // 转换后的x坐标const pos_y = -(y / canvasHeight) * 2 + 1; // 转换后的y坐标// 创建射线投射器对象(可以在初始化方法中创建,每次点击时创建有些浪费资源)const rayCaster = new this.$three.Raycaster();// 计算射线(在点击位置创建一条射线,用来拾取模型对象)rayCaster.setFromCamera(new this.$three.Vector2(pos_x, pos_y),this.camera);const mesh_list = [];// traverse 是threejs中的递归遍历方法;找出group中的meshthis.group.traverse((obj) => {if (obj.isMesh) {mesh_list.push(obj);}});// 射线交叉计算(计算出与自身射线相交的网格模型)const intersects = rayCaster.intersectObjects(mesh_list);if (intersects && intersects.length > 0) {console.log(intersects[0]);this.lookFor(intersects[0].object.name);}});},},
};
</script>
//
<style lang="less" scoped>
.box-card-left {display: flex;align-items: flex-start;flex-direction: row;width: 100%;.box-right {img {width: 500px;user-select: none;}}
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于网络爬虫的天气数据分析

二、网络爬虫设计 网络爬虫原理 网络爬虫是一种自动化程序&#xff0c;用于从互联网上获取数据。其工作原理可以分为以下几个步骤&#xff1a; 定义起始点&#xff1a;网络爬虫首先需要定义一个或多个起始点&#xff08;URL&#xff09;&#xff0c;从这些起始点开始抓取数据…

Spring | Spring中的Bean--下

Spring中的Bean: 4.Bean的生命周期5.Bean的配装配式 ( 添加Bean到IOC容器的方式 依赖注入的方式 )5.1 基于XML的配置5.2 基于Annotation (注解) 的装配 (更常用&#xff09;5.3 自动装配 4.Bean的生命周期 Spring容器可以管理 singleton作用域的Bean的生命周期&#xff0c;在此…

DBA技术栈(三):MySQL 性能影响因素

文章目录 前言一、影响MySQL性能的因素1.1 商业上的需求1.2 应用架构规划1.3 查询语句使用方式1.4 Schema的设计1.5 硬件环境 总结 前言 大部分人都一致认为一个数据库应用系统&#xff08;这里的数据库应用系统概指所有使用数据库的系统&#xff09;的性能瓶颈最容易出现在数…

Go 中 slice 的 In 功能实现探索

文章目录 遍历二分查找map key性能总结 之前在知乎看到一个问题&#xff1a;为什么 Golang 没有像 Python 中 in 一样的功能&#xff1f;于是&#xff0c;搜了下这个问题&#xff0c;发现还是有不少人有这样的疑问。 补充&#xff1a;本文写于 2019 年。GO 现在已经支持泛型&am…

TDengine 企业级功能:存储引擎对多表低频场景优化工作分享

在去年 8 月份发布的 3.1.0.0 版本中&#xff0c;TDengine 进行了一系列重要的企业级功能更新&#xff0c;其中包括对多表低频场景写入性能的大幅优化。这一优化工作为有此需求的用户提供了更大的便捷性和易用性。在本文中&#xff0c;TDengine 的资深研发将对此次优化工作进行…

Spring-BeanPostProcessor PostConstruct init InitializingBean 执行顺序

执行顺序探究 新建一个对象用于测试 Component public class Student implements InitializingBean {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}pu…

从matlab的fig图像文件中提取数据

这里用的是openfig&#xff08;&#xff09;函数打开的fig文件 →→→【matlab 中 fig 数据提取】 很简洁 →→→【MATLAB提取 .fig 文件中的数据】 这个给出了包含多个曲线的情况 →→→【提取matlab fig文件里的数据和legend】 chatgpt给出的方法 打开fig文件并保存数据 我的…

《Python数据分析技术栈》第01章 02 Jupyter入门(Getting started with Jupyter notebooks)

02 Jupyter入门&#xff08;Getting started with Jupyter notebooks&#xff09; 《Python数据分析技术栈》第01章 02 Jupyter入门&#xff08;Getting started with Jupyter notebooks&#xff09; Before we discuss the essentials of Jupyter notebooks, let us discuss…

Java JVM 堆、栈、方法区详解

目录 1. 栈 2. 堆 3. 方法区 4. 本地方法栈 5. 程序计数器 首先来看一下JVM运行时数据区有哪些。 1. 栈 在介绍JVM栈之前&#xff0c;先了解一下 栈帧 概念。 栈帧&#xff1a;一个栈帧随着一个方法的调用开始而创建&#xff0c;这个方法调用完成而销毁。栈帧内存放者方…

Java导出Excel并合并单元格

需求&#xff1a;需要在导出excel时合并指定的单元格 ruoyi excel 项目基于若伊框架二次开发&#xff0c;本着能用现成的就不自己写的原则&#xff0c;先是尝试了Excel注解中needMerge属性 /*** 是否需要纵向合并单元格,应对需求:含有list集合单元格)*/public boolean needMer…

VsCode + CMake构建项目 C/C++连接Mysql数据库 | 数据库增删改查C++封装 | 信息管理系统通用代码 ---- 课程笔记

这个是B站Up主&#xff1a;程序员程子青的视频 C封装Mysql增删改查操作_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1m24y1a79o/?p6&spm_id_frompageDriver&vd_sourcea934d7fc6f47698a29dac90a922ba5a3安装mysql:mysql 下载和安装和修改MYSQL8.0 数据库存储…

小封装高稳定性振荡器 Sg2520egn / sg2520vgn, sg2520ehn / sg2520vhn

描述 随着物联网和ADAS等5G应用的实施&#xff0c;数据流量不断增长&#xff0c;网络基础设施变得比以往任何时候都更加重要。IT供应商一直在快速建设数据中心&#xff0c;并且对安装在数据中心内部/内部的光模块有很大的需求。此应用需要具有“小”&#xff0c;“低抖动”和“…