Newer
Older
HuangJiPC / src / pages / views / WatershedOneMap / modalPart / cbwsc.vue
@zengcong zengcong on 24 Jul 16 KB 模型
<template>
  <div class="cantainer">
    <div id="bengzhan" ref="threeDom">
      <div id="lableBox" class="lableBox">
        <div class="label" v-for="(item, i) in labelData" :key="i" :id="item.id" style="display: none">
          <div class="outer">
            <div class="title">{{ item.name }}</div>
            <ul>
              <li v-for="(v, j) in item.data" :key="j">
                <span class="pointName">{{ v.pointName }}</span>
                <span class="value">{{ v.value }}</span>
              </li>
            </ul>
            <div class="triangle"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { ref, reactive, toRefs, onMounted, onUnmounted, nextTick, onBeforeMount } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; //控制器
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'; // gltf加载器
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import gsap from 'gsap';
import { CSSRulePlugin } from 'gsap/CSSRulePlugin';
gsap.registerPlugin(CSSRulePlugin); // 引入css插件,完成某些css动画
import { Move, CameraReverseOutline, ReturnDownForward, EyeSharp, Eye } from '@vicons/ionicons5';

export default {
  name: 'dqtxc',
  components: {
    Move,
    CameraReverseOutline,
    ReturnDownForward,
    EyeSharp,
    Eye,
  },
  props: {
    bzInfo: Object,
  },
  setup(props) {
    const state = reactive({
      width: null,
      height: null,
      Scene: null,
      Camera: null,
      Renderer: null,
      Controls: null,
      granaryArr: [],
      texture: null,
      LabelRenderer: null,
      cnt: 0,
      mixer4: null,
      // labelData: [],
      labelData: [
        {
          name: '一号泵机',
          data: [
            {
              pointName: '开关状态:',
              value: '关',
            },
            {
              pointName: '电压:',
              value: '0V',
            },
            {
              pointName: '电流:',
              value: '0A',
            },
          ],
          id: `label1`,
          position: {
            x: 46,
            y: -5,
            z: -6,
          },
        },
        {
          name: '二号泵机',
          data: [
            {
              pointName: '开关状态:',
              value: '关',
            },
            {
              pointName: '电压:',
              value: '0V',
            },
            {
              pointName: '电流:',
              value: '0A',
            },
          ],
          id: `label2`,
          position: {
            x: 50,
            y: -5,
            z: -16,
          },
        },
        {
          name: '三号泵机',
          data: [
            {
              pointName: '开关状态:',
              value: '关',
            },
            {
              pointName: '电压:',
              value: '0V',
            },
            {
              pointName: '电流:',
              value: '0A',
            },
          ],
          id: `label3`,
          position: {
            x: 55,
            y: -5,
            z: -22,
          },
        },
        {
          name: '四号泵机',
          data: [
            {
              pointName: '开关状态:',
              value: '关',
            },
            {
              pointName: '电压:',
              value: '0V',
            },
            {
              pointName: '电流:',
              value: '0A',
            },
          ],
          id: `label4`,
          position: {
            x: 60,
            y: -5,
            z: -28,
          },
        },
        {
          name: '五号泵机',
          data: [
            {
              pointName: '开关状态:',
              value: '关',
            },
            {
              pointName: '电压:',
              value: '0V',
            },
            {
              pointName: '电流:',
              value: '0A',
            },
          ],
          id: `label5`,
          position: {
            x: 65,
            y: -5,
            z: -34,
          },
        },
        {
          name: '六号泵机',
          data: [
            {
              pointName: '开关状态:',
              value: '关',
            },
            {
              pointName: '电压:',
              value: '0V',
            },
            {
              pointName: '电流:',
              value: '0A',
            },
          ],
          id: `label6`,
          position: {
            x: 70,
            y: -5,
            z: -40,
          },
        },
      ],
      timer: null,
      BZData: [],
    });
    const Scene = new THREE.Scene();
    // const axesHelper = new THREE.AxesHelper(10000);
    // Scene.add(axesHelper);
    const clock = new THREE.Clock();
    const threeDom = ref(null);
    const cameraPosition = {
      // x: 65,
      // y: -5,
      // z: -34,
      x: 0.6684777522359171,
      y: 73.34509967795945,
      z: -75.51598392913485,
    };
    const cameraLookat = {
      x: 0,
      y: 0,
      z: 0,
    };
    const cameraReset = (position, lookAt, time = 3) => {
      gsap.to(state.Camera.position, {
        x: position.x,
        y: position.y,
        z: position.z,
        duration: time,
        ease: 'power4.out',
      });
      gsap.to(state.Camera.lookAt, {
        x: lookAt.x,
        y: lookAt.y,
        z: lookAt.z,
        duration: time,
        ease: 'power4.out',
      });
      gsap.to(state.Controls.target, {
        x: lookAt.x,
        y: lookAt.y,
        z: lookAt.z,
        duration: time,
        ease: 'power4.out',
      });
    };

    const initLabelRenderer = () => {
      state.LabelRenderer = new CSS3DRenderer();
      state.LabelRenderer.setSize(state.width, state.height);
      state.LabelRenderer.domElement.style.position = 'absolute';
      state.LabelRenderer.domElement.style.top = '0px';
      threeDom.value.appendChild(state.LabelRenderer.domElement);
    };
    const initRenderer = () => {
      state.width = document.getElementById('bengzhan').clientWidth;
      state.height = document.getElementById('bengzhan').clientHeight;
      state.Renderer = new THREE.WebGLRenderer({
        antialias: true, //抗锯齿
        alpha: true, //开启alpha
      });
      state.Renderer.shadowMap.enabled = true;
      // state.Renderer.setClearColor("skyblue");
      state.Renderer.setPixelRatio(window.devicePixelRatio);
      state.Renderer.setSize(state.width, state.height);
      state.Renderer.toneMapping = THREE.ACESFilmicToneMapping;
      state.Renderer.toneMappingExposure = 2.3; // 曝光系数
      state.Renderer.setClearColor(0xffffff);

      threeDom.value.appendChild(state.Renderer.domElement);
    };

    //创建一个透视相机,45是相机的视角  , 宽高比是屏幕的宽高比 , 最近能看到0.1 , 最远能看到10000
    const initCamera = () => {
      state.Camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 10, 100000);
      //将相机放到x:1000 , y:1000 , z:1000的位置
      // state.Camera.position.set(30, 0, 10);
      state.Camera.position.set(1000, 1000, 1000);
    };
    const initControls = () => {
      //调试模型光线位置代码
      //   const axesHelper = new THREE.AxesHelper(10000);
      //   Scene.add(axesHelper);

      state.Controls = new OrbitControls(state.Camera, state.LabelRenderer.domElement);
      //上下翻转的最大角度
      state.Controls.maxPolarAngle = 5;
      // //上下翻转的最小角度
      state.Controls.minPolarAngle = 0.8;
      //是否允许缩放
      state.Controls.enableZoom = true;
      // 使动画循环使用时阻尼或自转 意思是否有惯性
      state.Controls.enableDamping = false;
      // 动态阻尼系数 就是鼠标拖拽旋转灵敏度
      state.Controls.dampingFactor = 0.04;
      // 是否可以旋转
      state.Controls.enableRotate = true;
      // 是否可以缩放与速度
      state.Controls.enableZoom = true;
      // 设置相机距离原点的最远距离
      state.Controls.minDistance = 100;
      // 设置相机距离原点的最远距离
      state.Controls.maxDistance = 12000;
      // 是否开启右键拖拽
      state.Controls.enablePan = true;
    };
    const initModal = (name, url) => {
      const Gltfloader = new GLTFLoader();
      var dracoLoader = new DRACOLoader();
      // dracoLoader.setDecoderPath('https://zhzz.hongshan.gov.cn:8865/file/hongshan/Three_Gltf/'); //设置解压库文件路径
      dracoLoader.setDecoderPath('/modelFilesJson/Three_Gltf/'); //设置解压库文件路径

      Gltfloader.setDRACOLoader(dracoLoader);
      Gltfloader.load(
        url,
        (gltf) => {
          gltf.scene.name = name;
          gltf.scene.scale.set(0.35, 0.35, 0.35);
          gltf.scene.position.set(10, 10, 10);
          //   gltf.scene.position.z = 10;

          cameraReset(cameraPosition, cameraLookat);
          state.mixer = new THREE.AnimationMixer(gltf.scene);
          // state.mixer.clipAction(gltf.animations[0]).play(); //渲染glb文件自带的动画效果

          Scene.add(gltf.scene);
          // Scene.add(cube);
          Scene.traverse(function (child) {
            if (child.isMesh) {
              child.frustumCulled = false;
              child.material.side = THREE.DoubleSide;
              state.granaryArr.push(child);
            }
          });
        },
        (function (xhr) {
          // console.log(Math.floor((xhr.loaded / xhr.total) * 100));
        })``
      );
    };
    const initLight = () => {
      let ambientLight = new THREE.AmbientLight(0x0557d7, 2); // 创建环境光
      Scene.add(ambientLight);
    };
    const initSpotLight = () => {
      let spotLight = new THREE.SpotLight(0x2e3d46, 0.9);
      spotLight.position.set(20, 500, 100);
      const SpotLightHelper = new THREE.SpotLightHelper(spotLight, 1);
      // 光源开启阴影效果
      // spotLight.castShadow = true;
      // Scene.add(SpotLightHelper);
      Scene.add(spotLight); // 将聚光灯添加到场景中
    };
    const initDirectionalLight = () => {
      // 平行光设置
      var directionalLight = new THREE.DirectionalLight(0x0557d7, 1);
      // 两点确定一条直线,我们要找两个点,一个是我们设置的点(position),一个是物体(target)
      directionalLight.position.set(120, 100, 50);
      // directionalLight.target = mesh;
      Scene.add(directionalLight);
    };

    // const hdr = '/modelFilesJson/three_glb/kloppenheim_061_4k.hdr';
    const hdr = './static/three_glb/kloppenheim_061_4k.hdr';
    // const hdr = 'public/static/three_glb/kloppenheim_061_4k.hdr';
    const initSky = () => {
      var pmremGenerator = new THREE.PMREMGenerator(state.Renderer); // 使用hdr作为背景色
      pmremGenerator.compileEquirectangularShader();
      new RGBELoader().load(hdr, function (texture) {
        const envMap = pmremGenerator.fromEquirectangular(texture).texture;
        // envMap.mapping = THREE.EquirectangularReflectionMapping;
        // state.Renderer.outputEncoding = THREE.sRGBEncoding;
        envMap.isPmremTexture = true;
        pmremGenerator.dispose();
        Scene.environment = envMap;
        Scene.background = envMap;
      });
    };
    // 创建气泡窗
    function createLable() {
      state.labelData.forEach((item, index) => {
        let labelCSS3D = Scene.getObjectByName(`label${index + 1}`);
        if (labelCSS3D === undefined) {
          let lableDiv = document.getElementById(`label${index + 1}`);
          lableDiv.style.display = 'block';
          labelCSS3D = new CSS3DObject(lableDiv);
          labelCSS3D.position.set(item.position.x, item.position.y, item.position.z);
          labelCSS3D.scale.set(0.03, 0.03, 0.03);
          labelCSS3D.name = 'Zha';
          Scene.add(labelCSS3D);
          console.log('labelCSS3D.position', labelCSS3D.position);
        } else {
          labelCSS3D.visible = true;
        }
      });
    }

    // 标注水位

    const onWindowResize = () => {
      state.Camera.aspect = window.innerWidth / window.innerHeight;
      state.Camera.updateProjectionMatrix();
      state.Renderer.setSize(state.width, state.height);
      state.LabelRenderer.setSize(state.width, state.height);

      Render();
    };
    const initPointLight = () => {
      const pointLight = new THREE.PointLight(0xffffff, 1, 200);
      pointLight.intensity = 100;
      pointLight.position.set(0, 200, 0);
      Scene.add(pointLight);

      const sphereSize = 1;
      //点光源辅助线
      // const pointLightHelper = new THREE.PointLightHelper(
      //     pointLight,
      //     sphereSize
      // );
      // Scene.add(pointLightHelper);
    };
    const Render = () => {
      requestAnimationFrame(Render);

      if (state.mixer) state.mixer.update(clock.getDelta()); //渲染glb文件自带的动画效果

      state.Controls.update(); // 轨道控制器的更新
      state.Renderer.clear(); // 清除画布
      state.Renderer.render(Scene, state.Camera);

      state.LabelRenderer.render(Scene, state.Camera);
      const delta = clock.getDelta();
      //调试打印相机XYZ的方向位置
      // console.log(2222, state.Camera);
    };

    onBeforeMount(() => {
      //   initGltfFloor();
      // initModal('wushuichang', '/modelFiles/three_glb/3.gltf');
      // initModal('wushuichang', 'public/static/three_glb/3.gltf');
    });
    onMounted(() => {
      initModal('wushuichang', './static/three_glb/3.gltf');
      // initModal('wushuichang', '/modelFilesJson/three_glb/3.gltf');
      nextTick(() => {
        if (document.readyState === 'complete') {
          // createLable();
        }
        // document.addEventListener('click', meshOnClick);
        window.addEventListener('resize', onWindowResize, false);
      });
      initLight(); //环境光
      initPointLight(); //点光
      initSpotLight(); //聚光灯
      initDirectionalLight(); //平行光
      initRenderer();
      initLabelRenderer();
      initCamera();
      initControls();

      initSky();
      Render();
    });
    onUnmounted(() => {
      Scene.traverse((e) => {
        if (e.BufferGeometry) e.BufferGeometry.dispose();
        if (e.material) {
          if (Array.isArray(e.material)) {
            e.material.forEach((m) => {
              m.dispose();
            });
          } else {
            e.material.dispose();
          }
        }
        if (e.isMesh) {
          e.remove();
        }
      });
      Scene.remove();
      state.Renderer.dispose();
      state.Renderer.content = null;

      window.removeEventListener('resize', onWindowResize, false);
      cancelAnimationFrame(Render);
      clearInterval(state.timer);
    });

    return {
      threeDom,
      ...toRefs(state),
      initRenderer,
      initLabelRenderer,
      initCamera,
      initControls,
      initDirectionalLight,
      initSky,
      initLight,
      Render,

      createLable,
    };
  },
  computed: {},
  methods: {},
};
</script>
<style lang="less" scoped>
.mt15 {
  margin-top: 15px;
}

.cantainer {
  position: relative;
  width: 100%;
  height: 100%;

  #ShowBox {
    position: absolute;
    right: 10px;
    top: 10px;
    z-index: 9999;
    font-size: 18px;
    color: aqua;
    cursor: pointer;
  }

  #bengzhan {
    width: 100%;
    height: 100%;
    background-image: radial-gradient(circle, #8594b4, #c0c8d8);
  }

  .label {
    padding: 10px;
    z-index: 9999 !important;
    width: 200px;

    .title {
      line-height: 40px;
      font-size: 18px;
      padding: 0 10px;
      border-bottom: 1px solid #e7f1ff;
      color: turquoise;
    }

    ul {
      li {
        padding: 0 10px;
        line-height: 30px;
        display: flex;
        justify-content: space-between;

        &:nth-child(2n) {
          background: #e7f1ff;
        }

        .pointName {
          color: #888;
        }

        .value {
          color: #0066ff;
        }
      }
    }

    .outer {
      position: absolute;
      top: 0;
      left: 0;
      width: 140px;
      border-radius: 10px;
      box-shadow: -2px 0 20px #0060ff;
      background: rgba(255, 255, 255, 0.712);
    }

    .inner {
      position: absolute;
      top: -7px;
      left: -7px;
      width: 100%;
      border-radius: 10px;
      border: 1px solid #0060ff;
      box-shadow: -2px 0 9px #0060ff;
      background: rgba(255, 255, 255, 0.685);
    }

    .triangle {
      position: absolute;
      right: 0;
      bottom: 0;
      width: 0;
      height: 0;
      border-right: 5px solid #0060ff;
      border-bottom: 5px solid #0060ff;
      border-left: 5px solid transparent;
      border-top: 5px solid transparent;
    }
  }
}
</style>