Koishi před 3 měsíci
rodič
revize
be77f5ca56
2 změnil soubory, kde provedl 371 přidání a 36 odebrání
  1. 360 26
      src/components/modelUnpack.vue
  2. 11 10
      src/views/cesium.vue

+ 360 - 26
src/components/modelUnpack.vue

@@ -4,16 +4,48 @@
 </template>
  
 <script>
-import * as THREE from "../Three/Three.js";
+// import * as THREE from "../Three/Three.js";
 
-import { TEngine } from "../threeTool/ThreeEngine";
-import { allBaseObject } from "../threeTool/ThreeBaseObject";
-import { allLights } from "../threeTool/ThreeLights";
-import { getColor } from "../threeTool/ThreeColor";
-import { ThreeAxes } from "../threeTool/ThreeAxes";
+// import { TEngine } from "../threeTool/ThreeEngine";
+// import { allBaseObject } from "../threeTool/ThreeBaseObject";
+// import { allLights } from "../threeTool/ThreeLights";
+// import { getColor } from "../threeTool/ThreeColor";
+// import { ThreeAxes } from "../threeTool/ThreeAxes";
 
-import { GLTFLoader } from "../Three/examples/jsm/loaders/GLTFLoader";
-import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
+// import { GLTFLoader } from "../Three/examples/jsm/loaders/GLTFLoader";
+// import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
+
+import * as THREE from "three";
+
+import {
+  WebGLRenderer,
+  Scene,
+  PerspectiveCamera,
+  Vector3,
+  MOUSE,
+  Raycaster,
+  Vector2,
+} from "three";
+
+import { OrbitControls } from "three/addons/controls/OrbitControls.js";
+import { TransformControls } from "three/examples/jsm/controls/TransformControls";
+import {
+  CSS3DRenderer,
+  CSS3DObject,
+} from "three/examples/jsm/renderers/CSS3DRenderer";
+
+import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
+import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
+import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
+import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
+import { TDSLoader } from "three/examples/jsm/loaders/TDSLoader";
+import { MTLLoader } from "three-obj-mtl-loader";
+
+import { Color } from "../Three/Three.js";
+
+import WebGL from "../threeTool/WebGL";
+
+THREE.Cache.enabled = true;
 
 export default {
   name: "ThreeScene",
@@ -21,35 +53,337 @@ export default {
   data() {
     return {
       ThreeEngine: null,
+      scene: null,
+      camera: null,
+      renderer: null,
+      loader: null,
+      baseWidth: 0,
+      baseHeight: 0,
+      orbitControls: null,
+      css3DRenderer: null,
+      animationId: null,
     };
   },
 
   mounted() {
-    this.initThree();
+    this.initLoader();
+    this.initThree({
+      dom: this.$refs.threeCanvas,
+      showGridHelper: true,
+    });
   },
 
   methods: {
-    initThree() {
-      this.ThreeEngine = new TEngine({
-        dom: this.$refs.threeCanvas,
-        showGUI: false,
-        cameraOptions: {
-          fov: 45,
-          aspectRatio: window.innerWidth / window.innerHeight,
-          near: 0.1,
-          far: 99999,
-        },
+    initThree(options) {
+      this.$nextTick(() => {
+        const parentDom = getComputedStyle(
+          document.querySelector(".el-tabs__content"),
+          null
+        );
+
+        this.baseWidth = parentDom.width ? parseInt(parentDom.width) : 0;
+        this.baseHeight = parentDom.height ? parseInt(parentDom.height) : 0;
+
+        // 创建3D场景对象Scene
+        const scene = new THREE.Scene();
+        scene.background = this.getColor("#add8e6");
+
+        // 相机
+        const camera = new PerspectiveCamera(
+          // 视野角度(fov)
+          options?.cameraOptions?.fov || 75,
+          // 长宽比(aspect ratio)
+          options?.cameraOptions?.aspectRatio ||
+            this.baseWidth / this.baseHeight,
+          // 近截面(near)
+          options?.cameraOptions?.near || 0.1,
+          // 远截面(far)
+          options?.cameraOptions?.far || 1000
+        );
+
+        // 设置摄像机位置和朝向
+        camera.position.set(80, 100, 200); // 调整摄像机位置
+        camera.lookAt(new THREE.Vector3(0, 0, 0)); // 设置摄像机朝向场景中心
+
+        // 渲染器
+        const renderer = new WebGLRenderer({
+          antialias: true, // 开启抗锯齿
+        });
+
+        // 添加灯光
+        const ambientLight = new THREE.AmbientLight(0xffffff, 1);
+        scene.add(ambientLight);
+        const directionalLight1 = new THREE.DirectionalLight(0xffffff, 5);
+        directionalLight1.position.set(0, 0, 1);
+        scene.add(directionalLight1);
+        const directionalLight2 = new THREE.DirectionalLight(0xffffff, 5);
+        directionalLight2.position.set(0, 0, -1);
+        scene.add(directionalLight2);
+        const directionalLight3 = new THREE.DirectionalLight(0xffffff, 5);
+        directionalLight3.position.set(1, 0, 0);
+        scene.add(directionalLight3);
+        const directionalLight4 = new THREE.DirectionalLight(0xffffff, 5);
+        directionalLight4.position.set(-1, 0, 0);
+        scene.add(directionalLight4);
+        const directionalLight5 = new THREE.DirectionalLight(0xffffff, 5);
+        directionalLight5.position.set(0, 1, 0);
+        scene.add(directionalLight5);
+        const directionalLight6 = new THREE.DirectionalLight(0xffffff, 5);
+        directionalLight6.position.set(0, -1, 0);
+        scene.add(directionalLight6);
+
+        // renderer.setSize(window.innerWidth, window.innerHeight);
+        const rendererBox = getComputedStyle(options.dom, null);
+        const renderSizeWidth = parseFloat(rendererBox.width);
+        const renderSizeHeight = parseFloat(rendererBox.height);
+        renderer.setSize(renderSizeWidth, renderSizeHeight);
+
+        options?.dom?.appendChild(renderer.domElement);
+
+        const css3DRenderer = new CSS3DRenderer();
+        css3DRenderer.setSize(renderSizeWidth, renderSizeHeight);
+        css3DRenderer.render(scene, camera);
+        css3DRenderer.domElement.style.position = "absolute";
+        css3DRenderer.domElement.style.top = 0;
+        css3DRenderer.domElement.style.pointerEvents = "none";
+        options.dom.appendChild(css3DRenderer.domElement);
+
+        // 设置鼠标功能键(轨道控制器)
+        const orbitControls = new OrbitControls(camera, renderer.domElement);
+        // 移动带阻尼
+        orbitControls.enableDamping = options.enableDamping || false;
+        // 设置阻尼系数
+        orbitControls.dampingFactor = options.dampingFactor || 0;
+        // 自动旋转
+        orbitControls.autoRotate = options.autoRotate || false;
+
+        orbitControls.mouseButtons = {
+          LEFT: MOUSE.ROTATE, // 左键无功能
+          MIDDLE: MOUSE.PAN, // 中键移动
+          RIGHT: null, // 右键旋转
+        };
+
+        if (options.showGridHelper) {
+          // 底图网格 (总长宽,分多少个网格,颜色,轴线颜色,和网格颜色 #e6e8ed)
+          const gridHelper = new THREE.GridHelper(
+            2000,
+            100,
+            this.getColor("#dedede"),
+            this.getColor("#dedede")
+          );
+          gridHelper.name = "网格地板";
+          gridHelper.disalbedDelete = true;
+          scene.add(gridHelper);
+        }
+        // 初始化射线发射器
+        let raycaster = new Raycaster();
+
+        // 渲染循环
+        const animate = () => {
+          this.animationId = requestAnimationFrame(animate);
+          orbitControls.update();
+          css3DRenderer.render(scene, camera);
+          renderer.render(scene, camera);
+        };
+
+        this.scene = scene;
+        this.camera = camera;
+        this.renderer = renderer;
+        this.orbitControls = orbitControls;
+        this.css3DRenderer = css3DRenderer;
+
+        if (WebGL.isWebGLAvailable()) {
+          animate();
+          // 窗口调整大小时更新渲染器
+          window.addEventListener("resize", () => {
+            renderer.setSize(window.innerWidth, window.innerHeight);
+            camera.aspect = window.innerWidth / window.innerHeight;
+            camera.updateProjectionMatrix();
+          });
+        } else {
+          const warning = WebGL.getWebGLErrorMessage();
+          options?.dom?.appendChild(warning);
+        }
+
+        this.addModel({ fileName: "SolarPowerPlant" });
+      });
+    },
+
+    // 初始化模型加载器
+    initLoader() {
+      this.loader = {
+        glb: new GLTFLoader(),
+        gltf: new GLTFLoader(),
+        obj: new OBJLoader(),
+        fbx: new FBXLoader(),
+        "3ds": new TDSLoader(),
+      };
+    },
+
+    // 获取颜色
+    getColor(colorHex) {
+      return new Color(colorHex);
+    },
+
+    // 添加模型
+    addModel({ fileType = "glb", fileName }) {
+      const loader = this.loader[fileType];
+      loader.setResourcePath(`./static/model/${fileName}/`);
+      loader.load(`./static/model/${fileName}/model.${fileType}`, (result) => {
+        const model = result.scene;
+
+        const camera = this.camera;
+
+        // model.traverse((child) => {
+        //   if (child.material) {
+        //     child.material.emissive = child.material.color;
+        //     child.material.emissiveMap = child.material.map;
+        //   }
+        // });
+
+        // model.children.forEach((item, index) => {
+        //   item.castShadow = true;
+        //   item.receiveShadow = true;
+        // });
+
+        const baseBoxSize = new THREE.Vector3(100, 100, 100);
+        // 计算模型的包围盒(bounding box)
+        const boundingBox = new THREE.Box3().setFromObject(model);
+        const modelSize = new THREE.Vector3();
+        boundingBox.getSize(modelSize);
+
+        // 计算模型的最大尺寸
+        const maxModelSize = Math.max(modelSize.x, modelSize.y, modelSize.z);
+
+        // 计算缩放比例,使模型尺寸不超过基准盒子的尺寸
+        const scaleFactor = baseBoxSize.clone().divideScalar(maxModelSize);
+
+        // 将模型等比例缩放到适应基准盒子大小
+        model.scale.set(scaleFactor.x, scaleFactor.y, scaleFactor.z);
+
+        camera.position.z = 200;
+        console.log(222, model);
+        this.collectMaterialInfo(model);
+        this.scene.add(model);
+      });
+    },
+
+    collectMaterialInfo(model) {
+      if (!model) return;
+
+      const info = [];
+      const originalMaterials = new Map();
+
+      let materialCount = 0;
+
+      model.traverse((node) => {
+        if (node.isMesh && node.material) {
+          materialCount++;
+          const materials = Array.isArray(node.material)
+            ? node.material
+            : [node.material];
+
+          materials.forEach((material, index) => {
+            if (material.name === "Mesh_225") {
+              
+            }
+            info.push(`材质 ${materialCount}-${index + 1}: ${material.type}`);
+              info.push(`  名称: ${material.name || "未命名"}`);
+              info.push(
+                `  颜色: ${
+                  material.color ? material.color.getHexString() : "无"
+                }`
+              );
+              info.push(`  贴图: ${material.map ? "有" : "无"}`);
+              info.push(`  自发光贴图: ${material.emissiveMap ? "有" : "无"}`);
+              info.push(
+                `  金属粗糙度贴图: ${material.metalnessMap ? "有" : "无"}`
+              );
+              info.push(`  法线贴图: ${material.normalMap ? "有" : "无"}`);
+              info.push("---");
+
+              // 保存原始材质引用
+              originalMaterials.set(node.uuid + "-" + index, material);
+          });
+        }
       });
+      console.log(333, info);
+    },
+
+    overrideMaterials() {
+      if (!model) return;
+
+      model.traverse((node) => {
+        if (node.isMesh) {
+          // 创建新的基本材质
+          const newMaterial = new THREE.MeshStandardMaterial({
+            color: 0x4488ff,
+            metalness: metalness.value,
+            roughness: roughness.value,
+            emissive: new THREE.Color(0x888888).multiplyScalar(
+              emissiveIntensity.value
+            ),
+            wireframe: wireframe.value,
+          });
 
-      this.ThreeEngine.loadModel({
-        fileType: "glb",
-        dirName: "fjSolo",
-        filePath: "./static/model/fjSolo/model.glb",
-      }).then((model) => {
-        console.log(1122, model);
-        this.ThreeEngine.addObject([model]);
+          node.material = newMaterial;
+        }
       });
     },
+
+    // 废弃
+    initThreeJS() {
+      // 获取容器元素
+      const container = this.$refs.threeCanvas;
+
+      // 创建场景
+      const scene = new THREE.Scene();
+      scene.background = this.getColor("#1a1a2e");
+      // scene.background = this.getColor("#add8e6");
+      scene.add(new THREE.AmbientLight(this.getColor("#ffffff"), 2));
+
+      // 创建相机
+      const camera = new THREE.PerspectiveCamera(
+        75,
+        container.clientWidth / container.clientHeight,
+        0.1,
+        1000
+      );
+      camera.position.z = 5;
+
+      // 创建渲染器
+      const renderer = new THREE.WebGLRenderer({ antialias: true });
+      renderer.setSize(container.clientWidth, container.clientHeight);
+      renderer.setPixelRatio(window.devicePixelRatio);
+      container.appendChild(renderer.domElement);
+
+      // 添加灯光
+      const light = new THREE.DirectionalLight(0xffffff, 1);
+      light.position.set(5, 5, 5).normalize();
+      scene.add(light);
+
+      // 添加轨道控制器
+      const controls = new OrbitControls(camera, renderer.domElement);
+      controls.enableDamping = true;
+
+      this.scene = scene;
+      this.camera = camera;
+      this.renderer = renderer;
+      // this.orbitControls = orbitControls;
+      // this.css3DRenderer = css3DRenderer;
+
+      // 窗口调整大小时更新渲染器
+      window.addEventListener("resize", () => {
+        camera.aspect = container.clientWidth / container.clientHeight;
+        camera.updateProjectionMatrix();
+        renderer.setSize(container.clientWidth, container.clientHeight);
+      });
+
+      // this.addModel({
+      //   fileType: "glb",
+      //   fileName: "fjSolo",
+      // });
+    },
   },
 };
 </script>

+ 11 - 10
src/views/cesium.vue

@@ -56,10 +56,7 @@
         >
       </div>
       <div class="item">
-        <el-button
-          size="small"
-          type="primary"
-          @click="switchTopographicMap"
+        <el-button size="small" type="primary" @click="switchTopographicMap"
           >风机</el-button
         >
       </div>
@@ -134,13 +131,12 @@
       v-model="showFjDialogActiveName"
       style="width: 100%"
       type="border-card"
-      @tab-click="handleClick"
     >
       <el-tab-pane label="基础信息" name="jcxx">基础信息</el-tab-pane>
       <el-tab-pane label="视频监控" name="spjk">视频监控</el-tab-pane>
       <el-tab-pane label="故障查看" name="gzck">故障查看</el-tab-pane>
-      <el-tab-pane label="模型解构" name="third">
-        <!-- <ModelUnpack /> -->
+      <el-tab-pane label="模型解构" name="mxjg">
+        <ModelUnpack v-if="showFjDialogActiveName === 'mxjg'" />
       </el-tab-pane>
     </el-tabs>
   </el-dialog>
@@ -158,12 +154,12 @@ import windLineJson from "../assets/geoJson/windLine_2017121300.json";
 
 import axios from "axios";
 
-// import ModelUnpack from "@/components/modelUnpack.vue";
+import ModelUnpack from "@/components/modelUnpack.vue";
 export default {
   name: "CesiumMap",
 
   components: {
-    // ModelUnpack,
+    ModelUnpack,
   },
 
   data() {
@@ -309,7 +305,7 @@ export default {
 
       // 添加一些3D模型
       this.addModel(
-        "./static/model/fjSolo/model.glb",
+        "./static/model/SolarPowerPlant/model.glb",
         "风机",
         106.169866,
         38.46637
@@ -1026,6 +1022,11 @@ export default {
     .el-tabs {
       height: 100%;
 
+      .el-tab-pane {
+        width: 100%;
+        height: 100%;
+      }
+
       .el-tabs__content {
         height: 100%;
       }