vue项目中使用three.js添加3D模型,模型加载做加载中动画以及模型作缓存、鼠标点击交互拿到模型对象

一、效果预览

 

 二、代码页面容器

<template>
  <div class="main-page">
    <div class="center">
      <div class="video-show module">
        <div class="mx">
          <!-- <iframe class="iframehtml" v-if="url" :src="url" frameborder="0" scrolling="no"></iframe> -->
          <!-- 遮罩层 -->
          <div class="modelMask" v-if="percentageBool">
            <div class="marg">
              <p>loading 3D model</p>
              <div class="elPro">
                <el-progress :stroke-width="6" :show-text="false" :percentage="percentage"></el-progress>
              </div>
            </div>
          </div>
          <!-- 模型存放区域 -->
          <div id="threeContained"></div>
        </div>
      </div>
    </div>
  </div>
</template>

 意:id为threeContained的div就是模型最终渲染的区域,所以在模型加载容器的时候注意,需要使用这个div的宽高,不是windows.innerwidth

三、鼠标交互事件(点击模型中的摄像头,获取摄像头的id)

// 鼠标点击事件
    selectObject(event){
      let container = document.getElementById('threeContained');
        var mouse = new THREE.Vector2();
        var raycaster = new THREE.Raycaster();
        let getBoundingClientRect = container.getBoundingClientRect()
        let x = ((event.clientX - getBoundingClientRect.left) / container.offsetWidth) * 2 - 1;// 标准设备横坐标
        let y = -((event.clientY - getBoundingClientRect.top) / container.offsetHeight) * 2 + 1;// 标准设备纵坐标
        let standardVector = new THREE.Vector3(x, y, 1);// 标准设备坐标
        // 标准设备坐标转世界坐标
        let worldVector = standardVector.unproject(this.camera);
        // 射线投射方向单位向量(worldVector坐标减相机位置坐标)
        let ray = worldVector.sub(this.camera.position).normalize();
        // 创建射线投射器对象
        let rayCaster = new THREE.Raycaster(this.camera.position, ray);
        // 返回射线选中的对象 第二个参数如果不填 默认是false
        let intersected = rayCaster.intersectObjects(this.scene.children, true);
        if (intersected.length) {
          const found = intersected[0];
          if(found.object.name == "354713923249152"){
              this.$router.push({
                path:'/home/monitoring/monitoringVideo',
                query:{
                  id:found.object.name
                }
              })
          }  
      }
    }

四、全部代码贴图

 

<script>
import { videoList } from "@/api/mainpage";
import * as THREE from "three"; //引入Threejs
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Stats from "three/examples/jsm/libs/stats.module";
// import rtsp2webrtc from '@/components/rtsp2webrtc'
export default {
  name: "MainPage",
  components: {
    // rtsp2webrtc,
  },
  mounted() {
    if(!localStorage.getItem('Admin-Token')){
      this.$router.push('/');
      return;
    }
    // 测试地址
    // this.$refs.video.connentStream(true, 'rtsp://admin:leinao123@192.168.8.220')
    // this.init();
    this.clock = new THREE.Clock();
    this.init();
    // this.animate();
    window.onpointerdown = this.selectObject;
  },
  data() {
    return {
      videoList: [],
      curIndex: 0,
      url: "https://realsee.com/ke/BEy832qG8mQDNnOe/1mlg5kWnP4kTkhxh1TaxzDMUG8wYBe4V/#lianjia",
      // 模型信息
      scene: "",
      light: "",
      camera: "",
      controls: "",
      renderer: "",
      load: "",
      clock: "",
      mixer: "",
      percentage:0,//进度条数据
      percentageBool:true,
      meshChildren:[],
    };
  },
  methods: {
    // 模型函数开始
    init() {
      var that = this;
      // 加缓存,避免模型再次请求
      // THREE.Cache.enabled = true;
      var container = document.getElementById("threeContained");
      // 创建场景
      that.scene = new THREE.Scene();
      // that.scene.background = new THREE.Color(0x8cc7de);
      that.scene.background = new THREE.Color("#080e30");
      // 创建相机
      that.camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.1,
        10000
      );
      // that.camera.position.set( -70, 25, 90 );
      // 定位相机,并且指向场景中心(这里设置的值我是根据模型尺寸来写的,其实应该是动态获取模型长宽高后设置相机位置,根据自己模型大小来写)
      that.camera.position.x = 800;
      that.camera.position.y = 520;
      that.camera.position.z = 3000;
      //设置z轴朝上
      // that.camera.up.x = 0;
      // that.camera.up.y = 0;
      // that.camera.up.z = 1;
      that.camera.lookAt(that.scene.position);

      // 显示三维坐标系
      // var axes = new THREE.AxesHelper(100);
      // // 添加坐标系到场景中:红色是X轴绿色是y轴蓝色是z轴
      // that.scene.add(axes);

      // // 创建地面的几何体
      // var planeGeometry = new THREE.PlaneGeometry(800, 1000);
      // // 给地面物体上色
      // var planeMaterial = new THREE.MeshStandardMaterial({ color: 0xcccccc });
      // // 创建地面
      // var plane = new THREE.Mesh(planeGeometry, planeMaterial);
      // plane.material.opacity = 0.6;
      // plane.material.transparent = true;
      // plane.rotation.x = -0.5 * Math.PI;
      // plane.position.x = 0;
      // plane.position.y = 0;
      // plane.position.z = 0;
      // plane.castShadow = true;
      // // 接收阴影
      // plane.receiveShadow = true;
      // that.scene.add(plane);

      // 灯光
      const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
      hemiLight.position.set(0, 1, 0);
      that.scene.add(hemiLight);

      const directionalLight1 = new THREE.DirectionalLight(0xffeeff, 0.8);
      directionalLight1.position.set(1, 1, 1);
      that.scene.add(directionalLight1);

      const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.8);
      directionalLight2.position.set(-1, 0.5, -1);
      that.scene.add(directionalLight2);

      const ambientLight = new THREE.AmbientLight(0xffffee, 0.25);
      that.scene.add(ambientLight);

      // stats消耗资源展示
      // that.stats = new Stats();
      // container.appendChild(that.stats.dom);

      // 材质
      //   const normal = new THREE.TextureLoader().load(
      //     "models/shanghai/textures/shanghai.jpg"
      //   );
      // model
      that.loader = new FBXLoader();
      // that.loader.load("/models/SHIWAI.FBX",function (geometry) {
      // that.loader.load("https://img.cnbita.com/meshes.fbx",function (geometry) {
      // that.loader.load("https://img.cnbita.com/fbx/BDZ.FBX", function (geometry) {
      that.loader.load("/models/fbx/BDZ.FBX", function (geometry) {
        // that.loader.load("https://img.cnbita.com/fbx/newMeshes.fbx", function (geometry) {
         that.percentageBool = false;
          // geometry.scale.set(0.04, 0.04, 0.04);
          geometry.scale.set(0.1,0.1,0.1);
          geometry.position.set(0, 36, 0);
          that.scene.add(geometry);
          that.animate();
        },
        // onProgress回调
        function ( xhr ) {
          that.percentage = Math.floor(xhr.loaded / xhr.total * 100);
          that.$forceUpdate();
          // console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
        },
        // onError回调
        function ( err ) {
          console.error( 'An error happened' );
        }
      );
      // 创建渲染器
      that.renderer = new THREE.WebGLRenderer({
        antialias: true,
        logarithmicDepthBuffer: true,
      });
      that.renderer.setPixelRatio(window.devicePixelRatio);
      // 设置渲染器的初始颜色
      that.renderer.setClearColor(new THREE.Color(0xeeeeee));
      // 设置输出canvas画面的大小
      // that.renderer.setSize(window.innerWidth, window.innerHeight);
      that.renderer.setSize(container.clientWidth,container.clientHeight);
      container.appendChild(that.renderer.domElement);
      // 控制模型的旋转
      const controls = new OrbitControls(that.camera, that.renderer.domElement);
      controls.target.set(0, 12, 0);
      controls.update();
      window.addEventListener("resize", that.onWindowResize);
    },
    // 窗口缩放
    onWindowResize() {
      var container = document.getElementById("threeContained");
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(container.clientWidth,container.clientHeight);
    },
    // 动画
    animate() {
      // requestAnimationFrame(this.animate);

      // this.renderer.render(this.scene, this.camera);

      // this.stats.update();

      requestAnimationFrame(this.animate);
      const delta = this.clock.getDelta();
      if (this.mixer) this.mixer.update(delta);
      this.renderer.render(this.scene, this.camera);
      // this.stats.update();
    },
    // 鼠标点击事件
    selectObject(event){
      if(this.percentageBool){
        return;
      }
      let container = document.getElementById('threeContained');
      if(!container){
        return;
      }
        var mouse = new THREE.Vector2();
        var raycaster = new THREE.Raycaster();
        let getBoundingClientRect = container.getBoundingClientRect()
        let x = ((event.clientX - getBoundingClientRect.left) / container.offsetWidth) * 2 - 1;// 标准设备横坐标
        let y = -((event.clientY - getBoundingClientRect.top) / container.offsetHeight) * 2 + 1;// 标准设备纵坐标
        let standardVector = new THREE.Vector3(x, y, 1);// 标准设备坐标
        // 标准设备坐标转世界坐标
        let worldVector = standardVector.unproject(this.camera);
        // 射线投射方向单位向量(worldVector坐标减相机位置坐标)
        let ray = worldVector.sub(this.camera.position).normalize();
        // 创建射线投射器对象
        let rayCaster = new THREE.Raycaster(this.camera.position, ray);
        // 返回射线选中的对象 第二个参数如果不填 默认是false
        let intersected = rayCaster.intersectObjects(this.scene.children, true);
        if (intersected.length) {
          const found = intersected[0];
          if(found.object.name == "354713923249152"){
              this.$router.push({
                path:'/home/monitoring/monitoringVideo',
                query:{
                  id:found.object.name
                }
              })
          }  
      }
    }
  },
};
</script>

<style scoped lang="scss">
@import "style/index.scss";
#threeContained {
  width: 100%;
  height: 100%;
}
.iframehtml {
  width: 100%;
  height: 100%;
}
.mx {
  width: 97.5%;
  height: 96%;
  margin: 0 auto;
  border-radius: 6.5% 6% 6% 6%;
  position: absolute;
  left: 1.25%;
  top: 2%;
  overflow: hidden;
  // bottom: 5%;
  // right: 4%;
  .modelMask {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    // background: #080e30;
    // background: rgba($color: #080e30, $alpha: 0.85);
    background: url('~@/assets/images/modelBg.png') no-repeat center center;
    background-size: 100% 100%;
    z-index: 9;
    display: flex;
    .marg {
      width: 300px;
      height: 60px;
      margin: auto;
      text-align: center;
      p {
        color: #e2e2e2;
        font-size: 13px;
      }
      .elPro {
        width: 100%;
        margin-top: 10px;
      }
    }
    
  } 
}
</style>

  

 

  

 

posted @ 2021-12-02 14:33  杰_森  阅读(7574)  评论(1编辑  收藏  举报