加载后台返回的GLTF格式的zip包

1.下载zip包,转成二进制数据

2.二进制数据转成blob存储,本地调用

3.运行加载器,加载blob文件

 

import * as THREE from 'three'
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader'
import JSZip from 'jszip'
import {RoomEnvironment} from 'three/examples/jsm/environments/RoomEnvironment'

class LoadModel {
  constructor(params) {
    this.url=params.url
    this.arrayBuffers=[] //二进制数据
    this.fileMap={} //储存原始路径和对应blob
    this.modelUrl='' //gltf文件路径
    //指定容器
    if(params.container){
      this.container=params.container
      this.width=params.width||this.container.clientWidth
    }else {
      this.container=document.body
      this.width=params.width|| window.innerWidth
    }
    this.height=params.height|| window.innerHeight
    // console.log(this.container,this.width,this.height)
    this.init()
  }
  async init(){
    this.loadTHREE()
    await this.loadZipFile()
    await this.fileToBlob()
    this.findFile()
    this.runLoader()
  }
  loadTHREE(){
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000);
    this.camera.position.set(0, 20, 20);
    this.camera.lookAt(0, 0, 0);

    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setSize(this.width, this.height);
    this.container.appendChild(this.renderer.domElement);

    const pmremGenerator = new THREE.PMREMGenerator( this.renderer );
    this.scene.background = new THREE.Color( 0x8a8c8e );
    this.scene.environment = pmremGenerator.fromScene( new RoomEnvironment(), 0.04 ).texture;
    const light = new THREE.AmbientLight( 0xffffff );
    this.scene.add(light)

    this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    this.controls.update();
  }
  loadZipFile(){
    return new Promise(resolve => {
      const fileLoader = new THREE.FileLoader();
      fileLoader
        .setResponseType("arraybuffer")
        .load(
          this.url,
          data => {
            // console.log(data,'file')
            this.arrayBuffers=data
            resolve()
          },
        )
    })
  }
  async fileToBlob(){
    //zip.js加载文件流生成对应文件:
    const zip = new JSZip();
    const promise = JSZip.external.Promise;
    const baseUrl = 'blob:' + THREE.LoaderUtils.extractUrlBase(this.url);
    const pendings = [];
    await zip.loadAsync(this.arrayBuffers);
    //转成blob文件,用URL.createObjectURL创建文件的url
    for (let file in zip.files) {
      const entry = zip.file(file);
      if (entry === null) continue;
      pendings.push(entry.async('blob').then(((file, blob) => {
        this.fileMap[baseUrl + file] = URL.createObjectURL(blob);
      }).bind(this, file)))
    }
    //监听所有请求结束
    await promise.all(pendings);
  }
  findFile(){
    //模型文件url
    this.modelUrl = Object.keys(this.fileMap).find(item => /\.(gltf)$/.test(item));
  }
  runLoader(){
    const manager = new THREE.LoadingManager();
    //转换处理,传入的是后台返回的路径,需找到对应blob
    manager.setURLModifier(url => {
      return this.fileMap[url] ? this.fileMap[url] : url;
    });

    const loader = new GLTFLoader(manager)
    loader.load(this.modelUrl, gltf=> {
      // console.log(gltf)
      gltf.scene.traverse(function (child) {
        if (child.isMesh) {
          //模型自发光
          child.material.emissive = child.material.color;
          child.material.emissiveMap = child.material.map;
        }
      });
      this.setScaleToFitSize(gltf.scene)
      this.scene.add(gltf.scene);
      animate()
    })
    const that=this
    function animate() {
      requestAnimationFrame(animate);
      that.controls.update();
      that.renderer.render(that.scene, that.camera);
    }
  }
  //适合模型观察的缩放比例
  setScaleToFitSize(obj) {
    const boxHelper = new THREE.BoxHelper(obj);
    boxHelper.geometry.computeBoundingBox();
    const box = boxHelper.geometry.boundingBox;
    const maxDiameter = Math.max((box.max.x - box.min.x), (box.max.y - box.min.y), (box.max.z - box.min.z));
    const scaleValue = this.camera.position.z / maxDiameter;
    obj.scale.set(scaleValue, scaleValue, scaleValue);
  }
}

export default LoadModel

 

当前只加载了GLTFLoader,其他类似。