three.js 点按钮,相机飞行靠近观察设备

news2024/11/28 23:10:51

效果: 

 代码:

<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="lookCar">停车场</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();
  },
  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()
      });
      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,
        }).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,
        }, 1000).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();
      }
      console.log(this.group);
    },
    loop() {
      this.renderer.render(this.scene, this.camera);
      TWEEN.update();
      window.requestAnimationFrame(this.loop);
    },
    lookCar(){},
    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)+min
        let 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 +
            ")"
        );
    },
    
  },
};
</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.coloradmin.cn/o/1392298.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

unable to create new native thread 问题处理

目录 unable to create new native thread 问题处理一、背景二、该问题产生可能原因三、处理过程3.1 确认内存是否不足3.2 确认机器线程数达到限制 四、总结 unable to create new native thread 问题处理 一、背景 生产实时集群部分节点的部分任务失败触发自动重启&#xff…

Unity之铰链关节和弹簧组件

《今天闪电侠他回来了&#xff0c;这一次他要拿回属于他的一切》 目录 &#x1f4d5;一、铰链关节组件HingeJoint 1. 实例 2. 铰链关节的坐标属性 ​3.铰链关节的马达属性Motor &#x1f4d5;二、弹簧组件 &#x1f4d5;三、杂谈 一、铰链关节组件HingeJoint 1. 实例 说…

基于Mapbox的Mvt矢量瓦片集成实践

目录 前言 一、数据说明 1、基本数据 2、属性数据 二、Mapbox集成Mvt矢量瓦片 1、关于访问令牌 2、定义html 3、初始地图 4、加载矢量瓦片 5、效果展示 总结 前言 熟悉矢量瓦片的朋友一定知道&#xff0c;在Webgis当中&#xff0c;矢量瓦片的格式除了pbf的格式&#x…

SuperPoint和SuperGlue 的算法介绍及学习应用经验分享

这里写目录标题 I.SuperPoint和SuperGIue的背景介绍特征点提取和匹配特征点的构成基于神经网络的方法优化方向一&#xff1a;增强特征点检测和描述子生成优化方向二&#xff1a;增强匹配和外点去除策略 背景和效果神经网络真的优于传统方案吗&#xff1f;DEMO演示为什么研究 2.…

Servlet系列:两种创建方式(xml,注解)

一、使用web.xml的方式配置&#xff08;Servlet2.5之前使用&#xff09; 在早期版本的Java EE中&#xff0c;可以使用XML配置文件来定义Servlet。在web.xml文件中&#xff0c;可以定义Servlet的名称、类名、初始化参数等。然后&#xff0c;在Java代码中实现Servlet接口&#x…

LeetCode、2336. 无限集中的最小数字(中等,小顶堆)

文章目录 前言LeetCode、2336. 无限集中的最小数字题目链接及类型思路代码题解 前言 博主所有博客文件目录索引&#xff1a;博客目录索引(持续更新) LeetCode、2336. 无限集中的最小数字 题目链接及类型 题目链接&#xff1a;2336. 无限集中的最小数字 类型&#xff1a;数据…

解析HTTP响应的状态码和头部信息

HTTP响应是客户端与服务器之间通信的重要部分。它包含了服务器对客户端请求的回应&#xff0c;以及与该响应相关的各种信息。在HTTP响应中&#xff0c;有两个关键部分&#xff1a;状态码和头部信息。 状态码 状态码是HTTP响应的第一部分&#xff0c;它是一个三位数字的代码&a…

【AI】RTX2060 6G Ubuntu 22.04.1 LTS (Jammy Jellyfish) 部署Chinese-LLaMA-Alpaca-2

下载源码 cd ~/Downloads/ai git clone --depth1 https://gitee.com/ymcui/Chinese-LLaMA-Alpaca-2 创建venv python3 -m venv venv source venv/bin/activate安装依赖 pip install -r requirements.txt 已安装依赖列表 (venv) yeqiangyeqiang-MS-7B23:~/Downloads/ai/Chi…

CCF认证+蓝桥杯习题训练

贪心 *上取整公式* *代码展示* #include <iostream> #include <cstring> #include <algorithm>using namespace std;const int N 1e5 10;typedef long long LL;int v[N] , a[N];int main() {int n , d;cin >> n >> d;for(int i 1 ; i < n…

oracle19C之grant语句

官网地址&#xff1a;GRANT 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 授予 目的 使用GRANT 致赠款声明: 用户和角色的系统权限。 表18-1 列出系统权限(由操作的数据库对象组织)。 注意ANY 例如,系统特权,SEL…

Spring5深入浅出篇:Spring与工厂设计模式简介

Spring5深入浅出篇:Spring与工厂设计模式简介 什么是Spring Spring是⼀个轻量级的JavaEE解决⽅案&#xff0c;整合众多优秀的设计模式轻量级 1. 对于运⾏环境是没有额外要求的开源 tomcat resion jetty收费 weblogic websphere 2. 代码移植性⾼不需要实现额外接⼝JavaEE的解…

java多线程传参数

package com.myThread;public class AdminThread extends Thread{private String name;public void AdminThread(String name){this.name name;}Overridepublic void run() {//线程开始之后执行的代码for (int i 0; i < 100; i) {System.out.print(getName()"线程…

Qt/QML编程之路:slider(34)

滑条slider&#xff0c;有时也成为进度条progressbar&#xff0c;在GUI界面中也是经常用到的。 import QtQuick 2.9 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.2ApplicationWindow {id:rootvisible: truewidth: 1920height: 720//title: qsTr("Hello World&q…

matlab快速入门(读取数据并绘制散点图和拉格朗日插值

目录 1.读取excel&#xff1a;2.注释快捷键&#xff1a;3.数组/矩阵索引&#xff1a;4.绘制散点图&#xff1a;5.拉格朗日插值&#xff1a;5.1分割出非空和空的x和y两组数据&#xff1a;5.2插值&#xff1a;5.3画图&#xff1a; 小结&#xff1a; 1.读取excel&#xff1a; [nu…

《动手学深度学习》学习笔记 第9章 现代循环神经网络

本系列为《动手学深度学习》学习笔记 书籍链接&#xff1a;动手学深度学习 笔记是从第四章开始&#xff0c;前面三章为基础知识&#xff0c;有需要的可以自己去看看 关于本系列笔记&#xff1a; 书里为了让读者更好的理解&#xff0c;有大篇幅的描述性的文字&#xff0c;内容很…

Unity之触发器

目录 &#x1f4d5;一、触发器概念 &#x1f4d5;二、碰撞与触发的区别 &#x1f4d5;三、触发器小实例 一、触发器概念 第一次玩侠盗猎车手是在小学&#xff0c;从那以后就开启了我的五星好市民之路。 下面是小编在小破站截的图&#xff0c;这是罪恶都市最开始的地方&a…

数据结构奇妙旅程之二叉树初阶

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

深度好文:MySQL体系结构

MySQL采用的是客户/服务器体系结构&#xff0c;实际是有两个程序&#xff0c;一个是MySQL服务器程序&#xff0c;指的是mysqld程序&#xff0c;运行在存放数据库的机器上&#xff0c;负责在网络上监听并处理来自客户的服务请求&#xff0c;根据这些请求去访问数据库的内容&…

在IntelliJ IDEA中集成SSM项目

SSM项目&#xff1a;springMVC为控制器、spring 为事务层、 MyBatis 负责持久 首先看下集成后项目结构&#xff1a; 1、打开IntelliJ IDEA&#xff0c;点击 "File" -> "New" -> "Project"。 点击Finish&#xff0c;此时我们就已经创建了一…

Git怎么将文件夹上传至github,全过程

小白建议参考github文件上传全流程-新手入门系列&#xff08;超详细&#xff01;&#xff01;&#xff01;&#xff09; 中间可能会有报错 $ ssh -T gitgithub.com ssh: connect to host github.com port 22: Connection timed out 这时&#xff0c;参考&#xff0c;如何解决&a…