需求
目前有一个需求就是需要从本地拖拽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字符串化,否则导入后依然不显示。
结果
项目重构,采用第二种方案