cesium模型的本地加载模型

需求

目前有一个需求就是需要从本地拖拽glb文件模型到cesium地球中显示模型

由于相关js库较多 本文章就不涉及拖拽功能了

思路

第一种方案

cesium通过Model.fromGltf函数来读取gltf的url
阅读此函数的源码可知 该函数本身也是从网页下载文件为 arraybuffeer流 后赋值model的gltf属性进行加载模型,但由于gltf只是一个只读属性,所以尝试重写该函数,让本地模型转化为arraybuffer后赋值加载模型

import defined from './Core/defined'
import clone from "./Core/clone";
import parseGlb from "./Scene/GltfPipeline/parseGlb";
import getMagic from "./Core/getMagic.js";
import DeveloperError from "./Core/DeveloperError";
import getJsonFromTypedArray from "./Core/getJsonFromTypedArray.js";
function setCachedGltf(model, cachedGltf) {
  model._cachedGltf = cachedGltf;
}
CachedGltf.prototype.makeReady = function (gltfJson) {
  this.gltf = gltfJson;

  const models = this.modelsToLoad;
  const length = models.length;
  for (let i = 0; i < length; ++i) {
    const m = models[i];
    if (!m.isDestroyed()) {
      setCachedGltf(m, this);
    }
  }
  this.modelsToLoad = undefined;
  this.ready = true;
};
// const gltfCache = {};
// const uriToGuid = {};
Object.defineProperties(CachedGltf.prototype, {
  gltf: {
    set: function (value) {
      this._gltf = value;
    },

    get: function () {
      return this._gltf;
    },
  },
});

function CachedGltf(options) {
  this._gltf = options.gltf;
  this.ready = options.ready;
  this.modelsToLoad = [];
  this.count = 0;
}

function CesiumOverWriteFromGltfFun(options, bimccArrayBuffer) {

  if (!defined(options) || !defined(options.url)) {
    throw new DeveloperError("options.url is required");
  }
  options = clone(options);
  options.cacheKey = 'cacheKey';
  options.basePath = 'resource';
  const model = new Cesium.Model(options);

  let cachedGltf = 'gltfCache[cacheKey]';
    cachedGltf = new CachedGltf({
      ready: false,
    });
    cachedGltf.count = 1;
    cachedGltf.modelsToLoad.push(model);
    setCachedGltf(model, cachedGltf);

    let arrayBuffer = bimccArrayBuffer
    const array = new Uint8Array(arrayBuffer);
    if (containsGltfMagic(array)) {
      // Load binary glTF
      console.log("Load binary glTF")
      const parsedGltf = parseGlb(array);
      cachedGltf.makeReady(parsedGltf);
    } else {
      // Load text (JSON) glTF
      console.log("Load text (JSON) glTF")
      const json = getJsonFromTypedArray(array);
      cachedGltf.makeReady(json);
    }
  return model;
}
function containsGltfMagic(uint8Array) {
  const magic = getMagic(uint8Array);
  return magic === "glTF";
}
export default CesiumOverWriteFromGltfFun;

这样就需要导入很多的工具类,虽然完成了需求,但是除了加大了打包的js的体积外,
还增加了和cesium 源码版本的耦合性,而且在应对没有压缩格式的模型文件(gltf)时需要进行额外的处理方式,代码复用性较差。(不过可以考虑将gltf的json bin等文件压缩为glb文件,这样仍然需要额外的性能开销)
额外的工具类

第二种方案

将模型导入后通过 createObjectURL 函数制造一个内存的url来规避掉安全策略,也能使用model.fromgltf函数。
此时 glb 文件是可以直接createObjectURL后使用model.fromgltf函数
但是gltf仍然需要对gltf文件进行操作 需要将文件中的buffers属性和images属性的uri更换为createObjectURL生成的uri
特别重要的是

URL.createObjectURL(new Blob([JSON.stringify(changedGltf)]))

PS: 必须需要将json格式的gltf文件(changedGltf)进行JSON.stringify字符串化,否则导入后依然不显示。

结果

项目重构,采用第二种方案

参考

posted @ 2022-08-18 14:47  DAmarkday  阅读(1595)  评论(0编辑  收藏  举报