当前位置: 代码网 > it编程>编程语言>Javascript > vue使用threeJs导入obj模型并实现添加标注

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

2024年06月11日 Javascript 我要评论
效果图1.安装threejsnpm install three2.安装轨道控件插件npm install three-orbit-controls3.安装加载.obj和.mtl文件的插件npm i -

效果图

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

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com