diff --git a/docs/tutorials/Fundamentals.md b/docs/tutorials/Fundamentals.md index 626bce70a4..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 and Google Photorealistic 3D Tiles). +- `{@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 a4185e110a..5403d0d491 100644 --- a/src/Main.js +++ b/src/Main.js @@ -92,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, glTFLoader, legacyGLTFLoader } from 'Parser/B3dmParser'; +export { enableDracoLoader, glTFLoader, legacyGLTFLoader } 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 603ffb455a..75efc7f7cb 100644 --- a/src/Parser/B3dmParser.js +++ b/src/Parser/B3dmParser.js @@ -1,14 +1,8 @@ import * as THREE from 'three'; -import Capabilities from 'Core/System/Capabilities'; import { GLTFLoader } from 'ThreeExtended/loaders/GLTFLoader'; -import { DRACOLoader } from 'ThreeExtended/loaders/DRACOLoader'; 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 { MeshBasicMaterial } from 'three'; -import disposeThreeMaterial from 'Utils/ThreeUtils'; import GLTFParser from './GLTFParser'; @@ -23,33 +17,6 @@ export const legacyGLTFLoader = new LegacyGLTFLoader(); /** * @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 Enable draco decoder - * // if you copied the folder from /itowns/examples/libs/draco/ to your root project, - * // You could set path with './'. - * itowns.enableDracoLoader('./'); - */ -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); -} export default { /** Parse b3dm buffer and extract THREE.Scene and batch table @@ -68,7 +35,6 @@ export default { */ parse(buffer, options) { const gltfUpAxis = options.gltfUpAxis; - const urlBase = options.urlBase; if (!buffer) { throw new Error('No array buffer provided.'); } diff --git a/src/Parser/GLTFParser.js b/src/Parser/GLTFParser.js index ee2103209a..f99acb9802 100644 --- a/src/Parser/GLTFParser.js +++ b/src/Parser/GLTFParser.js @@ -9,14 +9,9 @@ import ReferLayerProperties from 'Layer/ReferencingLayerProperties'; import { MeshBasicMaterial } from 'three'; import disposeThreeMaterial from 'Utils/ThreeUtils'; -const matrixChangeUpVectorZtoY = (new THREE.Matrix4()).makeRotationX(Math.PI / 2); +const matrixChangeUpVectorYtoZ = (new THREE.Matrix4()).makeRotationX(Math.PI / 2); export const glTFLoader = new GLTFLoader(); -const dracoLoader = new DRACOLoader(); -dracoLoader.setDecoderPath('./libs/draco/'); - - -glTFLoader.setDRACOLoader(dracoLoader); export const legacyGLTFLoader = new LegacyGLTFLoader(); @@ -45,6 +40,9 @@ function filterUnsupportedSemantics(obj) { /** * @module GLTFParser + * Supports GLTF 1.0 and 2.0 loading. + * GLTF 2.0 loading is done with THREE.GltfLoader(). + * Filters out non standard cesium-specific semantic that may have been added to gltf embedded in 3D Tiles. */ /** * Enable Draco decoding for gltf. @@ -75,23 +73,48 @@ export function enableDracoLoader(path, config) { } export default { - /** Parse gltf buffer and extract THREE.Scene and batch table + /** Parse gltf buffer and extract THREE.Scene * @param {ArrayBuffer} buffer - the gltf buffer. * @param {Object} options - additional properties. - * @param {Matrix4=} [options.gltfUpAxisMatrix={}] - Matrix4f up axis transformation, by default Z->Y is applied + * @param {Matrix4=} [options.gltfUpAxisMatrix={}] - Matrix4f up axis transformation, by default Y->Z is applied * @param {string} options.urlBase - the base url of the glTF 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. // unused here for now + * @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. - * @return {Promise} - a promise that resolves with an object containig a THREE.Scene (gltf) and a batch table (batchTable). + * @return {Promise} - a promise that resolves with an object containig a THREE.Scene (gltf) * */ parse(buffer, options) { const gltfUpAxisMatrix = options.gltfUpAxisMatrix; const urlBase = options.urlBase; + const frustumCulled = !!(options.frustumCulled); + + 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); + } + }; + if (!buffer) { throw new Error('No array buffer provided.'); } @@ -102,42 +125,22 @@ export default { const magicNumberByteLength = 4; gltfHeader.magic = utf8Decoder.decode(new Uint8Array(buffer, 0, magicNumberByteLength)); if (gltfHeader.magic) { - const promises = []; - promises.push(new Promise((resolve/* , reject */) => { + const promiseGltf = new Promise((resolve/* , reject */) => { const onload = (gltf) => { for (const scene of gltf.scenes) { scene.traverse(filterUnsupportedSemantics); } - // for gltf Z->Y is applied + // for gltf Y->Z is applied if (!gltfUpAxisMatrix) { - gltf.scene.applyMatrix4(matrixChangeUpVectorZtoY); + gltf.scene.applyMatrix4(matrixChangeUpVectorYtoZ); } else { gltf.scene.applyMatrix4(gltfUpAxisMatrix); } - 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('glTF shader has been patched to add log depth buffer support'); - } - ReferLayerProperties(mesh.material, options.layer); - } - }; - gltf.scene.traverse(init_mesh); + const shouldBePatchedForLogDepthSupport = Capabilities.isLogDepthBufferSupported() && !options.doNotPatchMaterial; + if (options.frustumCulling === false || options.overrideMaterials || shouldBePatchedForLogDepthSupport || options.layer) { + gltf.scene.traverse(init_mesh); + } resolve(gltf); }; @@ -149,8 +152,8 @@ export default { } else { glTFLoader.parse(buffer, urlBase, onload); } - })); - return Promise.all(promises).then(values => (values[0])); + }); + return promiseGltf; } else { throw new Error('Invalid gLTF file.'); } diff --git a/src/Process/3dTilesProcessing.js b/src/Process/3dTilesProcessing.js index 5069aef062..f461bbf88e 100644 --- a/src/Process/3dTilesProcessing.js +++ b/src/Process/3dTilesProcessing.js @@ -20,6 +20,7 @@ function requestNewTile(view, scheduler, geometryLayer, metadata, parent, redraw if (geometryLayer.source.isC3DTilesGoogleSource) { // special case to handle non-standard 3dTilesGoogle behavior + // see also https://github.com/CesiumGS/3d-tiles/issues/746 geometryLayer.source.completeMetadata(metadata); } diff --git a/src/Provider/3dTilesProvider.js b/src/Provider/3dTilesProvider.js index 9fc188d5aa..eaeb0131fd 100644 --- a/src/Provider/3dTilesProvider.js +++ b/src/Provider/3dTilesProvider.js @@ -26,7 +26,7 @@ function b3dmToMesh(data, layer, url) { }); } -function gltfoMesh(data, layer, url) { +function gltfToMesh(data, layer, url) { const urlBase = THREE.LoaderUtils.extractUrlBase(url); const options = { gltfUpAxis: layer.tileset.asset.gltfUpAxis, @@ -94,7 +94,6 @@ function executeCommand(command) { // Patch for supporting 3D Tiles pre 1.0 (metadata.content.url) and 1.0 // (metadata.content.uri) - // TODO should be responsability of each C3DTilesSource.completeMetadata to give the correct path. const path = metadata.content && (metadata.content.url || metadata.content.uri); const setLayer = (obj) => { @@ -107,7 +106,7 @@ function executeCommand(command) { const supportedFormats = { b3dm: b3dmToMesh, pnts: pntsParse, - gltf: gltfoMesh, + gltf: gltfToMesh, }; return Fetcher.arrayBuffer(url, layer.source.networkOptions, layer.source.urlParameters).then((result) => { if (result !== undefined) { diff --git a/src/Source/C3DTilesGoogleSource.js b/src/Source/C3DTilesGoogleSource.js index b45e4db038..80277777bc 100644 --- a/src/Source/C3DTilesGoogleSource.js +++ b/src/Source/C3DTilesGoogleSource.js @@ -3,9 +3,9 @@ import C3DTilesSource from './C3DTilesSource'; /** * @classdesc - * An object defining the source connection to a 3DTiles asset of a [Google api](https://tile.googleapis.com). + * An object defining the source connection to a 3DTiles asset from a [Google api](https://tile.googleapis.com). * - * @extends Source + * @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. @@ -17,7 +17,7 @@ class C3DTilesGoogleSource extends C3DTilesSource { * Create a new Source for 3D Tiles data from Google api. * * @constructor - * @extends Source + * @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.