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

news2024/10/1 1:18:08

效果:请关注抖音


 

代码:

<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>

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

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

相关文章

前端工程化之:CSS工程化+Less

一、什么是Less&#xff1f; Less官网 Less中文网 Less 是一种更加简洁的样式代码&#xff0c;它非常像 CSS &#xff0c;但又不太一样&#xff0c;它让编写样式变得更容易。 Less 代码虽好&#xff0c;但它无法被浏览器识别&#xff0c;因此需要一个工具将其转换为纯正的 CS…

软件包管理:在CentOS 7中部署Tengine

目录 下载&#xff1a; 方法一&#xff1a; 方法二&#xff1a; 部署&#xff1a; 实验操作 下载&#xff1a; 方法一&#xff1a; 1、打开浏览器搜索tengine并点击官网 2、选择需要安装的版本并复制链接链接 标题栏处可以更改为中文界面 下滑选择版本单击下载 在远程连…

第四篇【传奇开心果短博文系列】鸿蒙开发技术点案例示例:TabBar和Navbar实现页面切换

传奇开心果短博文系列 系列短博文目录鸿蒙开发技术点案例示例短博文系列 短博文目录一、前言二、给Index.ets添加TabBar组件三、用TabBar组件实现页面切换四、给Index.ets添加Navbar组件五、使用Navbar独立实现页面切换六、Navbar和TabBar同时在Index.ets主页实现各自独立的页面…

taskflow 源码阅读笔记-1

之前写了一篇介绍Taskflow的短文&#xff1a;传送门 Taskflow做那种有前后依赖关系的任务管理还是不错的&#xff0c;而且他的源码里运用了大量C17的写法&#xff0c;觉得还是非常值得学习的&#xff0c;因此决定看一下他的源码&#xff0c;这里顺便写了一篇代码学习笔记。 概…

【深度学习】sdxl中的 text_encoder text_encoder_2 区别

镜像问题是&#xff1a;https://editor.csdn.net/md/?articleId135867689 代码仓库&#xff1a; https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/tree/main 截图&#xff1a; 为什么有两个CLIP编码器 text_encoder 和 text_encoder_2 &#xff1f; 在…

vivado DDS学习

实现DDS通常有两种方式&#xff0c;一种是读取ROM存放的正弦/余弦信号的查表法&#xff0c;另一种是用DDS IP核。这篇学习笔记中&#xff0c;我们要讲解说明的是VIVADO DDS IP核的应用。 目前本篇默认Phase Generator and SIN/COS LUT&#xff08;DDS&#xff09;的standard模式…

运行时提示d3dx9_43.dll错误的解决办法,d3dx9_43.dll为什么会丢失

当你在运行某些程序或游戏时出现"找不到d3dx9_43.dll"的错误提示时&#xff0c;不要慌张&#xff01;这是一个常见的问题&#xff0c;但有多种有效的解决办法可以帮助你修复这个文件丢失的情况。今天就来教大家d3dx9_43.dll文件丢失的多种解决办法。 一、d3dx9_43.dl…

【微信小程序】怎样创建formdata对象,并通过 wx.request 发送file文件

一、场景 业务需求&#xff1a;微信小程序开发需要选择本地照片file连同一些表单数据&#xff0c;通过接口发送给服务器 问题&#xff1a; 因涉及到域名安全问题以及并不是单独上传图片&#xff0c;不能使用 wx.uploadFile 。 微信本身没有FormData对象&#xff0c;无法使用 n…

【yaml 文件使用】pytest+request 框架中 yaml 配置文件使用

又来进步一点点~~ 背景&#xff1a;最近在学习pytestrequest框架写接口测试自动化&#xff0c;使用yaml文件配置更方便管理用例中的数据&#xff0c;这样更方便 yaml 介绍&#xff1a; 什么是 yaml 文件&#xff1a;YAML 是 “YAML Ain’t a Markup Language”&#xff08;Y…

硬件知识(1) 手机的长焦镜头

#灵感# 手机总是配备好几个镜头&#xff0c;研究一下 目录 手机常配备的摄像头&#xff0c;及效果举例 长焦的焦距 焦距的定义和示图&#xff1a; IPC的焦距和适用场景&#xff1a; 手机常配备的摄像头&#xff0c;及效果举例 以下是小米某个手机的摄像头介绍&#xff1a…

防御保护----防火墙的安全策略、NAT策略实验

实验拓扑&#xff1a; 实验要求&#xff1a; 1.生产区在工作时间&#xff08;9&#xff1a;00-18&#xff1a;00&#xff09;内可以访问DMZ区&#xff0c;仅可以访问http服务器&#xff1b; 2.办公区全天可以访问DMZ区&#xff0c;其中10.0.2.10可以访问FTP服务器和HTTP服务器…

动能资讯 | 新能源充电桩

充电桩是新能源汽车快速发展不可或缺的一环。充电桩是为新能源汽车充电的充电设施&#xff0c;类似于加油站里的加油机&#xff0c;安装于公共建筑和居民小区停车场或充电站内&#xff0c;可以根据不同的电压等级为各种型号的电动汽车充电。 按照其输出的电压电流为交流电还是…

单片机学习笔记---矩阵键盘密码锁

目录 一&#xff0c;设置密码按键 1.设置密码区域 2.设置输入的数字左移 3.设置记录按键的次数 二&#xff0c;设置确认键 1.密码正确时显示OK 2.密码错误时显示ERR 3.密码错误恢复初始状态重输 三&#xff0c;设置取消键 学了这么久&#xff0c;迫不及待想要做一个密…

虹科数字化与AR部门升级为安宝特AR子公司

致关心虹科AR的朋友们&#xff1a; 感谢您一直以来对虹科数字化与AR的支持和信任&#xff0c;为了更好地满足市场需求和公司发展的需要&#xff0c;虹科数字化与AR部门现已升级为虹科旗下独立子公司&#xff0c;并正式更名为“安宝特AR”。 ”虹科数字化与AR“自成立以来&…

力扣hot100 实现Trie(前缀树) 字典树 一题双解

Problem: 208. 实现 Trie (前缀树) 文章目录 思路复杂度&#x1f49d; TrieNode版&#x1f49d; 二维数组版 思路 &#x1f469;‍&#x1f3eb; 宫水三叶 复杂度 &#x1f49d; TrieNode版 public class Trie {class TrieNode{boolean end;//标记是否有以当前节点为结尾的字…

算法笔记:地理探测器

1 空间分层异质性&#xff08;spatial stratified heterogeneity&#xff09; 空间分层异质性&#xff08;空间分异性/区异性&#xff09;&#xff1a;层内方差小于层间方差的地理现象例如气 候带、土地利用图、地貌图、生物区系、区际经济差异、城乡差异以及主体功能区等 等[…

Git 删除已经 Push 到远程多余的文件

例如要删除 data/log 文件 1. 在当前项目下打开终端 2. 查看有哪些文件夹 dir 3. 预览将要删除的文件&#xff08;如果不清楚该目录下是否存在不应该删除的文件&#xff09; git rm -r -n --cached 文件/文件夹名称 加上 -n 这个参数&#xff0c;执行命令时&#xff0c;是不会…

vue 样式隔离原理

日常写单文件组件时&#xff0c;会在style添加scoped属性&#xff0c;如<style scoped>&#xff0c;目的是为了隔离组件与组件之间的样式&#xff0c;如下面的例子&#xff1a; <template><p class"foo">这是foo</p><p class"bar&q…

React16源码: React中commitAllHostEffects内部的commitDeletion的源码实现

commitDeletion 1 &#xff09;概述 在 react commit 阶段的 commitRoot 第二个while循环中调用了 commitAllHostEffects&#xff0c;这个函数不仅仅处理了新增节点&#xff0c;更新节点最后一个操作&#xff0c;就是删除节点&#xff0c;就需要调用 commitDeletion&#xff0…

SAP包的操作-修改程序所在的包

SAP包的操作 目录 SAP包的操作SAP GUI转换程序所在的包Eclipse转换程序所在的包 SAP GUI转换程序所在的包 Eclipse转换程序所在的包