Răsfoiți Sursa

[Feat 0000] 添加喷淋-喷砂模型

houzekong 2 luni în urmă
părinte
comite
78965cbfe8

+ 1 - 1
src/views/vent/monitorManager/sprayMonitor/index.vue

@@ -378,7 +378,7 @@
     configs.value = zuhuabengConfigs;
     loading.value = true;
     mountedThree('#spray3D', ['#sprayCSS3D', '#sprayCSS3DEnvA', '#sprayCSS3DEnvB']).then(() => {
-      setModelType('spray').finally(() => {
+      setModelType('pensha').finally(() => {
         loading.value = false;
       });
     });

+ 19 - 2
src/views/vent/monitorManager/sprayMonitor/spray.three.ts

@@ -1,9 +1,12 @@
 import * as THREE from 'three';
 import UseThree from '../../../../utils/threejs/useThree';
 import ModelContext from './spray.threejs.base';
+import PenshaContext from './spray.threejs.pensha';
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
 
+type modelName = 'spray' | 'pensha';
+
 /** 模型总控制器 */
 let model: UseThree;
 /** 当前展示的具体模型的 Object3D 对象 */
@@ -11,7 +14,7 @@ let group: THREE.Object3D;
 /** 具体模型内容列表,包含此模型总控制器下的所有可用的具体模型内容 */
 const modelContextList: {
   /** 当前模型类型,在控制器下有多个具体模型时分辨它们 */
-  type: string;
+  type: modelName;
   /** 模型的具体内容,即负责模型导入、绘制的上下文对象,一个控制器可以新建多个 */
   context?: ModelContext;
 }[] = [];
@@ -52,11 +55,12 @@ function initEventListender() {
 // }
 
 /** 设置模型类型并切换,不同的类型通常对应不同的具体模型,在模型总控制器下的具体模型会根据传入的参数彼此交互、切换 */
-export function setModelType(modelType: 'spray') {
+export function setModelType(modelType: modelName) {
   return new Promise((resolve, reject) => {
     if (!model) return reject('模型未初始化');
     modelContextList.forEach(({ type, context }) => {
       if (!context) return reject('模型未初始化');
+      // 如果是指定类型的模型,则显示该模型,否则应该检查是否已经存在该模型,如果存在则隐藏
       if (modelType === type) {
         group = context?.group as THREE.Object3D;
         setTimeout(async () => {
@@ -66,6 +70,12 @@ export function setModelType(modelType: 'spray') {
           await animateCamera({ x: -693, y: 474, z: 398 }, { x: 0, y: 0, z: 0 }, context.cameraPostion, context.orbitTarget, model, 0.8);
           resolve(null);
         }, 400);
+      } else {
+        const group = context?.group;
+        const name = group?.name;
+        if (name && group && model.scene?.getObjectByName(name)) {
+          model.scene?.remove(group);
+        }
       }
     });
   });
@@ -87,6 +97,13 @@ export function mountedThree(sceneSelctor: string, cssSelectors: string[]) {
       type: 'spray',
       context: model1,
     });
+    const model2 = new PenshaContext(model);
+    await model2.mountedThree();
+    model2.initCssElement(selectors);
+    modelContextList.push({
+      type: 'pensha',
+      context: model2,
+    });
 
     initEventListender();
     model.animate();

+ 108 - 0
src/views/vent/monitorManager/sprayMonitor/spray.threejs.pensha.ts

@@ -0,0 +1,108 @@
+import * as THREE from 'three';
+import { CSS3DSprite } from 'three/examples/jsm/renderers/CSS3DRenderer';
+import { setModalCenter } from '/@/utils/threejs/util';
+// import { setModalCenter } from '/@/utils/threejs/util';
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class ModelContext {
+  model;
+  modelName = 'spray-pensha';
+  // modelName = 'spray-ts';
+  // modelName = 'dedust';
+  group: THREE.Object3D | null = null;
+  /** 本模型内支持的锚点位置数组 */
+  anchors: [number, number, number][] = [
+    [1.5, 0.5, 1.6],
+    // [0, 0, 0],
+    // 右侧传感器
+    [1.3, 0.5, 1.6],
+    // [-25.847, 8.783, 3.267],
+    // [31.142, 8.783, 3.267],
+  ];
+  /** 本模型显示的css详情元素数组 */
+  cssSprites: CSS3DSprite[] = [];
+  /** 初始化时用到的摄像头位置参数,可以供外部访问或初始化时使用 */
+  cameraPostion = {
+    x: 2.0063999826191625,
+    y: 0.3963997081529602,
+    z: 3.275298992446514,
+  };
+  /** 初始化时用到的滑轨目标参数,可以供外部访问或初始化时使用,配合摄像头可以实现更精确的控制 */
+  orbitTarget = {
+    x: 2.023679325280445,
+    y: -0.1461634482645532,
+    z: 0.04677126793423104,
+  };
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
+    directionalLight.position.set(6.3, 28, 20);
+    this.group?.add(directionalLight);
+    directionalLight.target = this.group as THREE.Object3D;
+
+    const pointLight = new THREE.PointLight(0xffffff, 1, 1000);
+    pointLight.position.set(45, 51, -4.1);
+    pointLight.shadow.bias = 0.05;
+    this.model.scene.add(pointLight);
+  }
+
+  /** 初始化css元素,将css元素选择器传入,该方法会将这些元素按顺序放入本模型支持的锚点中 */
+  initCssElement(selectors: string[]) {
+    selectors.forEach((selector, index) => {
+      const element = document.querySelector(selector) as HTMLElement;
+      if (element) {
+        const css3D = new CSS3DSprite(element);
+        this.cssSprites.push(css3D);
+        css3D.name = selector;
+        css3D.scale.set(0.002, 0.002, 0.002);
+        // const ff = gui.addFolder(`css元素${index}`);
+        // ff.add(css3D.position, 'x', -100, 100);
+        // ff.add(css3D.position, 'y', -100, 100);
+        // ff.add(css3D.position, 'z', -100, 100);
+        if (index < this.anchors.length) {
+          const [x, y, z] = this.anchors[index];
+          css3D.position.set(x, y, z);
+          this.group?.add(css3D);
+        } else {
+          console.warn(`指定的元素${selector}没有合适的位置放置`);
+        }
+      }
+    });
+  }
+
+  /** 清除css元素 */
+  clearCssElement() {
+    this.cssSprites.forEach((sprite) => {
+      this.group?.remove(sprite);
+    });
+    this.cssSprites = [];
+  }
+
+  mountedThree() {
+    return new Promise((resolve) => {
+      this.model.setGLTFModel([this.modelName]).then(async (gltf) => {
+        this.group = gltf[0];
+        if (this.group) {
+          setModalCenter(this.group);
+          resolve(null);
+          // this.addLight();
+        }
+      });
+    });
+  }
+
+  destroy() {
+    if (this.model) {
+      this.model.clearGroup(this.group);
+      this.model = null;
+      this.group = null;
+    }
+  }
+}
+export default ModelContext;