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..ad6e50b452 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 === true ?? false;
+
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..81b4295cef
--- /dev/null
+++ b/src/Parser/GLTFParser.js
@@ -0,0 +1,92 @@
+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.'));
+ return;
+ }
+
+ // 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..b228465e9a 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,16 @@ 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);
+ // Another specifics of 3D tiles from Google: tilesets in tilesets are required from the root base
+ // url and not from their parent base url
+ const newPrefix = layer.source.isC3DTilesGoogleSource ? layer.source.baseUrl : 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..b2203be1ff
--- /dev/null
+++ b/src/Source/C3DTilesGoogleSource.js
@@ -0,0 +1,78 @@
+import Fetcher from 'Provider/Fetcher';
+import C3DTilesSource from './C3DTilesSource';
+
+function findSessionId(tile) {
+ if (!tile) {
+ return null;
+ }
+ if (tile.content && tile.content.uri) {
+ const searchParams = new URLSearchParams(tile.content.uri.slice(tile.content.uri.indexOf('?') + 1));
+ return searchParams.get('session');
+ } 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);
});
});