wuhb 1 year ago
parent
commit
e708c07e6a
3 changed files with 205 additions and 30 deletions
  1. 1 1
      gltf/gltf.json
  2. 159 21
      src/layout/index.vue
  3. 45 8
      src/utils/objectSelect.ts

+ 1 - 1
gltf/gltf.json

@@ -27,7 +27,7 @@
 ,{"name":"冰机", "value":"冰机.gltf", "scaleX":0.01, "scaleY":0.01, "scaleZ":0.01, "posY":0}
 ,{"name":"钾离心机", "value":"钾离心机.gltf", "scaleX":0.01, "scaleY":0.01, "scaleZ":0.01, "posY":0}
 ,{"name":"芒硝离心机", "value":"芒硝离心机.gltf", "scaleX":0.01, "scaleY":0.01, "scaleZ":0.01, "posY":0}
-,{"name":"4组吸附罐", "value":"40组/吸附罐-4罐.gltf", "scaleX":10, "scaleY":10, "scaleZ":10, "posY":0}
+,{"name":"4组吸附罐", "value":"40组/吸附罐-4罐.gltf", "scaleX":1, "scaleY":1, "scaleZ":1, "posY":0}
 ,{"name":"40组吸附罐", "value":"40组/F1A1CAE88061AEC93.gltf", "scaleX":0.01, "scaleY":0.01, "scaleZ":0.01, "posY":0}
 ,{"name":"深锥", "value":"shengzhui/深锥.draco.gltf", "scaleX":10, "scaleY":10, "scaleZ":10, "posY":0}
 ]

+ 159 - 21
src/layout/index.vue

@@ -54,7 +54,7 @@
   import {Cube} from '@/utils/cube'
   import {Wall} from '@/utils/wall'
   import { initAxesHelper } from '@/utils/initScene'
-  import { ObjectSelect } from '@/utils/objectSelect'
+  import { ObjectSelect , clearSelect} from '@/utils/objectSelect'
   import { fullscreenToggel } from '@/utils/screen'
   import { getWallData } from '@/stores/data'
   import gltfJson from '../../gltf/gltf.json'
@@ -63,6 +63,7 @@
   import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
   import { DragControls } from 'three/examples/jsm/controls/DragControls.js';
   import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
+  import Stats from 'three/examples/jsm/libs/stats.module.js'
   import { ElLoading } from 'element-plus'
   
   const dom = ref<HTMLDivElement>()
@@ -70,6 +71,7 @@
   var cameraPos = {"y":200, "z":600};
   let selMesh:any
   let outlinePass: any;
+  let sellinePass: any;
   var scene:any;
   var settings = {selMesh: selMesh, color: '#ff0000' , x: 0, y: 0, z:0, rx:0, ry:0, rz:0, sx:1, sy:1, sz:1}
   let pathname:any;
@@ -96,6 +98,14 @@
   }
   showView();
   
+  // const showStats =() =>{
+  //   var stats = new Stats();
+  //   stats.dom.style.position = 'absolute';
+  //   stats.dom.style.top = '45px';
+  //   document.body.appendChild(stats.dom);
+  // }
+  // showStats();
+
   const isFullScreen=()=>{
     isShowView(false);
     fullscreenToggel();
@@ -163,7 +173,7 @@
 
   function addGeometry(val:string){
     var cube = initGeometry(val);
-    var minY = calculateModelBottomY(cube);
+    var minY = calculateModelBottomY(cube) * cube.scale.y;
     minY = -minY + 5
     cube.position.set(0, minY, 0);
     dragModel(cube);
@@ -188,13 +198,19 @@
       if(!scaleX)scaleX = 1;
       if(!scaleY)scaleY = 1;
       if(!scaleZ)scaleZ = 1;
+      baseScaleX = scaleX;
+      baseScaleY = scaleY;
+      baseScaleZ = scaleZ;
       originaMesh.scale.set(scaleX, scaleY, scaleZ)
-      var box = new THREE.Box3().setFromObject(originaMesh);
       var minY = calculateModelBottomY(originaMesh);
       if(posY){
         originaMesh.position.set(0,posY,0);
       }else{
-        minY = (-minY/100) + 5
+        if(originaMesh.scale.y<1){
+          minY = (-minY * originaMesh.scale.y) + 5
+        }else{
+          minY = 5
+        }
         originaMesh.position.set(0,minY,0);
       }
       originaMesh.name = "file_"+modelName+"_"+new Date().getTime();
@@ -219,7 +235,7 @@
       let originaMesh = mod.scene.children[0]
       originaMesh.scale.set(params.sx, params.sy, params.sz)
       originaMesh.position.set(params.x,params.y,params.z);
-      originaMesh.rotation.set(params.rx, params.ry, params.rz)
+      originaMesh.rotation.set(degreesArc(params.rx), degreesArc(params.ry), degreesArc(params.rz))
       originaMesh.name = params.name;
       dragModel(originaMesh);
       scene.add(originaMesh)
@@ -240,10 +256,11 @@
     dragControls.addEventListener("dragend", ()=>{
       control.enabled = true;
       if(settings.selMesh && model.name == settings.selMesh.name){
-        settings.x = model.position.x;
         settings.y = model.position.y;
+        settings.x = model.position.x;
         settings.z = model.position.z;
       }
+      checkY(model);
     })
     // 监听mouseDown事件
     renderer.domElement.addEventListener('mousedown', (event) => {
@@ -296,9 +313,9 @@
     const baseX = getDecimalDigits(baseScaleX);
     const baseY = getDecimalDigits(baseScaleY);
     const baseZ = getDecimalDigits(baseScaleZ);
-    gui.add(settings, 'sx', -baseScaleX*1000, baseScaleX*1000).name('缩放X').step(0.001);
-    gui.add(settings, 'sy', -baseScaleY*1000, baseScaleY*1000).name('缩放Y').step(0.001);
-    gui.add(settings, 'sz', -baseScaleZ*1000, baseScaleZ*1000).name('缩放Z').step(0.001);
+    gui.add(settings, 'sx', -baseScaleX*1000, baseScaleX*1000).name('缩放X').step(baseScaleX/10);
+    gui.add(settings, 'sy', -baseScaleY*1000, baseScaleY*1000).name('缩放Y').step(baseScaleY/10);
+    gui.add(settings, 'sz', -baseScaleZ*1000, baseScaleZ*1000).name('缩放Z').step(baseScaleY/10);
   }
   
   const initLight = () => {
@@ -337,12 +354,16 @@
     prevHeight = currentHeight;
   })
 
-  window.addEventListener('contextmenu', ()=>{
+  window.addEventListener('contextmenu', (e)=>{
     settings.selMesh = null;
     outlinePass.selectedObjects = [];
+    sellinePass.selectedObjects = [];
+    clearSelect();
+    drawer.value = false;
     if(gui){
       gui.destroy();
     }
+    e.stopPropagation()
   })
 
   function updateFloor(){
@@ -450,14 +471,28 @@
     outlinePass.visibleEdgeColor.set('#B31985');//包围线颜色
     outlinePass.hiddenEdgeColor.set('#190a05');//被遮挡的边界线颜色
   }
+
+  const initSelLine= () =>{
+    let vector = new THREE.Vector2(window.innerWidth, window.innerWidth);
+    sellinePass = new OutlinePass(vector, scene, camera);
+    sellinePass.edgeStrength = 10;//包围线浓度
+    sellinePass.edgeGlow = 0.1;//边缘线范围
+    sellinePass.edgeThickness = 1;//边缘线浓度
+    sellinePass.pulsePeriod = 2;//包围线闪烁评率
+    sellinePass.visibleEdgeColor.set('#1E90FF');//包围线颜色
+    sellinePass.hiddenEdgeColor.set('#B0E0E6');//被遮挡的边界线颜色
+  }
+
   const initComposer =() =>{
       let renderPass = new RenderPass(scene, camera);
       let composer = new EffectComposer(renderer);
       composer.addPass(renderPass);
       composer.addPass(outlinePass);
+      composer.addPass(sellinePass)
       return composer;
   }
   initoutLine();
+  initSelLine();
   let composer = initComposer();
   
   // 计算模型底部Y坐标的函数
@@ -475,6 +510,25 @@
       return minY;
   }
 
+  // 计算模型底部Y坐标的函数
+  function calculateModelTopY(object3D:any) {
+      let maxY = Infinity;
+      object3D.traverse(function (child:any) {
+          if (child.isMesh) {
+              const geometry = child.geometry;
+              if (geometry.boundingBox === null) {
+                  geometry.computeBoundingBox();
+              }
+              if(maxY == Infinity){
+                maxY = geometry.boundingBox.max.y;
+              }else{
+                maxY = Math.max(maxY, geometry.boundingBox.max.y);
+              }
+          }
+      });
+      return maxY;
+  }
+
   const clickHandle = (selectObject:any, frm:number) =>{
     drawer.value = false;
     if(!isOperater.value){
@@ -534,7 +588,11 @@
     var box = new THREE.Box3().setFromObject(settings.selMesh);
     var minY = calculateModelBottomY(settings.selMesh);
     if(settings.selMesh.name.startsWith("file_")){
-      minY = (-minY/100) + 5
+      if(settings.selMesh.scale.y > 1){
+        minY = 5
+      }else{
+        minY = (-minY*settings.selMesh.scale.y) + 5
+      }
     }else{
        minY = -minY + 5
     }
@@ -547,7 +605,7 @@
     initGUI(-x, x, minY, y_top, -z, z);
   }
   
-  ObjectSelect(scene, camera, outlinePass, clickHandle)
+  ObjectSelect(scene, camera, outlinePass, sellinePass, clickHandle)
   
   const updateModel =() =>{
     if(settings.selMesh
@@ -580,9 +638,7 @@
   }
 
   // 渲染函数
-  const clock = new THREE.Clock()
   const render = () => {
-    const delta = clock.getDelta()
     requestAnimationFrame(render)
     renderer.render(scene, camera)
     composer.render();
@@ -700,6 +756,7 @@
         gui.destroy()
         gui = null;
       }
+
       // var modelName = settings.selMesh;
       // if (scene.getObjectByName(modelName)) {
       //     var model = scene.getObjectByName(modelName);
@@ -727,27 +784,108 @@
     if (event.key === 'Escape'|| event.keyCode === 27) {
       isShowView(true);
     }
+    if((event.ctrlKey || event.key.indexOf('Control') > -1) && (event.key.indexOf("Up") > -1|| event.keyCode === 38)){
+      moveObject('Y+');
+    }else
+    if((event.ctrlKey || event.key.indexOf('Control') > -1) && (event.key.indexOf("Down") > -1 || event.keyCode === 40)){
+      moveObject('Y-');
+    }else
     if(event.key.indexOf("Up") > -1|| event.keyCode === 38){
+      moveObject('Z-');
+    }else
+    if(event.key.indexOf("Down") > -1 || event.keyCode === 40){
+      moveObject('Z+');
+    }else
+    if(event.key.indexOf("Left") > -1|| event.keyCode === 37){
+      moveObject('X-');
+    }else
+    if(event.key.indexOf("Right") > -1 || event.keyCode === 39){
+      moveObject('X+');
+    }
+  });
+
+  function moveObject(axes:any){
+    if(axes == 'Y+'){
       if(settings.selMesh){
-        settings.z = settings.z - 1
+        settings.y = settings.y + 1
+      }
+      var objects = sellinePass.selectedObjects;
+      for(var ix in objects){
+        var obj = objects[ix]
+        obj.position.y = obj.position.y + 1
       }
     }
-    if(event.key.indexOf("Down") > -1 || event.keyCode === 40){
+    if(axes == 'Y-'){
       if(settings.selMesh){
-        settings.z = settings.z + 1
+        settings.y = settings.y - 1
+        checkY(settings.selMesh)
+      }
+      var objects = sellinePass.selectedObjects;
+      for(var ix in objects){
+        var obj = objects[ix]
+        obj.position.y = obj.position.y - 1
+        checkY(settings.selMesh)
       }
     }
-    if(event.key.indexOf("Left") > -1|| event.keyCode === 37){
+
+    if(axes == 'X+'){
+      if(settings.selMesh){
+        settings.x = settings.x + 1
+      }
+      var objects = sellinePass.selectedObjects;
+      for(var ix in objects){
+        var obj = objects[ix]
+        obj.position.x = obj.position.x + 1
+      }
+    }
+    if(axes == 'X-'){
       if(settings.selMesh){
         settings.x = settings.x - 1
       }
+      var objects = sellinePass.selectedObjects;
+      for(var ix in objects){
+        var obj = objects[ix]
+        obj.position.x = obj.position.x - 1
+      }
     }
-    if(event.key.indexOf("Right") > -1 || event.keyCode === 39){
+
+    if(axes == 'Z+'){
       if(settings.selMesh){
-        settings.x = settings.x + 1
+        settings.z = settings.z + 1
+      }
+      var objects = sellinePass.selectedObjects;
+      for(var ix in objects){
+        var obj = objects[ix]
+        obj.position.z = obj.position.z + 1
       }
     }
-  });
+    if(axes == 'Z-'){
+      if(settings.selMesh){
+        settings.z = settings.z - 1
+      }
+      var objects = sellinePass.selectedObjects;
+      for(var ix in objects){
+        var obj = objects[ix]
+        obj.position.z = obj.position.z - 1
+      }
+    }
+  }
+
+  function checkY(model:any){
+    var minY = 5;
+    var boundY = calculateModelBottomY(model);
+    if(model.name.startsWith("file_")){
+      if(model.scale.y < 1){
+        minY = Math.abs(boundY * model.scale.y) + 5;
+      }
+    }else{
+      minY = -boundY + 5;
+    }
+    if(model.position.y < minY){
+      model.position.y = minY;
+      settings.y = minY;
+    }
+  }
 
   function handleFileUpload(event:any){
     const file = event.raw;

+ 45 - 8
src/utils/objectSelect.ts

@@ -3,26 +3,37 @@ import * as THREE from 'three';
 var raycaster = new THREE.Raycaster();
 var mouse = new THREE.Vector2();
 var selectedObjects: any|[];
-var isDragging = false; 
+var selObjects: any|[];
+var isDragging = false;
+var isClick = false;
 
-export const ObjectSelect = (_scene:any, _camera:any,outlinePass:any, clickHandle:any) => {
+export const ObjectSelect = (_scene:any, _camera:any,outlinePass:any, sellinePass:any, clickHandle:any) => {
     /****************************************************************************************************************************
      * 外包围处理*
      * @type {THREE.OutlinePass}
      */
 
     selectedObjects = []
+    selObjects = []
     window.addEventListener( 'click', onMouseClick);
     window.addEventListener('dblclick', onMouseDbClick);
     window.addEventListener('mousemove', onMouseMove);
     window.addEventListener('mousedown', onMouseDown);
+    window.addEventListener('mouseup', onMouseUp);
 
     function onMouseDown(event:any){
         isDragging = false;
+        isClick = true;
     }
-
-    function onMouseMove(event:any){
+    function onMouseUp(event:any){
         isDragging = true;
+        isClick = false;
+    }
+    
+    function onMouseMove(event:any){
+        if(isClick){
+            isDragging = true;
+        }
     }
 
     function onMouseClick(event: any) {
@@ -37,13 +48,30 @@ export const ObjectSelect = (_scene:any, _camera:any,outlinePass:any, clickHandl
         if (intersects.length == 0) {
             return;
         }
-        if(isDragging){
+        if(isDragging && !event.ctrlKey){
             isDragging = false;
             return;
         }
-        let selectObject;
+        let selectObject:any;
         selectObject=intersects[0].object;
-        clickHandle(selectObject, 3);
+        if(event.ctrlKey){
+            while(selectObject!=null 
+                && selectObject.parent?.type!='Scene'){
+                if(selectObject == null){
+                    break;
+                }
+                selectObject = selectObject.parent;
+            }
+            if(selectedObjects.length > 0 && selectObject && selectedObjects[0].name == selectObject.name){
+                return;
+            }
+            if(!selObjects.includes(selectObject)){
+                selObjects.push(selectObject)
+            }
+            sellinePass.selectedObjects = selObjects
+        }else{
+            clickHandle(selectObject, 3);
+        }
         // if(selectObject.name && 
         //     (selectObject.name.startsWith("wall")||selectObject.name.startsWith("floor")
         //     ||selectObject.name.startsWith("door"))){
@@ -74,7 +102,7 @@ export const ObjectSelect = (_scene:any, _camera:any,outlinePass:any, clickHandl
         if (intersects.length == 0) {
             return;
         }
-        let selectObject;
+        let selectObject:any;
         selectObject=intersects[0].object;
         if (selectObject.name && selectObject.name.startsWith("default_")
             ||selectObject.name.startsWith("floor")) {         
@@ -96,8 +124,17 @@ export const ObjectSelect = (_scene:any, _camera:any,outlinePass:any, clickHandl
             }
             selectedObjects.pop();
             selectedObjects.push(selectObject);
+            selObjects = selObjects.filter((item:any)=>{
+                return item.name != selectObject.name;
+            });
+            sellinePass.selectedObjects = selObjects;
             outlinePass.selectedObjects = selectedObjects;//给选中的线条和物体加发光特效
         }
         clickHandle(selectObject);
     }
+}
+
+export const clearSelect = ()=>{
+    selectedObjects = []
+    selObjects = []
 }