vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > 使用threeJs导入obj模型并添加标注

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

作者:看点博客

这篇文章主要介绍了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();
      }
   }

总结

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

您可能感兴趣的文章:
阅读全文