Parcourir la source

1. 新增布尔台单道风窗模型

hongrunxia il y a 11 mois
Parent
commit
df74d2cde1

+ 290 - 0
src/views/vent/monitorManager/windowMonitor/dandaoFcBet.threejs.ts

@@ -0,0 +1,290 @@
+import * as THREE from 'three';
+
+import { getTextCanvas, renderVideo } from '/@/utils/threejs/util';
+import gsap from 'gsap';
+
+class singleWindowBet {
+  model;
+  modelName = 'ddFcGroup';
+  group: THREE.Object3D = new THREE.Object3D();
+  animationTimer;
+  isLRAnimation = true;
+  direction = 1;
+  windowsActionArr = {
+    frontWindow: [],
+  };
+  player1;
+  player2;
+  playerStartClickTime1 = new Date().getTime();
+  constructor(model) {
+    this.model = model;
+    this.group.name = 'ddFcGroup';
+  }
+  addLight = () => {
+    if (!this.group || !this.group) return;
+
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
+    directionalLight.position.set(-437, 61, 559);
+    this.group.add(directionalLight);
+  };
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(22, 22, 22);
+    this.group?.position.set(-35, 25, 15);
+  }
+
+  addMonitorText(selectData) {
+    if (!this.group) {
+      return;
+    }
+    const textArr = [
+      {
+        text: `远程定量调节自动风窗`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 100,
+        y: 95,
+      },
+      {
+        text: `${selectData.OpenDegree ? '开度值' : selectData.forntArea ? '过风面积(m2)' : '过风面积(m2)'}:`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 145,
+      },
+      {
+        text: selectData.OpenDegree
+          ? Number(`${selectData.OpenDegree}`).toFixed(2)
+          : selectData.forntArea
+          ? Number(`${selectData.forntArea}`).toFixed(2)
+          : '-',
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 145,
+      },
+      {
+        text: `${selectData.frontRearDP ? '风窗压差(Pa):' : selectData.windSpeed ? '风速:' : '通信状态:'}:`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 200,
+      },
+      {
+        text: `${
+          selectData.frontRearDP
+            ? selectData.frontRearDP
+            : selectData.windSpeed
+            ? selectData.windSpeed
+            : selectData.netStatus == '0'
+            ? '断开'
+            : '连接'
+        }`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 200,
+      },
+      {
+        text: `${selectData.fWindowM3 ? '过风量(m³/min):' : '风窗道数:'} `,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 250,
+      },
+      {
+        text: `${selectData.fWindowM3 ? selectData.fWindowM3 : selectData.nwindownum}`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 250,
+      },
+      {
+        text: History_Type['type'] == 'remote' ? `国能神东煤炭集团监制` : '煤炭科学技术研究院有限公司研制',
+        font: 'normal 28px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: History_Type['type'] == 'remote' ? 90 : 30,
+        y: 300,
+      },
+    ];
+    getTextCanvas(750, 546, textArr, '').then((canvas: HTMLCanvasElement) => {
+      const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+      const textMaterial = new THREE.MeshBasicMaterial({
+        // 关于材质并未讲解 实操即可熟悉                 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质.
+        map: textMap, // 设置纹理贴图
+        transparent: true,
+        side: THREE.DoubleSide, // 这里是双面渲染的意思
+      });
+      textMap.dispose();
+      textMaterial.blending = THREE.CustomBlending;
+      const monitorPlane = this.group?.getObjectByName('monitorText');
+      if (monitorPlane) {
+        monitorPlane.material = textMaterial;
+      } else {
+        const planeGeometry = new THREE.PlaneGeometry(526, 346); // 平面3维几何体PlaneGeometry
+        const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
+        planeMesh.name = 'monitorText';
+        planeMesh.scale.set(0.0038, 0.004, 0.0038);
+        planeMesh.position.set(4.44, -0.165, -0.46);
+        this.group?.add(planeMesh);
+      }
+    });
+  }
+
+  /* 提取风门序列帧,初始化前后门动画 */
+  initAnimation() {
+    const meshArr01: THREE.Object3D[] = [];
+    this.group?.children.forEach((obj) => {
+      if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('FCshanye')) {
+        obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+        meshArr01.push(obj);
+      }
+    });
+    this.windowsActionArr.frontWindow = meshArr01;
+  }
+
+  play(rotationParam, flag) {
+    if (!this.windowsActionArr.frontWindow) {
+      return;
+    }
+    if (flag === 1) {
+      // 前风窗动画
+      this.windowsActionArr.frontWindow.forEach((mesh: THREE.Mesh) => {
+        gsap.to(mesh.rotation, {
+          y: THREE.MathUtils.degToRad(rotationParam.frontDeg1),
+          duration: (1 / 9) * Math.abs(rotationParam.frontDeg1 - mesh.rotation.y),
+          overwrite: true,
+        });
+      });
+    } else if (flag === 0) {
+      ([...this.windowsActionArr.frontWindow] as THREE.Mesh[]).forEach((mesh) => {
+        gsap.to(mesh.rotation, {
+          y: 0,
+          overwrite: true,
+        });
+      });
+    }
+  }
+
+  /* 点击风窗,风窗全屏 */
+  mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
+    this.isLRAnimation = false;
+    if (this.animationTimer) {
+      clearTimeout(this.animationTimer);
+      this.animationTimer = null;
+    }
+    // 判断是否点击到视频
+    intersects.find((intersect) => {
+      const mesh = intersect.object;
+      if (mesh.name === 'player1') {
+        if (new Date().getTime() - this.playerStartClickTime1 < 400) {
+          // 双击,视频放大
+          if (this.player1) {
+            this.player1.requestFullscreen();
+          }
+        }
+        this.playerStartClickTime1 = new Date().getTime();
+        return true;
+      }
+      return false;
+    });
+  }
+
+  mouseUpModel() {
+    // 10s后开始摆动
+    if (!this.animationTimer && !this.isLRAnimation) {
+      this.animationTimer = setTimeout(() => {
+        this.isLRAnimation = true;
+      }, 10000);
+    }
+  }
+
+  /* 风门动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+    if (this.isLRAnimation && this.group) {
+      // 左右摇摆动画
+      if (Math.abs(this.group.rotation.y) >= 0.2) {
+        this.direction = -this.direction;
+        this.group.rotation.y += 0.00002 * 30 * this.direction;
+      } else {
+        this.group.rotation.y += 0.00002 * 30 * this.direction;
+      }
+    }
+  }
+
+  async initCamera(dom1?) {
+    const videoPlayer1 = dom1;
+    let monitorPlane: THREE.Mesh | null = null;
+    const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+    const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+    const textMaterial = new THREE.MeshBasicMaterial({
+      map: textMap, // 设置纹理贴图
+      transparent: true,
+      side: THREE.DoubleSide, // 这里是双面渲染的意思
+    });
+    textMaterial.blending = THREE.CustomBlending;
+    monitorPlane = this.group?.getObjectByName('noPlayer');
+    if (monitorPlane) {
+      monitorPlane.material = textMaterial;
+    } else {
+      const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+      monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+      textMaterial.dispose();
+      planeGeometry.dispose();
+    }
+    const videoPlayer = this.group.getObjectByName('player1');
+    if (videoPlayer) {
+      this.model.clearMesh(videoPlayer);
+      this.group.remove(videoPlayer);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      monitorPlane.name = 'noPlayer1';
+      monitorPlane.scale.set(0.015, 0.007, 0.011);
+      monitorPlane.position.set(4.04, 0.02, -0.46);
+      this.group?.add(monitorPlane);
+    } else if (videoPlayer1) {
+      const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+      if (mesh) {
+        mesh?.scale.set(-0.038, 0.029, 1);
+        mesh?.position.set(-4.302, 0.15, -0.23);
+        mesh.rotation.y = -Math.PI;
+        this.group.add(mesh);
+      }
+    }
+  }
+
+  mountedThree() {
+    return new Promise((resolve) => {
+      this.model.setGLTFModel(['ddFc-bet'], this.group).then(() => {
+        this.setModalPosition();
+        this.initAnimation();
+        this.addLight();
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    this.model.clearGroup(this.group);
+    this.windowsActionArr.frontWindow = undefined;
+    this.model = null;
+    this.group = null;
+  }
+}
+export default singleWindowBet;

+ 10 - 32
src/views/vent/monitorManager/windowMonitor/window.threejs.ts

@@ -1,9 +1,11 @@
 import * as THREE from 'three';
 import UseThree from '../../../../utils/threejs/useThree';
 import singleWindow from './dandaoFc.threejs';
+import singleWindowBet from './dandaoFcBet.threejs';
 import doubleWindow from './shuangdaoFc.threejs';
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
+import { useGlobSetting } from '/@/hooks/setting';
 
 // import * as dat from 'dat.gui';
 // const gui = new dat.GUI();
@@ -11,7 +13,7 @@ import useEvent from '../../../../utils/threejs/useEvent';
 
 // 模型对象、 文字对象
 let model: UseThree,
-  singleWindowObj: singleWindow,
+  singleWindowObj: singleWindow | singleWindowBet,
   doubleWindowObj: doubleWindow,
   group: THREE.Object3D,
   windowType = 'singleWindow';
@@ -40,38 +42,8 @@ const addLight = () => {
   pointLight6.position.set(51, 51, 9);
   pointLight6.shadow.bias = 0.05;
   model.scene.add(pointLight6);
-
-  // const pointLight7 = new THREE.PointLight(0xffffff, 1, 1000);
-  // pointLight7.position.set(45, 51, -4.1);
-  // pointLight7.shadow.bias = 0.05;
-  // model.scene.add(pointLight7);
-
-  // const spotLight = new THREE.SpotLight();
-  // spotLight.angle = Math.PI / 16;
-  // spotLight.penumbra = 0;
-  // spotLight.castShadow = true;
-  // spotLight.intensity = 1;
-  // spotLight.position.set(-231, 463, 687);
-  // model.scene.add(spotLight);
-
-  // spotLight.shadow.camera.near = 0.5; // default
-  // spotLight.shadow.camera.far = 1000; // default
-  // spotLight.shadow.focus = 1.2;
-  // spotLight.shadow.bias = -0.000002;
-
-  // gui.add(directionalLight.position, 'x', -1000, 1000);
-  // gui.add(directionalLight.position, 'y', -1000, 1000);
-  // gui.add(directionalLight.position, 'z', -1000, 1000);
 };
 
-// // 重置摄像头
-// const resetCamera = () => {
-//   model.camera.position.set(30.328, 58.993, 148.315);
-//   model.camera.rotation.set(-31.85, 30.07, 17.29);
-//   model.orbitControls?.update();
-//   model.camera.updateProjectionMatrix();
-// };
-
 // 初始化左右摇摆动画
 const startAnimation = () => {
   // 定义鼠标点击事件
@@ -161,6 +133,7 @@ export const setModelType = (type) => {
 };
 
 export const mountedThree = (playerDom) => {
+  const { sysOrgCode } = useGlobSetting();
   return new Promise(async (resolve) => {
     model = new UseThree('#window3D');
     if (!model || !model.renderer || !model.camera) return;
@@ -169,7 +142,12 @@ export const mountedThree = (playerDom) => {
     model.camera.position.set(100, 0, 1000);
     // 单道、 双道
     doubleWindowObj = new doubleWindow(model);
-    singleWindowObj = new singleWindow(model);
+    if (sysOrgCode === 'sdmtjtbetmk') {
+      singleWindowObj = new singleWindowBet(model);
+    } else {
+      singleWindowObj = new singleWindow(model);
+    }
+
     doubleWindowObj.mountedThree(playerDom);
     singleWindowObj.mountedThree(playerDom);
     model.animate();