itowns
Version:
A JS/WebGL framework for 3D geospatial data visualization
299 lines (241 loc) • 11.4 kB
JavaScript
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.enableDracoLoader = enableDracoLoader;
exports["default"] = exports.legacyGLTFLoader = exports.glTFLoader = void 0;
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var THREE = _interopRequireWildcard(require("three"));
var _Capabilities = _interopRequireDefault(require("../Core/System/Capabilities"));
var _GLTFLoader = _interopRequireDefault(require("../ThreeExtended/loaders/GLTFLoader"));
var _DRACOLoader = _interopRequireDefault(require("../ThreeExtended/loaders/DRACOLoader"));
var _LegacyGLTFLoader = _interopRequireDefault(require("../ThreeExtended/loaders/deprecated/LegacyGLTFLoader"));
var _ShaderUtils = _interopRequireDefault(require("../Renderer/Shader/ShaderUtils"));
var _Utf8Decoder = _interopRequireDefault(require("../Utils/Utf8Decoder"));
var _BatchTableParser = _interopRequireDefault(require("./BatchTableParser"));
var matrixChangeUpVectorZtoY = new THREE.Matrix4().makeRotationX(Math.PI / 2); // For gltf rotation
var matrixChangeUpVectorZtoX = new THREE.Matrix4().makeRotationZ(-Math.PI / 2);
var glTFLoader = new _GLTFLoader["default"]();
exports.glTFLoader = glTFLoader;
var legacyGLTFLoader = new _LegacyGLTFLoader["default"]();
exports.legacyGLTFLoader = legacyGLTFLoader;
function filterUnsupportedSemantics(obj) {
// see GLTFLoader GLTFShader.prototype.update function
var supported = ['MODELVIEW', 'MODELVIEWINVERSETRANSPOSE', 'PROJECTION', 'JOINTMATRIX'];
if (obj.gltfShader) {
var names = []; // eslint-disable-next-line guard-for-in
for (var name in obj.gltfShader.boundUniforms) {
names.push(name);
}
for (var _i = 0, _names = names; _i < _names.length; _i++) {
var _name = _names[_i];
var semantic = obj.gltfShader.boundUniforms[_name].semantic;
if (!supported.includes(semantic)) {
delete obj.gltfShader.boundUniforms[_name];
}
}
}
}
/**
* @module B3dmParser
*/
/**
* Enable Draco decoding for gltf.
* @param {string} path to draco library folder.
* This library is mandatory to load b3dm with Draco compression.
* @param {object} config optional configuration for Draco compression.
*
* The Draco library files are in folder itowns/examples/libs/draco/.
* You are obliged to indicate this path when you want enable the Draco Decoding.
*
* For more information on Draco, read file in /itowns/examples/libs/draco/README.md.
*
* @example <caption>Enable draco decoder</caption>
* // if you copied the folder from /itowns/examples/libs/draco/ to your root project,
* // You could set path with './'.
* itowns.enableDracoLoader('./');
*/
function enableDracoLoader(path, config) {
if (!path) {
throw new Error('Path to draco folder is mandatory');
}
_DRACOLoader["default"].setDecoderPath(path);
if (config) {
_DRACOLoader["default"].setDecoderConfig(config);
}
var dracoLoader = new _DRACOLoader["default"]();
glTFLoader.setDRACOLoader(dracoLoader);
_DRACOLoader["default"].getDecoderModule();
}
var _default = {
/** Parse b3dm buffer and extract THREE.Scene and batch table
* @param {ArrayBuffer} buffer - the b3dm buffer.
* @param {Object} options - additional properties.
* @param {string=} [options.gltfUpAxis='Y'] - embedded glTF model up axis.
* @param {string} options.urlBase - the base url of the b3dm file (used to fetch textures for the embedded glTF model).
* @param {boolean=} [options.doNotPatchMaterial='false'] - disable patching material with logarithmic depth buffer support.
* @param {float} [options.opacity=1.0] - the b3dm opacity.
* @param {boolean|Material=} [options.overrideMaterials='false'] - override b3dm's embedded glTF materials. If overrideMaterials is a three.js material, it will be the material used to override.
* @return {Promise} - a promise that resolves with an object containig a THREE.Scene (gltf) and a batch table (batchTable).
*
*/
parse: function parse(buffer, options) {
var gltfUpAxis = options.gltfUpAxis;
var urlBase = options.urlBase;
if (!buffer) {
throw new Error('No array buffer provided.');
}
var view = new DataView(buffer, 4); // starts after magic
var byteOffset = 0;
var b3dmHeader = {}; // Magic type is unsigned char [4]
var magicNumberByteLength = 4;
b3dmHeader.magic = _Utf8Decoder["default"].decode(new Uint8Array(buffer, 0, magicNumberByteLength));
if (b3dmHeader.magic) {
// Version, byteLength, batchTableJSONByteLength, batchTableBinaryByteLength and batchTable types are uint32
b3dmHeader.version = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;
b3dmHeader.byteLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;
b3dmHeader.FTJSONLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;
b3dmHeader.FTBinaryLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;
b3dmHeader.BTJSONLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;
b3dmHeader.BTBinaryLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;
var headerByteLength = byteOffset + magicNumberByteLength;
var promises = [];
var FTJSON = {};
var FT_RTC = new THREE.Vector3();
if (b3dmHeader.FTJSONLength > 0) {
var sizeBegin = headerByteLength;
var jsonBuffer = buffer.slice(sizeBegin, b3dmHeader.FTJSONLength + sizeBegin);
var content = _Utf8Decoder["default"].decode(new Uint8Array(jsonBuffer));
FTJSON = JSON.parse(content);
if (FTJSON.RTC_CENTER) {
FT_RTC.fromArray(FTJSON.RTC_CENTER);
} else {
FT_RTC.set(0, 0, 0);
}
}
if (b3dmHeader.FTBinaryLength > 0) {
console.warn('3D Tiles feature table binary not supported yet.');
} // Parse batch table
if (b3dmHeader.BTJSONLength > 0) {
// sizeBegin is an index to the beginning of the batch table
var _sizeBegin = headerByteLength + b3dmHeader.FTJSONLength + b3dmHeader.FTBinaryLength;
promises.push(_BatchTableParser["default"].parse(buffer.slice(_sizeBegin, b3dmHeader.BTJSONLength + _sizeBegin), b3dmHeader.BTBinaryLength, FTJSON.BATCH_LENGTH));
} else {
promises.push(Promise.resolve({}));
}
var posGltf = headerByteLength + b3dmHeader.FTJSONLength + b3dmHeader.FTBinaryLength + b3dmHeader.BTJSONLength + b3dmHeader.BTBinaryLength;
var gltfBuffer = buffer.slice(posGltf);
var headerView = new DataView(gltfBuffer, 0, 20);
promises.push(new Promise(function (resolve
/* , reject */
) {
var onload = function (gltf) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = gltf.scenes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var scene = _step.value;
scene.traverse(filterUnsupportedSemantics);
} // Rotation managed
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator["return"] != null) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (gltfUpAxis === undefined || gltfUpAxis === 'Y') {
gltf.scene.applyMatrix(matrixChangeUpVectorZtoY);
} else if (gltfUpAxis === 'X') {
gltf.scene.applyMatrix(matrixChangeUpVectorZtoX);
} // Apply relative center from Feature table.
gltf.scene.position.copy(FT_RTC); // Apply relative center from gltf json.
var contentArray = new Uint8Array(gltfBuffer, 20, headerView.getUint32(12, true));
var content = _Utf8Decoder["default"].decode(new Uint8Array(contentArray));
var json = JSON.parse(content);
if (json.extensions && json.extensions.CESIUM_RTC) {
gltf.scene.position.fromArray(json.extensions.CESIUM_RTC.center);
gltf.scene.updateMatrixWorld(true);
}
gltf.scene.traverse(function (mesh) {
mesh.frustumCulled = false;
if (mesh.material) {
if (options.overrideMaterials) {
if (Array.isArray(mesh.material)) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = mesh.material[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var material = _step2.value;
material.dispose();
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
_iterator2["return"]();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
} else {
mesh.material.dispose();
}
if ((0, _typeof2["default"])(options.overrideMaterials) === 'object' && options.overrideMaterials.isMaterial) {
mesh.material = options.overrideMaterials;
} else {
mesh.material = new THREE.MeshLambertMaterial({
color: 0xffffff
});
}
} else if (_Capabilities["default"].isLogDepthBufferSupported() && mesh.material.isRawShaderMaterial && !options.doNotPatchMaterial) {
_ShaderUtils["default"].patchMaterialForLogDepthSupport(mesh.material);
console.warn('b3dm shader has been patched to add log depth buffer support');
}
mesh.material.transparent = options.opacity < 1.0;
mesh.material.opacity = options.opacity;
}
});
resolve(gltf);
};
var version = headerView.getUint32(4, true);
if (version === 1) {
legacyGLTFLoader.parse(gltfBuffer, urlBase, onload);
} else {
glTFLoader.parse(gltfBuffer, urlBase, onload);
}
}));
return Promise.all(promises).then(function (values) {
return {
gltf: values[1],
batchTable: values[0]
};
});
} else {
throw new Error('Invalid b3dm file.');
}
}
};
exports["default"] = _default;
;