diff --git a/docs/config.json b/docs/config.json index 3ea235c738..b5029ae5f3 100644 --- a/docs/config.json +++ b/docs/config.json @@ -82,6 +82,7 @@ "Parser": [ "GeoJsonParser", + "GLTFParser", "GpxParser", "VectorTileParser", "CameraCalibrationParser", diff --git a/docs/tutorials/Fundamentals.md b/docs/tutorials/Fundamentals.md index e9f91847e4..71cd75b5d1 100644 --- a/docs/tutorials/Fundamentals.md +++ b/docs/tutorials/Fundamentals.md @@ -47,7 +47,7 @@ with `{@link WFSSource}` and [Tile Map Service](https://wiki.osgeo.org/wiki/Tile iTowns also has sources for many data formats: [vector tile](https://docs.mapbox.com/help/glossary/vector-tiles/) resources from [MapBox](https://www.mapbox.com/) with `{@link VectorTilesSource}`, [Potree](https://github.com/potree/potree) (`{@link PotreeSource}`) and [Entwine](https://entwine.io/) (`{@link EntwinePointTileSource}`) 3D point clouds, [3DTiles](https://www.ogc.org/standards/3DTiles) -mesh (b3dm) and point clouds (pnts) from web servers (`{@link C3DTilesSource}`) and from Cesium ion `{@link C3DTilesIonSource}`, +mesh (b3dm) and point clouds (pnts) from web servers (`{@link C3DTilesSource}`), Cesium ion `{@link C3DTilesIonSource}` and from Google api `{@link C3DTilesGoogleSource}`, [GeoJSON](https://geojson.org/) with `{@link FileSource}` and `{@link GeoJsonParser}`, [KML](https://www.ogc.org/standards/kml) with `{@link FileSource}` and `{@link KMLParser}`, [GPX](https://www.topografix.com/gpx.asp) with `{@link FileSource}` and `{@link GpxParser}` and oriented images with `{@link OrientedImageSource}`. @@ -68,7 +68,7 @@ Several specific types of `Layers` exist, the use of which depends on the data t - `{@link PointCloudLayer}` can be used to display 3D point clouds. Any point cloud formats are supported as long as the corresponding `Source` is provided. Some point clouds formats such as Potree, Las and Entwine already have parsers defined in itowns that you can use. For 3D Tiles point clouds (pnts), use `C3DTilesLayer`. -- `{@link C3DTilesLayer}` can be used to display 3D Tiles layer (only b3dm and pnts). +- `{@link C3DTilesLayer}` can be used to display 3D Tiles datasets in version 1.0 (b3dm, pnts and gltf tiles are supported). - `{@link OrientedImageLayer}` can be used to display oriented images. diff --git a/src/Main.js b/src/Main.js index ac7d40a6e4..7e063f1df3 100644 --- a/src/Main.js +++ b/src/Main.js @@ -77,6 +77,7 @@ export { default as OrientedImageSource } from 'Source/OrientedImageSource'; export { default as PotreeSource } from 'Source/PotreeSource'; export { default as C3DTilesSource } from 'Source/C3DTilesSource'; export { default as C3DTilesIonSource } from 'Source/C3DTilesIonSource'; +export { default as C3DTilesGoogleSource } from 'Source/C3DTilesGoogleSource'; export { default as EntwinePointTileSource } from 'Source/EntwinePointTileSource'; // Parsers provided by default in iTowns @@ -91,7 +92,7 @@ export { default as LASParser } from 'Parser/LASParser'; export { default as ISGParser } from 'Parser/ISGParser'; export { default as GDFParser } from 'Parser/GDFParser'; export { default as GTXParser } from 'Parser/GTXParser'; -export { enableDracoLoader, enableKtx2Loader, glTFLoader, legacyGLTFLoader } from 'Parser/B3dmParser'; +export { default as GLTFParser, enableDracoLoader, enableKtx2Loader } from 'Parser/GLTFParser'; // 3D Tiles classes and extensions // Exported to allow one to implement its own 3D Tiles extension which needs to diff --git a/src/Parser/B3dmParser.js b/src/Parser/B3dmParser.js index d5e45d4b4b..00fc173f0f 100644 --- a/src/Parser/B3dmParser.js +++ b/src/Parser/B3dmParser.js @@ -1,24 +1,21 @@ import * as THREE from 'three'; -import Capabilities from 'Core/System/Capabilities'; -import { GLTFLoader } from 'ThreeExtended/loaders/GLTFLoader'; -import { DRACOLoader } from 'ThreeExtended/loaders/DRACOLoader'; -import { KTX2Loader } from 'ThreeExtended/loaders/KTX2Loader'; -import LegacyGLTFLoader from 'Parser/deprecated/LegacyGLTFLoader'; -import shaderUtils from 'Renderer/Shader/ShaderUtils'; import utf8Decoder from 'Utils/Utf8Decoder'; import C3DTBatchTable from 'Core/3DTiles/C3DTBatchTable'; -import ReferLayerProperties from 'Layer/ReferencingLayerProperties'; +import Capabilities from 'Core/System/Capabilities'; import { MeshBasicMaterial } from 'three'; import disposeThreeMaterial from 'Utils/ThreeUtils'; +import shaderUtils from 'Renderer/Shader/ShaderUtils'; +import ReferLayerProperties from 'Layer/ReferencingLayerProperties'; +import GLTFParser from './GLTFParser'; -const matrixChangeUpVectorZtoY = (new THREE.Matrix4()).makeRotationX(Math.PI / 2); -// For gltf rotation -const matrixChangeUpVectorZtoX = (new THREE.Matrix4()).makeRotationZ(-Math.PI / 2); - -export const glTFLoader = new GLTFLoader(); - -export const legacyGLTFLoader = new LegacyGLTFLoader(); +const matrixChangeUpVectorYtoZInv = (new THREE.Matrix4()).makeRotationX(-Math.PI / 2); +const matrixChangeUpVectorXtoZ = (new THREE.Matrix4()).makeRotationZ(-Math.PI / 2); +/** + * 3D Tiles pre-1.0 contain not standardized and specific uniforms that we filter out to avoid shader compilation errors + * This method is passed to scene.traverse and applied to all 3D objects of the loaded gltf. + * @param {THREE.Object3D} obj - 3D object of the gltf hierarchy + */ function filterUnsupportedSemantics(obj) { // see GLTFLoader GLTFShader.prototype.update function const supported = [ @@ -43,58 +40,25 @@ function filterUnsupportedSemantics(obj) { } /** - * @module B3dmParser + * 3D Tiles pre-1.0 had a gltfUpAxis parameter that defined the up vector of the gltf file that might be different from + * the standard y-up for gltf. Manage the case when this gltfUpAxis is defined (i.e. apply the correct rotation to the + * gltf file to have it z-up in the end). + * @param {THREE.Object3D} gltfScene - the parsed glTF scene + * @param {String} gltfUpAxis - the gltfUpAxis parameter */ -/** - * Enable Draco decoding for gltf. - * - * The Draco library files are in folder itowns/examples/libs/draco/. - * You must indicate this path when you want to enable Draco Decoding. - * For more information on Draco, read /itowns/examples/libs/draco/README.md. - * - * @example Enable draco decoder - * // if you copied /itowns/examples/libs/draco/ to the root folder of your project,you can set the path to './'. - * itowns.enableDracoLoader('./'); - * - * @param {string} path path to draco library folder. - * This library is mandatory to load b3dm and gltf with Draco compression. - * @param {object} config optional configuration for Draco compression. - */ -export function enableDracoLoader(path, config) { - if (!path) { - throw new Error('Path to draco folder is mandatory'); - } - const dracoLoader = new DRACOLoader(); - dracoLoader.setDecoderPath(path); - if (config) { - dracoLoader.setDecoderConfig(config); +function applyDeprecatedGltfUpAxis(gltfScene, gltfUpAxis) { + if (gltfUpAxis === 'Z') { + // If gltf up was already z-up, apply the inverse transform matrix that was applied in the glTFParser + gltfScene.applyMatrix4(matrixChangeUpVectorYtoZInv); + } else if (gltfUpAxis === 'X') { + gltfScene.applyMatrix4(matrixChangeUpVectorYtoZInv); + gltfScene.applyMatrix4(matrixChangeUpVectorXtoZ); } - glTFLoader.setDRACOLoader(dracoLoader); } /** - * Enable KTX2 decoding for gltf. This library is mandatory to load b3dm and gltf with KTX2 compression. - * - * The KTX2 library files are in folder itowns/examples/libs/basis/. - * You must indicate this path when you want to enable KTX2 decoding. - * For more information about KTX2, read /itowns/examples/libs/basis/README.md. - * - * @example Enable ktx2 decoder - * // if you copied /itowns/examples/libs/draco/ to the root folder of your project,you can set the path to './'. - * itowns.enableKtx2Loader('./', view.mainLoop.gfxEngine.renderer); - * - * @param {string} path path to KTX2 library folder. - * @param {THREE.WebGLRenderer} renderer the threejs renderer + * @module B3dmParser */ -export function enableKtx2Loader(path, renderer) { - if (!path || !renderer) { - throw new Error('Path to ktx2 folder and renderer are mandatory'); - } - const ktx2Loader = new KTX2Loader(); - ktx2Loader.setTranscoderPath(path); - ktx2Loader.detectSupport(renderer); - glTFLoader.setKTX2Loader(ktx2Loader); -} export default { /** Parse b3dm buffer and extract THREE.Scene and batch table @@ -102,9 +66,10 @@ export default { * @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 {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 + * @param {boolean=} [options.frustumCulled=false] - enable frustum culling. + * @param {boolean|Material=} [options.overrideMaterials=false] - override b3dm's embedded glTF materials. If * true, a threejs [MeshBasicMaterial](https://threejs.org/docs/index.html?q=meshbasic#api/en/materials/MeshBasicMaterial) * is set up. config.overrideMaterials can also be a threejs [Material](https://threejs.org/docs/index.html?q=material#api/en/materials/Material) * in which case it will be the material used to override. @@ -112,8 +77,8 @@ export default { * */ parse(buffer, options) { - const gltfUpAxis = options.gltfUpAxis; - const urlBase = options.urlBase; + const frustumCulled = options.frustumCulled === undefined || options.frustumCulled === null ? true : !!(options.frustumCulled); + if (!buffer) { throw new Error('No array buffer provided.'); } @@ -185,66 +150,56 @@ export default { const gltfBuffer = buffer.slice(posGltf); const headerView = new DataView(gltfBuffer, 0, 20); - promises.push(new Promise((resolve/* , reject */) => { - const onload = (gltf) => { - for (const scene of gltf.scenes) { - scene.traverse(filterUnsupportedSemantics); - } - // Rotation managed - if (gltfUpAxis === undefined || gltfUpAxis === 'Y') { - gltf.scene.applyMatrix4(matrixChangeUpVectorZtoY); - } else if (gltfUpAxis === 'X') { - gltf.scene.applyMatrix4(matrixChangeUpVectorZtoX); + const init_mesh = function f_init(mesh) { + mesh.frustumCulled = frustumCulled; + if (mesh.material) { + if (options.overrideMaterials) { + const oldMat = mesh.material; + // Set up new material + if (typeof (options.overrideMaterials) === 'object' && + options.overrideMaterials.isMaterial) { + mesh.material = options.overrideMaterials; + } else { + mesh.material = new MeshBasicMaterial(); + } + disposeThreeMaterial(oldMat); + } else if (Capabilities.isLogDepthBufferSupported() + && mesh.material.isRawShaderMaterial + && !options.doNotPatchMaterial) { + shaderUtils.patchMaterialForLogDepthSupport(mesh.material); + console.warn('glTF shader has been patched to add log depth buffer support'); } + ReferLayerProperties(mesh.material, options.layer); + } + }; - // Apply relative center from Feature table. - gltf.scene.position.copy(FT_RTC); + promises.push(GLTFParser.parse(gltfBuffer, options).then((gltf) => { + for (const scene of gltf.scenes) { + scene.traverse(filterUnsupportedSemantics); + } - // Apply relative center from gltf json. - const contentArray = new Uint8Array(gltfBuffer, 20, headerView.getUint32(12, true)); - const content = utf8Decoder.decode(new Uint8Array(contentArray)); - const json = JSON.parse(content); - if (json.extensions && json.extensions.CESIUM_RTC) { - gltf.scene.position.fromArray(json.extensions.CESIUM_RTC.center); - gltf.scene.updateMatrixWorld(true); - } + applyDeprecatedGltfUpAxis(gltf.scene, options.gltfUpAxis); - const init_mesh = function f_init(mesh) { - mesh.frustumCulled = false; - if (mesh.material) { - if (options.overrideMaterials) { - const oldMat = mesh.material; - // Set up new material - if (typeof (options.overrideMaterials) === 'object' && - options.overrideMaterials.isMaterial) { - mesh.material = options.overrideMaterials; - } else { - mesh.material = new MeshBasicMaterial(); - } - disposeThreeMaterial(oldMat); - } else if (Capabilities.isLogDepthBufferSupported() - && mesh.material.isRawShaderMaterial - && !options.doNotPatchMaterial) { - shaderUtils.patchMaterialForLogDepthSupport(mesh.material); - console.warn('b3dm shader has been patched to add log depth buffer support'); - } - ReferLayerProperties(mesh.material, options.layer); - } - }; + const shouldBePatchedForLogDepthSupport = Capabilities.isLogDepthBufferSupported() && !options.doNotPatchMaterial; + if (options.frustumCulling === false || options.overrideMaterials || shouldBePatchedForLogDepthSupport || options.layer) { gltf.scene.traverse(init_mesh); + } - resolve(gltf); - }; - - const version = headerView.getUint32(4, true); + // Apply relative center from Feature table. + gltf.scene.position.copy(FT_RTC); - if (version === 1) { - legacyGLTFLoader.parse(gltfBuffer, urlBase, onload); - } else { - glTFLoader.parse(gltfBuffer, urlBase, onload); + // Apply relative center from gltf json. + const contentArray = new Uint8Array(gltfBuffer, 20, headerView.getUint32(12, true)); + const content = utf8Decoder.decode(new Uint8Array(contentArray)); + const json = JSON.parse(content); + if (json.extensions && json.extensions.CESIUM_RTC) { + gltf.scene.position.fromArray(json.extensions.CESIUM_RTC.center); + gltf.scene.updateMatrixWorld(true); } - })); - return Promise.all(promises).then(values => ({ gltf: values[1], batchTable: values[0] })); + + return gltf; + }).catch((e) => { throw new Error(e); })); + return Promise.all(promises).then(values => ({ gltf: values[1], batchTable: values[0] })).catch((e) => { throw new Error(e); }); } else { throw new Error('Invalid b3dm file.'); } diff --git a/src/Parser/GLTFParser.js b/src/Parser/GLTFParser.js new file mode 100644 index 0000000000..4de807cb01 --- /dev/null +++ b/src/Parser/GLTFParser.js @@ -0,0 +1,91 @@ +import * as THREE from 'three'; +import { GLTFLoader } from 'ThreeExtended/loaders/GLTFLoader'; +import { DRACOLoader } from 'ThreeExtended/loaders/DRACOLoader'; +import { KTX2Loader } from 'ThreeExtended/loaders/KTX2Loader'; +import LegacyGLTFLoader from 'Parser/deprecated/LegacyGLTFLoader'; + +const matrixChangeUpVectorYtoZ = (new THREE.Matrix4()).makeRotationX(Math.PI / 2); + +export const glTFLoader = new GLTFLoader(); +export const legacyGLTFLoader = new LegacyGLTFLoader(); + +/** + * @module GLTFParser + * @description Parses [glTF](https://www.khronos.org/gltf/) 1.0 and 2.0 files. + * + * Under the hood, glTF 2.0 files are parsed with THREE.GltfLoader() and GLTF 1.0 are parsed with the previous THREE + * GltfLoader (for 1.0 glTF) that has been kept and maintained in iTowns. + */ + +/** + * Enable loading gltf files with [Draco](https://google.github.io/draco/) geometry extension. + * + * @param {String} path path to draco library folder containing the JS and WASM decoder libraries. They can be found in + * [itowns examples](https://github.com/iTowns/itowns/tree/master/examples/libs/draco). + * @param {Object} [config] optional configuration for Draco decoder (see threejs' + * [setDecoderConfig](https://threejs.org/docs/index.html?q=draco#examples/en/loaders/DRACOLoader.setDecoderConfig) that + * is called under the hood with this configuration for details. + */ +export function enableDracoLoader(path, config) { + if (!path) { + throw new Error('Path to draco folder is mandatory'); + } + const dracoLoader = new DRACOLoader(); + dracoLoader.setDecoderPath(path); + if (config) { + dracoLoader.setDecoderConfig(config); + } + glTFLoader.setDRACOLoader(dracoLoader); +} + +/** + * Enable loading gltf files with [KTX2](https://www.khronos.org/ktx/) texture extension. + * + * @param {String} path path to ktx2 library folder containing the JS and WASM decoder libraries. They can be found in + * [itowns examples](https://github.com/iTowns/itowns/tree/master/examples/libs/basis). + * @param {THREE.WebGLRenderer} renderer the threejs renderer + */ +export function enableKtx2Loader(path, renderer) { + if (!path || !renderer) { + throw new Error('Path to ktx2 folder and renderer are mandatory'); + } + const ktx2Loader = new KTX2Loader(); + ktx2Loader.setTranscoderPath(path); + ktx2Loader.detectSupport(renderer); + glTFLoader.setKTX2Loader(ktx2Loader); +} + +export default { + /** Parses a gltf buffer to an object with threejs structures and applies a y-up to z-up conversion to align with + * itowns convention. Essentially calls THREE.GltfLoader.parse() for glTF 2.0 files and the legacy threejs parser + * for gtTF 1.0 files. + * @param {ArrayBuffer} buffer - the glTF asset to parse, as an ArrayBuffer, JSON string or object. + * @param {String} path - the base path from which to find subsequent glTF resources such as textures and .bin data files. + * @return {Promise} - a promise that resolves with an object containing an Object that contains loaded parts: + * .scene, .scenes, .cameras, .animations, and .asset. + */ + parse(buffer, path) { + return new Promise((resolve, reject) => { + if (!buffer || !path) { + reject(new Error('[GLTFParser]: Buffer and path are mandatory to parse a glTF.')); + } + + // Apply y-up (gltf convention) to z-up (itowns convention) conversion + const onload = (gltf) => { + gltf.scene.applyMatrix4(matrixChangeUpVectorYtoZ); + resolve(gltf); + }; + const onError = (e) => { + reject(new Error(`[GLTFParser]: Failed to parse gltf with error: ${e}`)); + }; + const headerView = new DataView(buffer, 0, 20); + const version = headerView.getUint32(4, true); + + if (version === 1) { + legacyGLTFLoader.parse(buffer, path, onload, onError); + } else { + glTFLoader.parse(buffer, path, onload, onError); + } + }); + }, +}; diff --git a/src/Provider/3dTilesProvider.js b/src/Provider/3dTilesProvider.js index a44b87360d..adf011a66b 100644 --- a/src/Provider/3dTilesProvider.js +++ b/src/Provider/3dTilesProvider.js @@ -1,6 +1,7 @@ import * as THREE from 'three'; import B3dmParser from 'Parser/B3dmParser'; import PntsParser from 'Parser/PntsParser'; +import GLTFParser from 'Parser/GLTFParser'; import Fetcher from 'Provider/Fetcher'; import ReferLayerProperties from 'Layer/ReferencingLayerProperties'; import utf8Decoder from 'Utils/Utf8Decoder'; @@ -13,7 +14,6 @@ function b3dmToMesh(data, layer, url) { urlBase, overrideMaterials: layer.overrideMaterials, doNotPatchMaterial: layer.doNotPatchMaterial, - opacity: layer.opacity, registeredExtensions: layer.registeredExtensions, layer, }; @@ -25,6 +25,11 @@ function b3dmToMesh(data, layer, url) { }); } +function gltfToMesh(data, layer, url) { + const urlBase = THREE.LoaderUtils.extractUrlBase(url); + return GLTFParser.parse(data, urlBase).then(result => ({ object3d: result.scene })); +} + function pntsParse(data, layer) { return PntsParser.parse(data, layer.registeredExtensions).then((result) => { const material = layer.material ? @@ -91,10 +96,14 @@ function executeCommand(command) { }; if (path) { // Check if we have relative or absolute url (with tileset's lopocs for example) - const url = path.startsWith('http') ? path : metadata.baseURL + path; + let url = path.startsWith('http') ? path : metadata.baseURL + path; + if (layer.source.isC3DTilesGoogleSource) { + url = layer.source.getTileUrl(url); + } const supportedFormats = { b3dm: b3dmToMesh, pnts: pntsParse, + gltf: gltfToMesh, }; return Fetcher.arrayBuffer(url, layer.source.networkOptions).then((result) => { if (result !== undefined) { @@ -102,12 +111,21 @@ function executeCommand(command) { const magic = utf8Decoder.decode(new Uint8Array(result, 0, 4)); if (magic[0] === '{') { result = JSON.parse(utf8Decoder.decode(new Uint8Array(result))); - const newPrefix = url.slice(0, url.lastIndexOf('/') + 1); + let newPrefix = ''; + // Another specifics of 3D tiles from Google: tilesets in tilesets are required from the root base + // url and not from their parent base url + if (layer.source.isC3DTilesGoogleSource) { + newPrefix = layer.source.baseUrl; + } else { + newPrefix = url.slice(0, url.lastIndexOf('/') + 1); + } layer.tileset.extendTileset(result, metadata.tileId, newPrefix, layer.registeredExtensions); } else if (magic == 'b3dm') { func = supportedFormats.b3dm; } else if (magic == 'pnts') { func = supportedFormats.pnts; + } else if (magic == 'glTF') { + func = supportedFormats.gltf; } else { return Promise.reject(`Unsupported magic code ${magic}`); } diff --git a/src/Source/C3DTilesGoogleSource.js b/src/Source/C3DTilesGoogleSource.js new file mode 100644 index 0000000000..8e37a068b1 --- /dev/null +++ b/src/Source/C3DTilesGoogleSource.js @@ -0,0 +1,79 @@ +import Fetcher from 'Provider/Fetcher'; +import C3DTilesSource from './C3DTilesSource'; + +function findSessionId(tile) { + if (!tile) { + return null; + } + if (tile.content && tile.content.uri) { + const uri = tile.content.uri.substr(tile.content.uri.indexOf('?') + 1); + const sessionIds = uri.split('='); + return sessionIds[1]; + } else if (tile.children && tile.children.length > 0) { + for (const c of tile.children) { + const sessionId = findSessionId(c); + if (sessionId) { + return sessionId; + } + } + } + return null; +} + +/** + * @classdesc + * An object defining the source connection to a 3DTiles asset from a [Google api](https://tile.googleapis.com). + * + * @extends C3DTilesSource + * + * @property {boolean} isC3DTilesGoogleSource - Used to checkout whether this source is a C3DTilesGoogleSource. Default is + * true. You should not change this, as it is used internally for optimisation. + * @property {string} url - The URL to the tileset json. + * @property {string} baseUrl - The base URL to access tiles. + */ +class C3DTilesGoogleSource extends C3DTilesSource { + /** + * Create a new Source for 3D Tiles data from Google api (experimental). + * + * @constructor + * @extends C3DTilesSource + * + * @property {boolean} isC3DTilesGoogleSource - Used to checkout whether this source is a C3DTilesGoogleSource. Default is + * true. You should not change this, as it is used internally for optimisation. + * @param {Object} source An object that can contain all properties of a C3DTilesGoogleSource and {@link Source}. + * @param {String} source.key Your google tiles map API access key + */ + constructor(source) { + if (!source.key) { + throw new Error('[C3DTilesGoogleSource]: A API key for the google map tiles API is required'); + } + // URL to the root tileset + source.url = `https://tile.googleapis.com/v1/3dtiles/root.json?key=${source.key}`; + super(source); + this.isC3DTilesGoogleSource = true; + this.baseUrl = 'https://tile.googleapis.com'; + this.key = source.key; + this.whenReady = Fetcher.json(source.url, this.networkOptions).then((json) => { + if (json && json.root) { + this.sessionId = findSessionId(json.root); + if (this.sessionId === null) { + throw new Error('[C3DTilesGoogleSource]: Cannot find sessionId from the tileset while it is mandatory to request tiles.'); + } + } + return json; + }); + } + + /** + * Adds the key and session to the tile url (non-standard behaviour, that is specific to Google 3D tiles), + * see https://github.com/CesiumGS/3d-tiles/issues/746 + * @param {String} url the tile url + * @returns {String} the tile url with Google map tiles api key and session parameters added at the end of the url + */ + getTileUrl(url) { + const extraParameters = `key=${this.key}&session=${this.sessionId}`; + return /\?/.test(url) ? `${url}&${extraParameters}` : `${url}?${extraParameters}`; + } +} + +export default C3DTilesGoogleSource; diff --git a/test/unit/gltfLoader.js b/test/unit/gltfparser.js similarity index 65% rename from test/unit/gltfLoader.js rename to test/unit/gltfparser.js index cbf1f423fc..c3f28a7fca 100644 --- a/test/unit/gltfLoader.js +++ b/test/unit/gltfparser.js @@ -1,14 +1,14 @@ import assert from 'assert'; -import { glTFLoader } from 'Parser/B3dmParser'; +import GLTFParser from 'Parser/GLTFParser'; import gltf from '../data/gltf/Box.gltf'; if (typeof atob === 'undefined') { global.atob = b64Encoded => Buffer.from(b64Encoded, 'base64').toString('binary'); } -describe('gltfLoader', function () { +describe('GLTFParser', function () { it('should load gltf', function () { - glTFLoader.parse(gltf, '../data/gltf/Box.gltf', (result) => { + GLTFParser.parse(gltf, '../data/gltf/', (result) => { assert.ok(result.scene); }); });