Просмотр исходного кода

[Feat 0000] 羊马河防火门模型开发

houzekong 1 неделя назад
Родитель
Сommit
6b4f037496

+ 30 - 1
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ts

@@ -9,6 +9,7 @@ let model,
   fireDoor, //液压风门
   fireDoorF, //保德风门
   fireDoorSsl, // 思山岭防火门
+  fireDoorYmh, // 思山岭防火门
   fireDoorRed, // 防火门
   group: THREE.Object3D,
   fhmType = '';
@@ -31,6 +32,9 @@ const startAnimation = () => {
     if (fhmType === 'fireDoorSsl') {
       fireDoorSsl?.mouseUpModel.call(fireDoorSsl);
     }
+    if (fhmType === 'fireDoorYmh') {
+      fireDoorYmh?.mouseUpModel.call(fireDoorYmh);
+    }
     if (fhmType === 'fireDoorRed') {
       fireDoorRed?.mouseUpModel.call(fireDoorRed);
     }
@@ -50,6 +54,9 @@ const mouseEvent = (event) => {
       if (fhmType === 'fireDoorSsl' && fireDoorSsl) {
         fireDoorSsl?.mousedownModel.call(fireDoorSsl, intersects);
       }
+      if (fhmType === 'fireDoorYmh' && fireDoorYmh) {
+        fireDoorYmh?.mousedownModel.call(fireDoorYmh, intersects);
+      }
       if (fhmType === 'fireDoorRed' && fireDoorRed) {
         fireDoorRed?.mousedownModel.call(fireDoorRed, intersects);
       }
@@ -68,6 +75,9 @@ export const play = (handlerState, flag?) => {
   if (fhmType === 'fireDoorSsl' && fireDoorSsl) {
     return fireDoorSsl.play.call(fireDoorSsl, handlerState, flag);
   }
+  if (fhmType === 'fireDoorYmh' && fireDoorYmh) {
+    return fireDoorYmh.play.call(fireDoorYmh, handlerState, flag);
+  }
   if (fhmType === 'fireDoorRed' && fireDoorRed) {
     return fireDoorRed.play.call(fireDoorRed, handlerState, flag);
   }
@@ -85,6 +95,9 @@ export const setModelType = (type) => {
   if (fhmType === 'fireDoorSsl' && fireDoorSsl) {
     fireDoorSsl.resetAnimate();
   }
+  if (fhmType === 'fireDoorYmh' && fireDoorYmh) {
+    fireDoorYmh.resetAnimate();
+  }
   if (fhmType === 'fireDoorRed' && fireDoorRed) {
     fireDoorRed.resetAnimate();
   }
@@ -108,6 +121,12 @@ export const setModelType = (type) => {
       newP: { x: 342.74781900192056, y: 183.50210411099545, z: 451.0806333923029 },
       newT: { x: 72.33938301176254, y: -35.03891296652319, z: -37.91742549963208 },
     },
+    fireDoorYmh: {
+      render: fireDoorYmh ? () => fireDoorYmh.render() : null,
+      group: fireDoorYmh ? fireDoorYmh.group : null,
+      newP: { x: 342.74781900192056, y: 183.50210411099545, z: 451.0806333923029 },
+      newT: { x: 72.33938301176254, y: -35.03891296652319, z: -37.91742549963208 },
+    },
     fireDoorRed: {
       render: fireDoorRed ? () => fireDoorRed.render() : null,
       group: fireDoorRed ? fireDoorRed.group : null,
@@ -126,7 +145,7 @@ export const setModelType = (type) => {
     model.orbitControls.minDistance = 600;
     model.orbitControls.maxDistance = 900;
     model.orbitControls.update();
-  } else if (type == 'fireDoorRed' || type == 'fireDoorSsl') {
+  } else if (type == 'fireDoorRed' || type == 'fireDoorSsl' || type == 'fireDoorYmh') {
     model.orbitControls.maxPolarAngle = Math.PI;
     model.orbitControls.minPolarAngle = 0;
     model.orbitControls.enableRotate = true;
@@ -163,6 +182,8 @@ export const initCameraCanvas = async (playerVal1) => {
     return await fireDoorF.initCamera.call(fireDoorF, playerVal1);
   } else if (fhmType === 'fireDoorSsl' && fireDoorSsl) {
     return await fireDoorSsl.initCamera.call(fireDoorSsl, playerVal1);
+  } else if (fhmType === 'fireDoorYmh' && fireDoorYmh) {
+    return await fireDoorYmh.initCamera.call(fireDoorYmh, playerVal1);
   } else if (fhmType === 'fireDoorRed' && fireDoorRed) {
     return await fireDoorRed.initCamera.call(fireDoorRed, playerVal1);
   }
@@ -172,6 +193,7 @@ const loadModel = (code): Promise<any> => {
   if (code === 'fireDoor') return import('./fireDoor.threejs.fire').then((r) => r.default);
   if (code === 'fireDoorF') return import('./fireDoor.threejs.fireF').then((r) => r.default);
   if (code === 'fireDoorSsl') return import('./fireDoor.threejs.ssl').then((r) => r.default);
+  if (code === 'fireDoorYmh') return import('./fireDoor.threejs.ymh').then((r) => r.default);
   if (code === 'fireDoorRed') return import('./fireDoor.threejs.fire.redGate').then((r) => r.default);
   return import('./fireDoor.threejs.fire.redGate').then((r) => r.default);
 };
@@ -202,6 +224,11 @@ export const mountedThree = () => {
             fireDoorSsl = new FireDoorSsl(model);
             fireDoorSsl.mountedThree();
             break;
+          case 'fireDoorYmh':
+            const FireDoorYmh = await loadModel('fireDoorYmh');
+            fireDoorYmh = new FireDoorYmh(model);
+            fireDoorYmh.mountedThree();
+            break;
           case 'fireDoorRed':
             const FireDoorRed = await loadModel('fireDoorRed');
             fireDoorRed = new FireDoorRed(model);
@@ -236,6 +263,8 @@ export const destroy = () => {
     fireDoorF = null;
     if (fireDoorSsl) fireDoorSsl.destroy();
     fireDoorSsl = null;
+    if (fireDoorYmh) fireDoorYmh.destroy();
+    fireDoorYmh = null;
     if (fireDoorRed) fireDoorRed.destroy();
     fireDoorRed = null;
     // @ts-ignore-next-line

+ 248 - 0
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ymh.ts

@@ -0,0 +1,248 @@
+import * as THREE from 'three';
+import { useAppStore } from '/@/store/modules/app';
+
+import * as dat from 'dat.gui';
+const gui = new dat.GUI();
+gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+// 羊马河
+class FireDoorYmh {
+  modelName = 'fireDoorYmh';
+  model; //
+  group;
+  isLRAnimation = true; // 是否开启左右摇摆动画
+  direction = 1; // 摇摆方向
+  animationTimer: NodeJS.Timeout | null = null; // 摇摆开启定时器
+  player1;
+  player2;
+  deviceDetailCSS3D;
+  playerStartClickTime1 = new Date().getTime();
+  playerStartClickTime2 = new Date().getTime();
+
+  fmClock = new THREE.Clock();
+  mixers: THREE.AnimationMixer | undefined;
+  appStore = useAppStore();
+  damperOpenMesh;
+  damperClosedMesh;
+
+  clipActionArr: Record<string, THREE.AnimationAction | undefined> = {
+    /** 卷帘门动画 */
+    fengmen: undefined,
+    /** 盖板动画 */
+    gaiban: undefined,
+  };
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
+    directionalLight.position.set(344, 690, 344);
+    this.group?.add(directionalLight);
+    directionalLight.target = this.group as THREE.Object3D;
+
+    const pointLight2 = new THREE.PointLight(0xffeeee, 1, 300);
+    pointLight2.position.set(-4, 10, 1.8);
+    pointLight2.shadow.bias = 0.05;
+    this.group?.add(pointLight2);
+
+    const pointLight3 = new THREE.PointLight(0xffeeee, 1, 200);
+    pointLight3.position.set(-0.5, -0.5, 0.75);
+    pointLight3.shadow.bias = 0.05;
+    this.group?.add(pointLight3);
+  }
+  resetCamera() {
+    this.model.camera.far = 274;
+    this.model.orbitControls?.update();
+    this.model.camera.updateProjectionMatrix();
+  }
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(24, 24, 24);
+    this.group?.position.set(-20, 20, 10);
+  }
+
+  /* 风门动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+    if (this.mixers && this.fmClock.running) {
+      this.mixers.update(1);
+    }
+  }
+
+  /* 点击风门 */
+  mousedownModel(intersects: THREE.Intersection[]) {
+    console.log('摄像头控制信息', intersects);
+  }
+
+  mouseUpModel() {}
+
+  /**
+   * 提取风门序列帧,初始化前后门动画
+   *
+   * 动画序列帧提取操作提示:使用threejs编辑器打开模型并选择模型后点击右下角播放后排查动画元素,找到分界点后手动标记或根据name标记
+   */
+  initAnimation() {
+    const group = this.group.children[0];
+    console.log('debug rr', group.animations[0].tracks);
+    /** 卷帘门的元素名称,pCude34-pCude73 */
+    if (group) {
+      const tracksA: THREE.KeyframeTrack[] = [];
+      const tracksB: THREE.KeyframeTrack[] = [];
+
+      group.animations[0].tracks.forEach((track, index) => {
+        if (index < 9) {
+          tracksA.push(track);
+        } else {
+          tracksB.push(track);
+        }
+      });
+      this.mixers = new THREE.AnimationMixer(group);
+
+      const fengmen = new THREE.AnimationClip('fengmen', 10, tracksA);
+      const clipA = this.mixers.clipAction(fengmen, group);
+      clipA.clampWhenFinished = true;
+      clipA.loop = THREE.LoopOnce;
+      this.clipActionArr.fengmen = clipA;
+
+      const gaiban = new THREE.AnimationClip('gaiban', 10, tracksB);
+      const clipB = this.mixers.clipAction(gaiban, group);
+      clipB.clampWhenFinished = true;
+      clipB.loop = THREE.LoopOnce;
+      this.clipActionArr.gaiban = clipB;
+    }
+  }
+  resetAnimate() {
+    if (this.clipActionArr.fengmen) {
+      this.clipActionArr.fengmen.reset();
+      this.clipActionArr.fengmen.time = 0.1;
+      this.clipActionArr.fengmen.stop();
+      this.fmClock.stop();
+    }
+    if (this.clipActionArr.gaiban) {
+      this.clipActionArr.gaiban.reset();
+      this.clipActionArr.gaiban.time = 0.1;
+      this.clipActionArr.gaiban.stop();
+      this.fmClock.stop();
+    }
+  }
+
+  /**
+   * 播放门开关动画的处理函数
+   * @param {number} handlerState - 处理状态,1表示开门,2表示关门
+   * @param {number} [timeScale=0.01] - 动画时间缩放因子,控制动画播放速度
+   */
+  play(handlerState, timeScale = 0.01) {
+    console.log('debug ', handlerState);
+    let handler = () => {};
+    switch (handlerState) {
+      case 1: // 打开门
+        handler = () => {
+          if (!this.clipActionArr.fengmen) return;
+          this.clipActionArr.fengmen.paused = true;
+          this.clipActionArr.fengmen.reset();
+          this.clipActionArr.fengmen.time = 0.1;
+          this.clipActionArr.fengmen.timeScale = timeScale;
+          // this.clipActionArr.fengmen.clampWhenFinished = true;
+          this.clipActionArr.fengmen.play();
+          this.fmClock.start();
+
+          // 显示打开前门文字
+          if (this.damperOpenMesh) this.damperOpenMesh.visible = true;
+        };
+        break;
+      case 2: // 关闭门
+        handler = () => {
+          if (!this.clipActionArr.fengmen) return;
+          this.clipActionArr.fengmen.paused = true;
+          this.clipActionArr.fengmen.reset(); //
+          this.clipActionArr.fengmen.time = 9;
+          this.clipActionArr.fengmen.timeScale = -timeScale;
+          // this.clipActionArr.fengmen.clampWhenFinished = true;
+          this.clipActionArr.fengmen.play();
+          this.fmClock.start();
+
+          if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
+        };
+        break;
+      case 3: // 打开盖板
+        handler = () => {
+          if (!this.clipActionArr.gaiban) return;
+          this.clipActionArr.gaiban.paused = true;
+          this.clipActionArr.gaiban.reset();
+          this.clipActionArr.gaiban.time = 0.1;
+          this.clipActionArr.gaiban.timeScale = timeScale;
+          // this.clipActionArr.gaiban.clampWhenFinished = true;
+          this.clipActionArr.gaiban.play();
+          this.fmClock.start();
+
+          if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
+        };
+        break;
+      case 4: // 关闭盖板
+        handler = () => {
+          if (!this.clipActionArr.gaiban) return;
+          this.clipActionArr.gaiban.paused = true;
+          this.clipActionArr.gaiban.reset(); //
+          this.clipActionArr.gaiban.time = 9;
+          this.clipActionArr.gaiban.timeScale = -timeScale;
+          // this.clipActionArr.gaiban.clampWhenFinished = true;
+          this.clipActionArr.gaiban.play();
+          this.fmClock.start();
+
+          if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
+        };
+        break;
+      default:
+    }
+    handler();
+  }
+
+  mountedThree() {
+    this.group = new THREE.Object3D();
+    this.group.name = this.modelName;
+
+    return new Promise((resolve) => {
+      if (!this.model) {
+        resolve(null);
+      }
+      this.model.setGLTFModel(['fireDoorYmh'], this.group).then(() => {
+        this.setModalPosition();
+        // 初始化左右摇摆动画;
+        this.initAnimation();
+        // this.addLight();
+        // this.model.animate();
+        // resolve(this.model);
+
+        // this.damperOpenMesh = this.group.getObjectByName('Damper_Open_2');
+        // if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
+        // this.damperClosedMesh = this.group.getObjectByName('Damper_Closed_2');
+        // if (this.damperClosedMesh) this.damperClosedMesh.visible = true;
+      });
+    });
+  }
+
+  destroy() {
+    if (!this.model) return;
+    if (this.mixers && this.clipActionArr.fengmen && this.clipActionArr.gaiban) {
+      this.mixers.uncacheClip(this.clipActionArr.fengmen.getClip());
+      this.mixers.uncacheAction(this.clipActionArr.fengmen.getClip(), this.group);
+      this.mixers.uncacheClip(this.clipActionArr.gaiban.getClip());
+      this.mixers.uncacheAction(this.clipActionArr.gaiban.getClip(), this.group);
+      this.mixers.uncacheRoot(this.group);
+
+      if (this.model.animations[0]) this.model.animations[0].tracks = [];
+    }
+    this.model.clearGroup(this.group);
+    this.clipActionArr.fengmen = undefined;
+    this.clipActionArr.gaiban = undefined;
+
+    this.mixers = undefined;
+
+    // document.getElementById('damper3D').parentElement.remove(document.getElementById('damper3D'))
+  }
+}
+export default FireDoorYmh;