three.js 鼠标选中模型弹出标签

效果:请关注抖音


 

代码:

<template>
  <div>
    <el-container>
      <el-main>
        <div class="box-card-left">
          <div id="threejs" style="border: 1px solid red;position: relative;"></div>
        </div>
      </el-main>
    </el-container>
  </div>
</template>
<script>
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
// 效果制作器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
// 渲染通道
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
// 发光描边OutlinePass
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
import { CSS2DObject, CSS2DRenderer } from "three/examples/jsm/renderers/CSS2DRenderer.js";

export default {
  data() {
    return {
      name: "",
      scene: null,
      camera: null,
      renderer: null,
      css2DRenderer: null,
      effectComposer: null,
      mesh: null,
      geometry: null,
      group: null,
      material: null,
      texture: null,
      position: null,
      outlinePass: null,
      canvasWidth: 1000,
      canvasHeight: 800,
      color: [],
      meshArr: [],
    };
  },
  created() {},
  mounted() {
    this.name = this.$route.query.name;
    this.init();
  },
  methods: {
    goBack() {
      this.$router.go(-1);
    },
    init() {
      // 思路:有六个模型,分别代表人的头,身体,左右手臂,左右腿;当点击某一个模型时,高亮,并且显示标签名称
      this.scene = new this.$three.Scene();
      const axesHelper = new this.$three.AxesHelper(300);
      this.scene.add(axesHelper);
      this.group = new this.$three.Group();
      this.group.translateY(150);
      this.creatMesh_tou();
      this.creatMesh_body();
      this.creatMesh_hand();
      this.creatMesh_foot();
 
      this.scene.add(this.group);
      // 创建相机对象
      this.camera = new this.$three.PerspectiveCamera(60,1,0.01,2000);
      this.camera.position.set(300,300,300);
      this.camera.lookAt(0,0,0);
      // 创建渲染器对象
      this.renderer = new this.$three.WebGLRenderer();
      this.renderer.setSize(this.canvasWidth, this.canvasHeight);
      this.renderer.render(this.scene, this.camera);
      window.document.getElementById("threejs").appendChild(this.renderer.domElement);

      // 
      this.css2DRenderer = new CSS2DRenderer();
      this.css2DRenderer.setSize(this.canvasWidth, this.canvasHeight);
      this.css2DRenderer.render(this.scene, this.camera);
      this.css2DRenderer.domElement.style.position = "absolute";
      this.css2DRenderer.domElement.style.top = 0;
      this.css2DRenderer.domElement.style.pointerEvents = 'none';
      window.document.getElementById("threejs").appendChild(this.css2DRenderer.domElement);

        // 创建空间轨道控制器对象
      const controls = new OrbitControls(this.camera, this.renderer.domElement);
      controls.addEventListener("change", () => {
        this.renderer.render(this.scene, this.camera);
      })
      this.rayCasterFn();
      this.effectComposerFn();
    },
    renderFun() {
      // 调用后处理对象的render方法进行渲染,
      this.effectComposer.render();
      this.css2DRenderer.render(this.scene, this.camera);
      window.requestAnimationFrame(this.renderFun);
    },
    rayCasterFn() {
      // 画布添加事件监听
      document.getElementById("threejs").addEventListener("click", e => {
        this.scene.traverse(one => {
          if(one.isCSS2DObject) {
            this.scene.remove(one);
          }
        })
        // 坐标转换
        const p_x = e.offsetX;
        const p_y = e.offsetY;
        const x = (p_x / this.canvasWidth) * 2 - 1;
        const y = -(p_y / this.canvasHeight) * 2 + 1;
        // 创建射线拾取器对象
        const raycaster = new this.$three.Raycaster();
        // 射线计算
        raycaster.setFromCamera(new this.$three.Vector2(x, y), this.camera);
        // 射线交叉计算
        const intersects = raycaster.intersectObjects(this.group.children);
        if(intersects.length > 0) {
          let obj = intersects[0].object;
          this.outlinePass.selectedObjects = [obj];
          let dom = this.createDiv(obj.name);
  
          let css2_obj = new CSS2DObject(dom);
          
          const wp = new this.$three.Vector3();
          obj.getWorldPosition(wp)
          css2_obj.position.set(wp.x, wp.y, wp.z);
          this.scene.add(css2_obj);
          this.renderFun();
        } else {
          this.outlinePass.selectedObjects = [];
        }
      })
    },
    effectComposerFn() {
      // 创建后处理对象
      this.effectComposer = new EffectComposer(this.renderer);
      // 创建后处理通道
      const renderPass = new RenderPass(this.scene, this.camera);
      this.effectComposer.addPass(renderPass);
      // 创建发光描边对象
      this.outlinePass = new OutlinePass(new this.$three.Vector2(this.canvasWidth, this.canvasHeight), this.scene, this.camera);
      this.outlinePass.edgeStrength = 20;
      this.outlinePass.edgeThickness = 5;
      this.outlinePass.visibleEdgeColor.set(0xffaadd);
      this.outlinePass.pulsePeriod = 2;
      this.effectComposer.addPass(this.outlinePass);
    },
    createDiv(name) {
      let dom = document.createElement("div");
      dom.style.padding = '5px 10px';
      dom.style.border = '1px solid skyblue';
      dom.style.color = 'red';
      dom.style.background = '#2FF885';
      dom.style.borderRadius = '15px';
      dom.innerHTML = name;
      // dom.innerHTML = "龙年大吉";
      return dom;
    },
    creatMesh_tou() {
      const geometry = new this.$three.SphereGeometry(30,64,64);
      const material = new this.$three.MeshBasicMaterial({
        color: 0xdfdf
      });
      const mesh = new this.$three.Mesh(geometry, material);
      mesh.name = "头";
      this.group.add(mesh);
    },
    creatMesh_body() {
      const geometry = new this.$three.BoxGeometry(50,100,80);
      const material = new this.$three.MeshBasicMaterial({
        color: 0xdaafdf
      });
      const mesh = new this.$three.Mesh(geometry, material);
      mesh.translateY(-80);
      mesh.name = "身体";
      this.group.add(mesh);
    },
    creatMesh_hand() {
      const geometry = new this.$three.BoxGeometry(10,10,120);
      const material = new this.$three.MeshBasicMaterial({
        color: 0x11afdf
      });
      const mesh = new this.$three.Mesh(geometry, material);
      mesh.translateY(-60);
      mesh.translateZ(-100);
      mesh.name = "右手";
      this.group.add(mesh);
      const mesh2 = mesh.clone();
      mesh2.translateZ(200);
      mesh2.name = "左手";
      this.group.add(mesh2);
    },
    creatMesh_foot() {
      const geometry = new this.$three.BoxGeometry(10,190,10);
      const material = new this.$three.MeshBasicMaterial({
        color: 0xD63DF0
      });
      const mesh = new this.$three.Mesh(geometry, material);
      mesh.translateY(-220);
      mesh.translateZ(-30);
      mesh.name = "右腿";
      this.group.add(mesh);
      const mesh2 = mesh.clone();
      mesh2.translateZ(60);
      mesh2.name = "左腿";
      this.group.add(mesh2);
    },
  },
};
</script>
//
<style lang="less" scoped>
.box-card-left {
  display: flex;
  align-items: flex-start;
  flex-direction: row;
  position: relative;
  width: 100%;

  .box-right {
  img{
    width:500px;
    user-select: none;
  }
  }
}
</style>

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

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

相关文章

Emergent Abilities of Large Language Models 机翻mark

摘要 证明通过扩大语言模型可以可靠地提高性能和样本效率在广泛的下游任务。相反&#xff0c;本文讨论了我们称之为大型语言模型的新兴能力的一种不可预测的现象。我们认为如果一个能力不存在于较小的模型中&#xff0c;但在较大的模型中存在&#xff0c;则该能力就是新兴的。…

springboot 整合 Activiti6

1.添加maven依赖 <dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter-basic</artifactId><version>6.0.0</version> </dependency>2.添加配置 spring:activiti:check-process-definitio…

【wink】如何调整视频比例、缩放视频、修改背景?

这三个问题都可在「视频剪辑-画布」功能里实现&#xff1a; 调整视频比例&#xff1a; 点击「视频剪辑 - 画布- 比例」&#xff0c;即可选择合适的视频比例。 缩放视频&#xff1a; 点击「视频剪辑 - 画布 - 缩放」&#xff0c;即可通过滑杆缩放视频。 修改背景&#xff1a;…

《动手学深度学习(PyTorch版)》笔记4.1

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过。…

【大数据】Flink 中的事件时间处理

Flink 中的事件时间处理 1.时间戳2.水位线3.水位线传播和事件时间4.时间戳分配和水位线生成 在之前的博客中&#xff0c;我们强调了时间语义对于流处理应用的重要性并解释了 处理时间 和 事件时间 的差异。虽然处理时间是基于处理机器的本地时间&#xff0c;相对容易理解&#…

再谈Android View绘制流程

一&#xff0c;先思考何时开始绘制 笔者在这里提醒读者&#xff0c;Android的View是UI的高级抽象&#xff0c;我们平时使用的XML文件也好&#xff0c;本质是设计模式中的一种策略模式&#xff0c;其View可以理解为一种底层UI显示的Request。各种VIew的排布&#xff0c;来自于开…

scrapy的概念作用和工作流程

1. scrapy的概念 Scrapy是一个Python编写的开源网络爬虫框架。它是一个被设计用于爬取网络数据、提取结构性数据的框架。 Scrapy 使用了Twisted[twɪstɪd]异步网络框架&#xff0c;可以加快我们的下载速度。 Scrapy文档地址&#xff1a;http://scrapy-chs.readthedocs.io/zh_…

pytorch 实现中文文本分类

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客&#x1f366; 参考文章&#xff1a;365天深度学习训练营&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制]\n&#x1f680; 文章来源&#xff1a;[K同学的学习圈子](https://www.yuque.com/mi…

K8s 安装部署-Master和Minion(Node)文档

K8s 安装部署-Master和Minion(Node)文档 操作系统版本&#xff1a;CentOS 7.4 Master &#xff1a;172.20.26.167 Minion-1&#xff1a;172.20.26.198 Minion-2&#xff1a;172.20.26.210&#xff08;后增加节点&#xff09; ETCD&#xff1a;172.20.27.218 先安装部署ETC…

ElasticSearch的集群管理命令

ElasticSearch版本 {"name" : "data-slave1","cluster_name" : "data-es","cluster_uuid" : "xxxxxxxxxx-eMwxw","version" : {"number" : "7.2.1","build_flavor" : &…

【JaveWeb教程】(32)SpringBootWeb案例之《智能学习辅助系统》的详细实现步骤与代码示例(5)文件上传的实现

目录 SpringBootWeb案例052. 文件上传2.1 简介2.2 本地存储 SpringBootWeb案例05 前面我们已经实现了员工信息的条件分页查询以及删除操作。 关于员工管理的功能&#xff0c;还有两个需要实现新增和修改员工。 本节的主要内容&#xff1a; 文件上传 2. 文件上传 在我们完成…

【开源】基于JAVA语言的实验室耗材管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 耗材档案模块2.2 耗材入库模块2.3 耗材出库模块2.4 耗材申请模块2.5 耗材审核模块 三、系统展示四、核心代码4.1 查询耗材品类4.2 查询资产出库清单4.3 资产出库4.4 查询入库单4.5 资产入库 五、免责说明 一、摘要 1.1…

docker 存储管理

文章目录 docker 存储管理容器存储方案docker 容器存储解决方案 docker 存储驱动基本概述存储驱动的选择原则主流的 docker 存储驱动docker 版本支持的存储驱动 overlay2 存储驱动OverlayFSoverlay2 存储驱动要求配置 docker 使用 overlay2 驱动 overlay2 存储驱动的工作机制Ov…

C++核心编程:C++ 中的引用 笔记

2.引用 2.1 引用的基本使用 - 作用&#xff1a;给变量起别名 - 语法&#xff1a;数据类型 &别名 原名 #include<iostream> using namespace std; int main() {// 引用基本语法// 数据类型 &别名 原名int a 10;// 创建引用int &ref_a a;cout<<&qu…

搭建Redis集群

一 应用场景 为什么需要redis集群&#xff1f; 当主备复制场景&#xff0c;无法满足主机的单点故障时&#xff0c;需要引入集群配置。 一般数据库要处理的读请求远大于写请求 &#xff0c;针对这种情况&#xff0c;我们优化数据库可以采用读写分离的策略。我们可以部 署一台…

Ubuntu 系统如何修改时间

Ubuntu 系统如何修改时间 简介&#xff1a;在Ubuntu上&#xff0c;你可以使用以下三种方法来修改时间&#xff1a;date命令&#xff0c;timedatectl命令和hw 原文&#xff1a;Ubuntu 系统如何修改时间 (baidu.com)https://cloud.baidu.com/article/393621 三种方法修改Ubunt…

Linux——文本编辑器Vim

Linux中的所有内容以文件形式管理&#xff0c;在命令行下更改文件内容&#xff0c;常常会用到文本编辑器。我们首选的文本编辑器是Vim&#xff0c;它是一个基于文本界面的编辑工具&#xff0c;使用简单且功能强大&#xff0c;更重要的是&#xff0c;Vim是所有Linux发行版本的默…

husky结合commitlint审查commit信息

commintlint是一个npm包用来规范化我们的commit信息&#xff0c;当然这个行为的操作时期是在git的commit-msg生命周期期间&#xff0c;这一点当然是有husky来控制&#xff0c;需要注意的是commit-msg作为一个git生命周期会被git commit和git merge行为唤醒&#xff0c;并且可以…

03-Redis缓存高可用集群

文章目录 1、Redis集群方案比较2、Redis高可用集群搭建redis集群搭建Java操作redis集群 4、Redis集群原理分析槽位定位算法跳转重定位Redis集群节点间的通信机制gossip通信的10000端口网络抖动 Redis集群选举原理分析集群脑裂数据丢失问题集群是否完整才能对外提供服务Redis集群…

第二百八十八回

文章目录 1. 概念介绍2. 使用方法2.1 实现步骤2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取文件类型"相关的内容&#xff0c;本章回中将介绍如何播放视频.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 播放视频是我们常用…