Newer
Older
urbanLifeline_YanAn / src / views / oneMap / BIM / WangJiaPIng.vue
@zhangqy zhangqy on 10 Oct 10 KB 模型优化
<template>
  <div id="WangJiaPIng" ref="threeDom"></div>
</template>

<script setup name="WangJiaPIng">
import { ref, reactive, toRefs, onMounted } 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 { Water } from "three/examples/jsm/objects/Water.js";

import {
  CSS3DRenderer,
  CSS3DObject,
} from "three/examples/jsm/renderers/CSS3DRenderer.js";
import gsap from "gsap";
import { CSSRulePlugin } from "gsap/CSSRulePlugin";
const AllData = reactive({});

const width = ref(null);
const height = ref(null);
const Camera = ref(null);
const Renderer = ref(null);
const Controls = ref(null);
const granaryArr = ref([]);
const LabelRenderer = ref(null);
let Twater = null;
const labelData = ref([
  {
    name: "一号泵机",
    id: `YuanDian1`,
    position: {
      x: -180,
      y: 230,
      z: -180,
    },
    OnSrc: "/Three/icon/BJ_On.png",
    OffSrc: "/Three/icon/BJ_Off.png",
    status: false,
    boxShow: true,
    value1: "--",
    value2: "--",
    value3: "--",
    deviceCode: "",
    stCode: "HP0104201130000469",
  },
  {
    name: "二号泵机",
    id: `YuanDian2`,
    position: {
      x: 3,
      y: 230,
      z: -180,
    },
    OnSrc: "/Three/icon/BJ_On.png",
    OffSrc: "/Three/icon/BJ_Off.png",
    status: false,
    boxShow: true,
    value1: "--",
    value2: "--",
    value3: "--",
    deviceCode: "",
    stCode: "HP0104201130000469",
  },
  {
    name: "三号泵机",
    id: `YuanDian3`,
    position: {
      x: 195,
      y: 230,
      z: -180,
    },
    OnSrc: "/Three/icon/BJ_On.png",
    OffSrc: "/Three/icon/BJ_Off.png",
    status: false,
    boxShow: true,
    value1: "--",
    value2: "--",
    value3: "--",
    deviceCode: "",
    stCode: "HP0104201130000469",
  },
]);
const deviceCode = ref(null);
const stCode = ref(null);
const MiMa = ref(null);
const dialogVisible = ref(false);
const loading = ref(false);
const status = ref(false);
const timer = ref(null);

const Scene = new THREE.Scene();
const clock = new THREE.Clock();
const threeDom = ref(null);
const cameraPosition = {
  // x: 457.66301930145875,
  // y: 397.5473109836439,
  // z: 943.8703438418463,
  x: -58.221584999469584,
  y: 6.590211176632594,
  z: 9.665579736149148,
};
const cameraLookat = {
  x: 1,
  y: 1,
  z: -20,
};

/**
 * 初始化模态对话框
 * @param {string} name - 模型的名称
 * @param {string} url - 模型的URL
 */
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("/draco/"); //设置解压库文件路径
  Gltfloader.setDRACOLoader(dracoLoader);
  Gltfloader.load(
    url,
    (gltf) => {
      gltf.scene.name = name;
      gltf.scene.scale.set(1, 1, 1);
      // gltf.scene.position.x = -70;
      gltf.scene.position.y = 2;

      cameraReset(cameraPosition, cameraLookat);

      Scene.add(gltf.scene);
      Scene.traverse(function (child) {
        if (child.isMesh) {
          child.frustumCulled = false;
          child.material.side = THREE.DoubleSide;
          granaryArr.value.push(child);
        }
      });
    },
    function (xhr) {
      console.log(Math.floor((xhr.loaded / xhr.total) * 100));
    }
  );
};

/**
 * 恢复相机位置和视角
 *
 * 此函数通过GSAP动画库来调整相机的位置和视角,以实现 Smooth Transition
 *
 * @param {Object} position - 相机的新位置,包含x, y, z坐标
 * @param {Object} lookAt - 相机的新视角目标,包含x, y, z坐标,目前未使用
 * @param {number} time - 动画过渡时间,单位为秒,默认为3秒
 */
const cameraReset = (position, lookAt, time = 3) => {
  gsap.to(Camera.value.position, {
    x: position.x,
    y: position.y,
    z: position.z,
    duration: time,
    ease: "power4.out",
  });
  // gsap.to(Camera.value.lookAt, {
  //   x: lookAt.x,
  //   y: lookAt.y,
  //   z: lookAt.z,
  //   duration: time,
  //   ease: "power4.out",
  // });
  gsap.to(Controls.value.target, {
    x: lookAt.x,
    y: lookAt.y,
    z: lookAt.z,
    duration: time,
    ease: "power4.out",
  });
};

/**
 * 初始化渲染器
 * 该函数负责创建和配置Three.js的WebGL渲染器,包括设置视口大小、抗锯齿、阴影、像素比、色调映射等
 */
const initRenderer = () => {
  width.value = document.getElementById("WangJiaPIng").clientWidth;
  height.value = document.getElementById("WangJiaPIng").clientHeight;
  Renderer.value = new THREE.WebGLRenderer({
    antialias: true,
    // alpha: true, //开启alpha
  });
  Renderer.value.shadowMap.enabled = true;
  Renderer.value.setPixelRatio(window.devicePixelRatio);
  Renderer.value.setSize(width.value, height.value, true);
  // Renderer.value.toneMapping = THREE.ACESFilmicToneMapping;
  Renderer.value.toneMappingExposure = 1; // 曝光系数
  threeDom.value.appendChild(Renderer.value.domElement);
};

/**
 * 初始化标签渲染器
 * 该函数用于创建和配置一个CSS3D渲染器,用于渲染标签对象
 * 它设置了渲染器的大小,位置,并将其添加到三维场景的DOM元素中
 */
const initLabelRenderer = () => {
  LabelRenderer.value = new CSS3DRenderer();
  LabelRenderer.value.setSize(width.value, height.value);
  LabelRenderer.value.domElement.style.position = "absolute";
  LabelRenderer.value.domElement.style.top = "0px";
  threeDom.value.appendChild(LabelRenderer.value.domElement);
  // LabelRenderer.value.domElement.addEventListener("click", meshOnClick);
};

/**
 * 初始化摄像机
 * 创建一个透视摄像机,并设置其位置
 */
const initCamera = () => {
  Camera.value = new THREE.PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    1,
    4000
  );
  Camera.value.position.set(500, 500, 500);
};

/**
 * 初始化控制对象
 * 设置相机控制属性,以实现特定的相机行为
 */
const initControls = () => {
  Controls.value = new OrbitControls(Camera.value, LabelRenderer.value.domElement);
  //上下翻转的最大角度
  // state.Controls.maxPolarAngle = 1.5;
  // //上下翻转的最小角度
  // state.Controls.minPolarAngle = 0.2;
  //是否允许缩放
  Controls.value.enableZoom = false;
  // 使动画循环使用时阻尼或自转 意思是否有惯性
  Controls.value.enableDamping = false;
  // 动态阻尼系数 就是鼠标拖拽旋转灵敏度
  Controls.value.dampingFactor = 0.04;
  // 是否可以旋转
  Controls.value.enableRotate = true;
  // 是否可以缩放与速度
  Controls.value.enableZoom = true;
  // 设置相机距离原点的最远距离
  Controls.value.minDistance = 50;
  // 设置相机距离原点的最远距离
  Controls.value.maxDistance = 3000;
  // 是否开启右键拖拽
  Controls.value.enablePan = true;
  // AxesHelper:辅助观察的坐标系
  const axesHelper = new THREE.AxesHelper(3000);
  Scene.add(axesHelper);
};

/**
 * 初始化灯光
 * 创建并添加环境光到场景中,以模拟全局照明效果
 */
const initLight = () => {
  // let ambientLight = new THREE.AmbientLight(0xffffff, 0.1); // 创建环境光
  // Scene.add(ambientLight);
  // // 设置场景的背景颜色,即天空颜色
  // Scene.background = new THREE.Color(0x999999); // 设置背景,可以更换为你想要的颜色
  // // 设置天空的雾气颜色和雾气近距离
  // Scene.fog = new THREE.Fog(0xffffff, 10, 150); // 距离10开始,到200结束
  // //  创建平行光源
  // const directionalLight = new THREE.DirectionalLight(0xffffff, 0.1);
  // directionalLight.position.set(-100, 100, 100);
  // // 将光源添加到场景
  // Scene.add(directionalLight);
};

/**
 * 初始化天空盒
 * 使用PMREMGenerator生成环境贴图,并设置为场景的环境光和背景
 * 通过RGBELoader加载HDR纹理,用于创建环境贴图
 * 注意:此函数未使用TextureLoader加载背景图片,而是使用HDR纹理
 */
const initSky = () => {
  var pmremGenerator = new THREE.PMREMGenerator(Renderer.value); // 使用hdr作为背景色
  pmremGenerator.compileEquirectangularShader();
  new RGBELoader().load("/Gltf/Skey_1K.hdr", function (texture) {
    const envMap = pmremGenerator.fromEquirectangular(texture).texture;
    envMap.isPmremTexture = true;
    Scene.environment = envMap;
    // Scene.background = envMap;
    //  envMap.offset.set(0.8, 0.89); // 设置环境映射的偏移量
    pmremGenerator.dispose();
  });
  new THREE.TextureLoader().load("/Gltf/bg.png", function (texture) {
    Scene.background = texture;
  });
};

/**
 * 渲染函数,用于不断更新和渲染场景
 */
const Render = () => {
  requestAnimationFrame(Render);
  Controls.value.update(); // 轨道控制器的更新
  Renderer.value.clear(); // 清除画布
  Renderer.value.render(Scene, Camera.value);
  LabelRenderer.value.render(Scene, Camera.value);
  const delta = clock.getDelta();
  console.log(Camera.value);
};

onBeforeMount(() => {
  //   initGltfFloor();
  // initModal('ChangJing', '/Gltf/ChuWangCheng.gltf');
  initModal("daqiao", "/Gltf/daqiao.gltf");
});
onMounted(() => {
  nextTick(() => {
    if (document.readyState === "complete") {
      // createLable();
      // createWaterLevel();
    }
  });
  initRenderer();
  initLabelRenderer();
  initCamera();
  initControls();
  initLight();
  initSky();
  // createLable();
  // LoadWater();
  Render();
});

onBeforeUnmount(() => {
  // document.removeEventListener('click', meshOnClick);
  // window.removeEventListener("resize", onWindowResize, false);

  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();
  Renderer.value.dispose();
  Renderer.value.content = null;
  clearInterval(timer.value);
});
</script>

<style lang="scss" scoped>
#WangJiaPIng {
  width: 100%;
  height: 100%;
  position: absolute;
  // background: url("@/assets/images/Sponge_screen/QiaoLiang/BIM.png") no-repeat center center;
}
</style>