vue使用threeJs导入obj模型,并添加标注

2023-11-11

效果图:
在这里插入图片描述
1.安装threeJs

npm install three

2.安装轨道控件插件

npm install three-orbit-controls

3.安装加载.obj和.mtl文件的插件

npm i --save three-obj-mtl-loader

页面引用:

import * as THREE from "three";  //引入three.js  
import { MTLLoader } from "three-obj-mtl-loader";   //引入加载外部模型
import { OBJLoader } from "../../public/objJs/OBJLoader.js";   //引入加载外部模型
// const OrbitControls = require("three-orbit-controls")(THREE);  //引入控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { CSS2DObject, CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer';

在外部创建变量:

   场景    模型    相机   渲染      控制器     标签
let scene, scale, camera, renderer, controls, labelRenderer;

data中:

data () {
    return {
      mesh: null,
      events: {
        raycaster: new THREE.Raycaster(),
        pickedObject: null,
        pickedObjectSavedColor: 0,
        pickPosition: new THREE.Vector2(),//创建二维平面
      },
    }
  },

导入模型,在场景中加载

loadMTL () {
      let that = this;
      let mtlLoader = new MTLLoader();
      let objloader = new OBJLoader();
      mtlLoader.load('/file.mtl', function (materials) {
        materials.preload();
        objloader.setMaterials(materials);
        objloader.load('/file.obj', function (obj) {
          obj.position.set(0, -5, 0);//模型摆放的位置
          obj.scale.set(0.002, 0.002, 0.002);//模型放大或缩小,有的时候看不到模型,考虑是不是模型太小或太大。
          scene.add(obj);//将模型加入场景中
          function (xhr) {
            // console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
          },
          // called when loading has errors
          function (error) {
            console.log(error)
            console.log("An error happened");
          });
      });
    },

创建场景

initScene () {
      scene = new THREE.Scene();
      // var axesHelper = new THREE.AxesHelper(250); // 建立xyz坐标轴,红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.长度15

      // scene.add(axesHelper);

      // 改变外壳颜色
      var AmbientLight = new THREE.AmbientLight(0xAF8E00); // 环境光

      scene.add(AmbientLight);

      let DirectionalLight = new THREE.DirectionalLight(0xdfebff, 0.45); // 平行光

      scene.add(DirectionalLight);

    },

初始化相机

initCamera () {

      camera = new THREE.PerspectiveCamera(

        75,

        window.innerWidth / window.innerHeight,

        0.1,

        1000

      );

      camera.position.set(20, 20, 20); // 调整相机方位

      camera.lookAt(new THREE.Vector3(0, 0, 0)); // 让相机指向原点
      const pointLight = new THREE.PointLight(0xffffff, 1, 100);
      pointLight.position.set(0, 0, 20100);
      scene.add(pointLight);
      scene.add(camera);
    },

初始化加载器

initRenderer () {
      renderer = new THREE.WebGLRenderer();
      let container = document.getElementById("container");
      let width = document.getElementById('container').clientWidth;
      let height = document.getElementById('container').clientHeight;
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearColor(0x8B8B8B, 1.0); // 背景光
      container.appendChild(renderer.domElement);
      renderer.setPixelRatio(window.devicePixelRatio);
      // 初始化标签
      labelRenderer = new CSS2DRenderer();
      labelRenderer.setSize(window.innerWidth, window.innerHeight);
      labelRenderer.domElement.style.position = "absolute";
      labelRenderer.domElement.style.top = 0;
      labelRenderer.domElement.style.pointerEvents = 'none';
      labelRenderer.domElement.className = "allLabel"
      container.appendChild(labelRenderer.domElement);

    },
// 鼠标点击创建标签
    clickEvents () {
      window.addEventListener('click', this.clickPickPosition);
    },
     // 当前鼠标点击坐标
    clickPickPosition (e) {
      this.events.pickPosition.x = e.clientX / renderer.domElement.clientWidth * 2 - 1;
      this.events.pickPosition.y = -(e.clientY / renderer.domElement.clientHeight * 2) + 1;
      this.pickEvents(this.events.pickPosition, scene, camera, obj => {
        obj.userData.checked = !obj.userData.checked;
        if (!obj.userData.checked) {
          obj.material.emissive.setHex(this.events.pickedObjectSavedColor)
        } else {
          obj.material.emissive.setHex(0xFFFF00)
        }
      })
    },
    // 创建点击事件(默认是离摄像头最近的相交)
    pickEvents (normalizedPosition, scene, camera, callback) {
      // 如果存在拾取的对象,则恢复颜色
      if (this.events.pickedObject) {
        this.events.pickedObject.material.emissive.setHex(this.events.pickedObjectSavedColor);
        this.events.pickedObject = undefined;
      }
      // 沿着摄像头的方向投射射线
      this.events.raycaster.setFromCamera(normalizedPosition, camera)
      // 获取与射线光线相交的对象列表
      const intersectedObjects = this.events.raycaster.intersectObjects(scene.children);
      if (intersectedObjects.length) {

        // // 获取与射线光纤相交的第一个对象。也是最近的一个
        this.events.pickedObject = intersectedObjects[0].object;
        // // 保存当前对象的颜色
        this.events.pickedObjectSavedColor = this.events.pickedObject.material.emissive.getHex();
        // // 将其发射颜色设置为闪烁的红色/黄色
        this.events.pickedObject.material.emissive.setHex(0xFFFF00)
        // 点击设置标签
        // intersectedObjects[0].point.y *= 1.08;
        // intersectedObjects[0].point.x *= -1.08;
        console.log(intersectedObjects[0].point)
        let pointLabelDom = this.createLableObj(intersectedObjects[0].object.name, intersectedObjects[0].point)
        scene.add(pointLabelDom);//将模型加入场景中
        if (callback) {
          callback(this.events.pickedObject)
        }
      }
    },
    //创建标签方法
    createLableObj (text, vector) {
      let laberDiv = document.createElement('div');//创建div容器
        laberDiv.className = 'laber_name';
        // laberDiv.textContent = text;
        laberDiv.innerHTML = `
            <div class='label_count'>
                ${text}
            </div>
        `
      // 给标签设置坐标位置
      let pointLabel = new CSS2DObject(laberDiv);
      	pointLabel.position.set(vector.x, vector.y, vector.z);
      return pointLabel;
    }

集成在init中调用

init () {
      this.initScene();
      this.initCamera();
      this.initRenderer();
      this.initOrbitControls()
      //调用点击事件
      this.clickEvents()
    },

刷新动画

animate () {
  // requestAnimationFrame 应运而生,它采用的是系统时间间隔(约16.7ms),保持最佳绘制效果与效率,
  // 使各种网页动画有一个统一的刷新机制,从而节省系统资源,提高系统性能。
  requestAnimationFrame(this.animate);
  // controls.update();
  renderer.render(scene, camera);
  labelRenderer.render(scene, camera)
},

在mounted中调用,

mounted () {
    this.$nextTick(() => {
      this.init();
      this.loadMTL()
      this.animate();
      }
   }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue使用threeJs导入obj模型,并添加标注 的相关文章

随机推荐

  • Unity&Shader案例篇—绘制雨滴

    一 前言 转载请注明出处凯尔八阿哥专栏 惯例先上效果图 本文不只是简单的绘制雨滴 同时处理了摄像机不同朝向看到的雨滴下落的方向也不一样 二 方法 1 绘制雨线 绘制雨使用的是C 脚本绘制的 脚本为 using UnityEngine usi
  • 测试之自动化测试

    详细Python教程见 http www liaoxuefeng com wiki 0014316089557264a6b348958f449949df42a6d3a2e542c000 0014316090478912dab2a3a9e8f
  • 【金九银十】软件测试中的高频面试题梳理(内附答案)

    写数据库语句 一个老师表 一个学生表 1 查李老师班的小明 2 并将小明的年纪改成26 select t1 from 学生表 t1 jion 老师表 t2 on t1 班级 t2 班级 where t1 姓名 小明 and t2 姓名 李老
  • vue阻止弹窗_vue 弹窗禁止底层滚动

    原因 底层视图高度超出百分百 加入弹窗后再苹果浏览器隐藏上下栏的情况下遮罩层没有完全遮住底层 处理 打开弹窗后禁止底层滚动调用stop事件 关闭则开启底层滚动调用move事件 let mo function e e preventDefau
  • 实时流协议(RTSP) 来自 维基百科

    https zh wikipedia org wiki E5 8D B3 E6 99 82 E4 B8 B2 E6 B5 81 E5 8D 94 E5 AE 9A 目录 协议指令 OPTIONS 请求 DESCRIBE 请求 SETUP 请
  • stat()/lstat()的使用

    stat 函数和lstat 函数都是用于获取文件或目录的信息的函数 它们可以返回包含文件或目录的各种属性的结构体 这里是关于这两个函数的使用方法的简要说明 stat 函数 include
  • Boostrap对HTML的表格的设计和优化

    目录 01 Bootstrap的默认表格风格 02 没有边线 边界的表格 03 行与行的背景颜色交替变换 条纹样式 04 给表格加上边框效果 05 鼠标移到行上时该行的颜色加深 06 把表格的padding值缩减一半 使表格看起来更紧凑 0
  • 评分模型应用案例_FLUENT太阳辐射模型应用简单案例

    正文共 897字 11图 预计阅读时间 3分钟 1 前言 FLUENT自带了一个太阳辐射模型 solar load model 可以用来计算太阳光线进入计算域带来的辐照 其所谓光线追踪法 ray tracing approach 可以高效地
  • springBoot 整合shiro

    1 springBoot 整合思路 2 环境搭建 2 1创建springBoot项目并导入依赖 a 基本依赖 shiro spring boot starter spring web lombok b shiro依赖
  • 网络编程问题

    数据发送 假设应用程序要发送40KB数据 但是OS的TCP发送缓冲区只有25KB剩余空间 那么剩下的15KB数据怎么办 如果等待OS缓冲区可用 会阻塞当前线程 因为不知道对方什么时候收到并读取数据 因此网络库应该把这个15KB数据缓存起来
  • The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar

    今天用eclipse在maven项目里测试jsp页面时报了如下错误 The absolute uri http java sun com jsp jstl core cannot be resolved in either web xml
  • JUC学习笔记及拓展

    本文为自己整理的学习笔记及学习心得 大纲取自尚硅谷的JUC视频 感兴趣的小伙伴可以去B站自学 JUC学习笔记及拓展 Java JUC 1 Java JUC简介 2 volatile 关键字 内存可见性 2 1 内存可见性 2 2 volat
  • 在linux系统中发布springboot项目

    第一种方法 将项目打成jar包进行发布 第一步 在pom文件中的packing是jar的情况下
  • 汇报措辞:你懂得怎样向领导汇报吗(审阅、审批、批阅、批示、查阅)?

    很多程序员总以为自己技术很牛自倨 不太重视与领导沟通 也不太注重汇报的方式 给领导汇报总不能让领导满意 特别是做到项目经理后 可能会感觉到汇报很难弄 总也说不到点子上 不知道汇报怎样措辞写才能让领导看了满意 其实汇报也是一门技术 需要学习才
  • 在VS中如保快速查看DLL或exe的已导出的函数

    我们知道dumpbin 可以查看dll 或 exe 的导出函数接口 具体命令格式如下 Win r 输入CMD 调出 cmd 指令窗口 输入 C Program Files x86 Microsoft Visual Studio 14 0 V
  • 【框架篇】Spring Boot 日志

    Spring Boot 日志 一 日志用途 尽管一个项目在没有日志记录的情况下可能能够正常运行 但是日志记录对于我们来说却是至关重要的 它存在以下功能 1 故障排查和调试 当项目出现异常或者故障时 日志记录可以快速帮助我们定位到异常的部分以
  • AcWing 1223. 最大比例 指数的最大公约数

    AcWing 1223 最大比例 X星球的某个大奖赛设了 M 级奖励 每个级别的奖金是一个正整数 并且 相邻的两个级别间的比例是个固定值 也就是说 所有级别的奖金数构成了一个等比数列 比如 16 24 36 54 其等比值为 3 2 现在
  • RuntimeError: CUDA out of memory. Tried to allocate 14.00 MiB (GPU 0; 6.00 G)的解决【实测成功】

    仅作为记录 大佬请跳过 仅需减小batchsize 展示 即可运行 注 博主的这个程序减小batchsize就行了 可能不同的博友们的程序不一样 也有的大佬博主使用不计算梯度或释放内存的方式 不计算梯度 传送门 with torch no
  • python学习7.1文件

    一 open 函数 1 第一个参数 文件名 2 打开方式 1 r 以只读模式打开文件 readlines 以列表形式输出 输入 file open a txt r print file readlines file close 输出 汪湾
  • vue使用threeJs导入obj模型,并添加标注

    效果图 1 安装threeJs npm install three 2 安装轨道控件插件 npm install three orbit controls 3 安装加载 obj和 mtl文件的插件 npm i save three obj