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

 更新时间:2024年05月23日 11:09:02   作者:看点博客  
这篇文章主要介绍了vue使用threeJs导入obj模型并实现添加标注方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

效果图

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();
      }
   }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vue两组件间值传递 $router.push实现方法

    vue两组件间值传递 $router.push实现方法

    两组件间传值,可能包含多种情况,这篇文章主要介绍了vue两组件间值传递 $router.push实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-05-05
  • Vue——解决报错 Computed property

    Vue——解决报错 Computed property "****" was assigned to but it ha

    这篇文章主要介绍了Vue——解决报错 Computed property "****" was assigned to but it has no setter.的方法,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下
    2020-12-12
  • vue、react等单页面项目部署到服务器的方法及vue和react的区别

    vue、react等单页面项目部署到服务器的方法及vue和react的区别

    这篇文章主要介绍了vue、react等单页面项目部署到服务器的方法,需要的朋友可以参考下
    2018-09-09
  • vue实现导出excel的多种方式总结

    vue实现导出excel的多种方式总结

    在Vue中实现导出Excel有多种方式,可以通过前端实现,也可以通过前后端配合实现,这篇文章将为大家详细介绍几种常用的实现方式,需要的可以参考下
    2023-08-08
  • vue中解决微信html5原生ios虚拟键返回不刷新问题

    vue中解决微信html5原生ios虚拟键返回不刷新问题

    这篇文章主要介绍了vue中解决微信html5原生ios虚拟键返回不刷新问题,本文给大家分享解决方法,通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • vue篇之事件总线EventBus使用示例详解

    vue篇之事件总线EventBus使用示例详解

    这篇文章主要为大家介绍了vue篇之事件总线EventBus使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 在Vue3中进行单元测试和集成测试的操作方法

    在Vue3中进行单元测试和集成测试的操作方法

    随着越来越多的企业和开发者选择使用 Vue.js 构建他们的前端应用程序,确保代码质量和可靠性变得尤为重要,在本博客中,我们将深入探讨如何在 Vue 3 中进行单元测试和集成测试,并提供示例代码来帮助您上手,需要的朋友可以参考下
    2025-01-01
  • 解决vue3中内存泄漏的问题

    解决vue3中内存泄漏的问题

    在项目中会发现一个奇怪的现象,当我们在使用element-plus中的图标组件时会出现内存泄漏,所以本文讲给大家讲讲如何解决vue3中的内存泄漏的问题,需要的朋友可以参考下
    2023-07-07
  • vue实现双向绑定和依赖收集遇到的坑

    vue实现双向绑定和依赖收集遇到的坑

    这篇文章主要介绍了vue的双向绑定和依赖收集,主要是通过Object.defineProperty() 实现双向绑定,具体思路代码大家跟随小编一起看看吧
    2018-11-11
  • vue中defineProperty和Proxy的区别详解

    vue中defineProperty和Proxy的区别详解

    这篇文章主要介绍了vue中defineProperty和Proxy的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11

最新评论