Vue uses threeJs to import the obj model and add annotations

Effect picture:
insert image description here
1. Install threeJs

npm install three

2. Install the track control plug-in

npm install three-orbit-controls

3. Install plugins that load .obj and .mtl files

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

Page reference:

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

Create variables externally:

   场景    模型    相机   渲染      控制器     标签
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(),//创建二维平面
      },
    }
  },

Import the model and load it in the scene

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");
          });
      });
    },

create scene

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

    },

Initialize the camera

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

init loader

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

The integration is called in init

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

refresh animation

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

Called in mounted,

mounted () {
    
    
    this.$nextTick(() => {
    
    
      this.init();
      this.loadMTL()
      this.animate();
      }
   }

Guess you like

Origin blog.csdn.net/hzqzzz/article/details/126142871
Recommended