Three.js三维前端文档

991 阅读4分钟

三维前端文档

1.整体流程图

png (2).png

2.实现步骤
  1. 创建本地数据库

     connect.onupgradeneeded = function (event) {
          console.log("数据库更新")
          db = event.target.result;
          // 判断是否有这个表
          if (!db.objectStoreNames.contains('person')) {
            // 创建表
            var objectStore;
            objectStore = db.createObjectStore('person', {
              // 主键
              keyPath: 'id'
            });
            // 创建索引
            objectStore.createIndex('blob', 'blob', {
              // 是否唯一
              unique: false
            });
            objectStore.createIndex('name', 'name', {
              // 是否唯一
              unique: true
            });
          }
        }
    
  2. 查找本地模型

function find(storename, key, callback) {
      let store = db.transaction(storename, 'readwrite').objectStore(storename);
      let request = store.get(key);
      request.onerror = function () {
        console.error('getDataByKey error');
      };
      request.onsuccess = function (e) {
        // 查到了
        if (result) {
          var url = URL.createObjectURL(result.blob)
          THREE.DRACOLoader.setDecoderPath('three/examples/js/libs/draco/gltf/'); //设置解压库文件路径
          var dracoLoader = new THREE.DRACOLoader();
          gltfloader.setDRACOLoader(dracoLoader);
          gltfloader.load(url, function (gltf) {
            // 清理 blob协议缓存
            // URL.revokeObjectURL(url)
            scene.add(gltf.scene)
            setCameraHide(false);
            addCameraImg()
            gltf.scene.position.set(-5, 0, 0);
            setTimeout(() => {
              renderDailog();
              console.log('渲染结束', new Date());

            }, 10)
            if (callback) {
              callback(result);
            }
          });
        } else {
          console.log('没查到');
          console.log('开始下载', new Date());
          xhr.send();
        }
      }
    }
  1. 下载模型
 var xhr = new XMLHttpRequest(),
      blob;

    xhr.open("GET", url, true);
    // Set the responseType to blob
    xhr.responseType = "blob";
    xhr.addEventListener("load", function () {
      if (xhr.status === 200) {
        console.log('下载结束', new Date());
        // File as response
        blob = xhr.response;
        addData('person', {
          id: 'parkwh',
          blob: blob
        }, () => {
          console.log('添加成功-开始查询')
          find('person', 'parkwh', () => {
            console.log('查找结束')
          })
        })
        // Put the received blob into IndexedDB
        // putElephantInDb(blob);
      }
    }, false);
  1. 添加indexDb
function addData(storename, data, callback) {
      let store = db.transaction(storename, 'readwrite').objectStore(storename);
      let request = store.add(data);
      request.onerror = function () {
        console.error('add添加数据库中已有该数据')
      };
      request.onsuccess = function () {
        console.log('add添加数据已存入数据库')
        callback();
      };
    }
  1. gltfLoader加载模型,模型添加至场景,设置模型初始位置
 var url = URL.createObjectURL(result.blob)
          // let loader = new THREE.GLTFLoader();
          THREE.DRACOLoader.setDecoderPath('three/examples/js/libs/draco/gltf/'); //设置解压库文件路径
          var dracoLoader = new THREE.DRACOLoader();
          gltfloader.setDRACOLoader(dracoLoader);
          gltfloader.load(url, function (gltf) {
            // 清理 blob协议缓存
            // URL.revokeObjectURL(url)
            scene.add(gltf.scene)
            setCameraHide(false);
            addCameraImg()
            gltf.scene.position.set(-5, 0, 0);
            setTimeout(() => {
              renderDailog();
              console.log('渲染结束', new Date());

            }, 10)
            if (callback) {
              callback(result);
            }
          });
        }
  1. 通知主程序点位坐标
const renderDailog = () => {
    let ad = [];
    if (!scene) return null;
    const arr = scene.children.find((d) => d.type === 'Scene');
    const text = arr.children.find((d) => d.name === "warning");

    const dataS = [];
    if (text && text.children) {
        text.children.map((li) => {
            li.getWorldPosition(worldVector);
            // 特殊情况下,局部坐标等于世界坐标
            // var worldVector = boxMesh.position.clone();
            // 世界坐标转标准设备坐标,standardVector是WebGL标准设备坐标
            // .project()方法提取相机参数的视图矩阵、投影矩阵对世界坐标进行变换
            const standardVector = worldVector.project(camera);
            const a = width / 2;
            const b = height / 2;
            const x = Math.round(standardVector.x * a + a); // 模型标签x坐标,单位像素
            const y = Math.round(-standardVector.y * b + b); // 模型标签y坐标,单位像素
            li.domTop = y;
            li.domLeft = x;
            dataS.push({
                name: li.name.replace('dw-', '').replace('dw_', ''),
                domTop: li.domTop,
                domLeft: li.domLeft,
            });

        });
    }

    sendMessage('dailog', dataS);
};
    
const sendMessage = (title, obj) => {
    var data = {
        name: title,
        data: obj,
    };
    window.parent.postMessage(data, '*'); //window.postMessage
};
  1. 摄像头隐藏

    const setCameraHide = (bool) => {

      if (!scene) return;
      const sce = scene.children.find(d => d.type === "Scene")
      if (!sce) return;
      const obj = sce.children.find(d => d.name === "cameras")
      if (!obj) return;
      if (bool) {
        obj.children.map((d) => {
          if (bool.data[d.name.replace('sxt_', '').replace('sxt-', '')]) {
            d.children?.map((li) => {
              li.visible = true;
            })
          }

        })
      } else {
        obj.children.map((d) => {
          d.children?.map((li) => {
            li.visible = bool;
          })
        })
      }

    }
  1. 入口隐藏
const addCameraImg = () => {

      if (!scene) return;
      const sce = scene.children.find(d => d.type === "Scene")
      console.log(sce, '----')
      if (!sce) return;
      const cameras = sce.children.find(d => d.name === "cameras")
      if (!cameras) return;
      const warnings = sce.children.find(d => d.name === "warning")
      const titles = sce.children.find(d => d.name === "文字")

      warnings?.children.map((d) => {
        d.material.visible = false;
      })

      titles?.children.map((d) => {
        // d.material.visible = false;
        d.children?.map((li) => {
          li.material.visible = false;
        })

        setTitle(d)
      })
      console.log(cameraData, 'cameraData')

      cameras?.children.map((d) => {
        d.material.visible = false;
        setLabel(d);
      })
      cameras?.children.map((d) => {
        d.children?.map((li) => {
          li.visible = false;
        })
      })
    }
  1. 自定义摄像头/入口
const setLabel = (onjectValue) => {
    var labelDiv = document.createElement('div')
    labelDiv.className = 'label';
    labelDiv.name = onjectValue.name;
    labelDiv.ondblclick = cameraClick;
    var earthLabel = new THREE.CSS2DObject(labelDiv)
    onjectValue.add(earthLabel)
}
const setTitle = (onjectValue) => {
    const arr =
          [
              {
                  code: 'fftl', name: '浮法脱硫'
              },
              {
                  code: "cc1", name: '仓储1'
              },
              {
                  code: "cc2", name: '仓储2'
              },
              {
                  code: "dd500", name: '电子500T'
              },
              {
                  code: "dmrx", name: '镀膜二线'
              },
              {
                  code: "dmsx", name: '镀膜三线'
              },
              {
                  code: "dmyx", name: '镀膜一线'
              },
              {
                  code: "dz200", name: '电子200T'
              },
              {
                  code: "dzcy", name: '电子储运'
              },
              {
                  code: "dztltx", name: '电子脱硫脱硝'
              },
              {
                  code: "ff500", name: '浮法500T'
              },
              {
                  code: "ff600", name: '浮法600T'
              },
              {
                  code: "ff700", name: '浮法700T'
              },
              {
                  code: "ff900", name: '浮法900T'
              },
              {
                  code: "trqzq", name: '天然气制氢'
              },
              {
                  code: "yqdqz", name: '一期氮氢站'
              },
              {
                  code: "dz", name: '氮站'
              },
              {
                  code: "dztl", name: '电子脱硫'
              },
              {
                  code: "dztx", name: '电子脱硝'
              },
          ]
    const obj = arr.find((d) => d.code === onjectValue.name)
    if (obj && obj.name) {
        var labelDiv = document.createElement('div')
        labelDiv.className = 'title';
        labelDiv.innerText = obj.name;
        labelDiv.id = obj.code;
        labelDiv.name = onjectValue.name;
        labelDiv.ondblclick = enterLine;
        var earthLabel = new THREE.CSS2DObject(labelDiv)
        onjectValue.add(earthLabel)
    }
}
  1. 设置灯光/相机/渲染器
const setLight = () => {
    //环境光
    var ambient = new THREE.AmbientLight(0xC4C4C4, 1);
    var point = new THREE.PointLight(0xC4C4C4, 1);
    var point1 = new THREE.PointLight(0xC4C4C4, 1);
    var point2 = new THREE.PointLight(0xC4C4C4, 1);
    // 点光源

    point.position.set(-15.432835578918457, 37.574790954589844, 77.27122497558594); // 点光源位置
    point1.position.set(356.2715148925781, 127.52357482910156, -142.99517822265625); // 点光源位置
    point2.position.set(-54.23904037475586, 28.659584045410156, -59.19256591796875); // 点光源位置

    scene.add(point); // 点光源添加到场景中
    scene.add(point1); // 点光源添加到场景中
    scene.add(point2); // 点光源添加到场景中
    // 环境光
    // scene.add(ambient);
};

/**
     * 相机设置
     */
const setCamera = () => {
    camera.position.set(11.582765074860337, 80.84475536367229, 154.73173390246936); // 设置相机位置
    camera.lookAt(new THREE.Vector3(0, 0, 0)); // 设置相机方向(指向的场景对象)
};

/**
     * 创建渲染器对象
     */
const setRender = () => {
    renderer.shadowMap.enabled = false;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.setSize(width, height); // 设置渲染区域尺寸
    // renderer.setClearColor(0x000000, 1); // 设置背景颜色
    document.body.appendChild(renderer.domElement); // body元素中插入canvas对象
    labelRenderer = new THREE.CSS2DRenderer();
    labelRenderer.setSize(width, height);
    labelRenderer.domElement.style.position = "absolute";
    labelRenderer.domElement.style.top = 0;
    document.body.appendChild(labelRenderer.domElement);
};
  1. 增加双击事件/划过事件
function dbclick(event) {
    if (!scene) return;
    if (!scene.children.find((d) => d.type === 'Scene')) return;

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    const arr = scene.children.find((d) => d.type === 'Scene');
}

function mouseover(event) {
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    const arr = scene.children.find((d) => d.type === 'Scene');
    const text = arr.children.find((d) => d.name === '文字');
    var intersects = raycaster.intersectObjects(text.children, true);
    if (intersects.length > 0) {
        selectObj && (selectObj.material.color = oldColor);
        selectObj = intersects[0].object;
        var {
            r,
            g,
            b
        } = {
            ...selectObj.material.color
        };
        oldColor = new THREE.Color(r, g, b);
        selectObj.material.color.set('#b97751');
        selectObj.material.needsUpdate = true;
    } else {
        selectObj && (selectObj.material.color = oldColor);
    }
}