Browse Source

Merge pull request #105 from NASA-AMMOS/add-draco-2

Add support for draco via manager
Garrett Johnson 5 years ago
parent
commit
ac8ec9d1e6

+ 10 - 0
CHANGELOG.md

@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
 
+## Unreleased
+
+### Added
+
+- `manager` field to `TilesRenderer` to enable support for DRACO decompression.
+
+### Fixed
+
+- `CMPTLoader` not importing `I3DMLoader`.
+
 ## [0.1.4] - 2020-07-17
 ## [0.1.4] - 2020-07-17
 ### Added
 ### Added
 
 

+ 32 - 1
README.md

@@ -118,6 +118,30 @@ scene.add( tilesRenderer.group );
 scene.add( tilesRenderer2.group );
 scene.add( tilesRenderer2.group );
 ```
 ```
 
 
+## Adding DRACO Decompression Support
+
+Adding support for DRACO decompression within the GLTF files that are transported in B3DM and I3DM formats. The same approach can be used to add support for KTX2 and DDS textures.
+
+```js
+const tilesRenderer = new TilesRenderer( './path/to/tileset.json' );
+tilesRenderer.manager.addHandler( /\.gltf$/, {
+
+	parse( ...args ) {
+
+		// Note the DRACO compression files need to be supplied via an explicit source.
+		// We use unpkg here but in practice should be provided by the application.
+		const dracoLoader = new DRACOLoader();
+		dracoLoader.setDecoderPath( 'https://unpkg.com/three@0.116.1/examples/js/libs/draco/gltf/' );
+
+		const loader = new GLTFLoader( tiles.manager );
+		loader.setDRACOLoader( dracoLoader );
+		return loader.parse( ...args );
+
+	}
+
+} );
+```
+
 # API
 # API
 
 
 ## TilesRenderer
 ## TilesRenderer
@@ -200,7 +224,6 @@ parseQueue = new PriorityQueue : PriorityQueue
 
 
 _NOTE: This cannot be modified once [update](#update) is called for the first time._
 _NOTE: This cannot be modified once [update](#update) is called for the first time._
 
 
-
 ### .group
 ### .group
 
 
 ```js
 ```js
@@ -211,6 +234,14 @@ The container group for the 3d tiles. Add this to the three.js scene in order to
 
 
 When raycasting a higher performance traversal approach is used if `raycaster.firstHitOnly = true`. If true then only the first hit of the terrain is reported in the tileset.
 When raycasting a higher performance traversal approach is used if `raycaster.firstHitOnly = true`. If true then only the first hit of the terrain is reported in the tileset.
 
 
+### .manager
+
+```js
+manager : LoadingManager
+```
+
+The manager used when loading tile geometry.
+
 ### .constructor
 ### .constructor
 
 
 ```js
 ```js

+ 18 - 0
example/index.js

@@ -29,6 +29,8 @@ import {
 } from 'three';
 } from 'three';
 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
 import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
 import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
+import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
+import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
 import * as dat from 'three/examples/jsm/libs/dat.gui.module.js';
 import * as dat from 'three/examples/jsm/libs/dat.gui.module.js';
 import Stats from 'three/examples/jsm/libs/stats.module.js';
 import Stats from 'three/examples/jsm/libs/stats.module.js';
 
 
@@ -84,6 +86,22 @@ function reinstantiateTiles() {
 
 
 	tiles = new TilesRenderer( url );
 	tiles = new TilesRenderer( url );
 	tiles.fetchOptions.mode = 'cors';
 	tiles.fetchOptions.mode = 'cors';
+	tiles.manager.addHandler( /\.gltf$/, {
+
+		parse( ...args ) {
+
+			// Note the DRACO compression files need to be supplied via an explicit source.
+			// We use unpkg here but in practice should be provided by the application.
+			const dracoLoader = new DRACOLoader();
+			dracoLoader.setDecoderPath( 'https://unpkg.com/three@0.116.1/examples/js/libs/draco/gltf/' );
+
+			const loader = new GLTFLoader( tiles.manager );
+			loader.setDRACOLoader( dracoLoader );
+			return loader.parse( ...args );
+
+		}
+
+	} );
 	offsetParent.add( tiles.group );
 	offsetParent.add( tiles.group );
 
 
 }
 }

+ 4 - 2
src/three/B3DMLoader.js

@@ -1,9 +1,10 @@
 import { B3DMLoaderBase } from '../base/B3DMLoaderBase.js';
 import { B3DMLoaderBase } from '../base/B3DMLoaderBase.js';
+import { DefaultLoadingManager } from 'three';
 import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
 import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
 
 
 export class B3DMLoader extends B3DMLoaderBase {
 export class B3DMLoader extends B3DMLoaderBase {
 
 
-	constructor( manager ) {
+	constructor( manager = DefaultLoadingManager ) {
 
 
 		super();
 		super();
 		this.manager = manager;
 		this.manager = manager;
@@ -17,7 +18,8 @@ export class B3DMLoader extends B3DMLoaderBase {
 		return new Promise( ( resolve, reject ) => {
 		return new Promise( ( resolve, reject ) => {
 
 
 			const manager = this.manager;
 			const manager = this.manager;
-			new GLTFLoader( manager ).parse( gltfBuffer, null, model => {
+			const loader = manager.getHandler( 'path.gltf' ) || new GLTFLoader( manager );
+			loader.parse( gltfBuffer, null, model => {
 
 
 				model.batchTable = b3dm.batchTable;
 				model.batchTable = b3dm.batchTable;
 				model.featureTable = b3dm.featureTable;
 				model.featureTable = b3dm.featureTable;

+ 3 - 2
src/three/CMPTLoader.js

@@ -1,11 +1,12 @@
-import { Group } from 'three';
+import { Group, DefaultLoadingManager } from 'three';
 import { CMPTLoaderBase } from '../base/CMPTLoaderBase.js';
 import { CMPTLoaderBase } from '../base/CMPTLoaderBase.js';
 import { B3DMLoader } from './B3DMLoader.js';
 import { B3DMLoader } from './B3DMLoader.js';
 import { PNTSLoader } from './PNTSLoader.js';
 import { PNTSLoader } from './PNTSLoader.js';
+import { I3DMLoader } from './I3DMLoader.js';
 
 
 export class CMPTLoader extends CMPTLoaderBase {
 export class CMPTLoader extends CMPTLoaderBase {
 
 
-	constructor( manager ) {
+	constructor( manager = DefaultLoadingManager ) {
 
 
 		super();
 		super();
 		this.manager = manager;
 		this.manager = manager;

+ 4 - 3
src/three/I3DMLoader.js

@@ -1,6 +1,6 @@
 import { I3DMLoaderBase } from '../base/I3DMLoaderBase.js';
 import { I3DMLoaderBase } from '../base/I3DMLoaderBase.js';
+import { DefaultLoadingManager, Matrix4, InstancedMesh, Vector3, Quaternion } from 'three';
 import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
 import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
-import { Matrix4, InstancedMesh, Vector3, Quaternion } from 'three';
 
 
 const tempPos = new Vector3();
 const tempPos = new Vector3();
 const tempQuat = new Quaternion();
 const tempQuat = new Quaternion();
@@ -8,7 +8,7 @@ const tempSca = new Vector3();
 const tempMat = new Matrix4();
 const tempMat = new Matrix4();
 export class I3DMLoader extends I3DMLoaderBase {
 export class I3DMLoader extends I3DMLoaderBase {
 
 
-	constructor( manager ) {
+	constructor( manager = DefaultLoadingManager ) {
 
 
 		super();
 		super();
 		this.manager = manager;
 		this.manager = manager;
@@ -26,7 +26,8 @@ export class I3DMLoader extends I3DMLoaderBase {
 				return new Promise( ( resolve, reject ) => {
 				return new Promise( ( resolve, reject ) => {
 
 
 					const manager = this.manager;
 					const manager = this.manager;
-					new GLTFLoader( manager ).parse( gltfBuffer, null, model => {
+					const loader = manager.getHandler( 'path.gltf' ) || new GLTFLoader( manager );
+					loader.parse( gltfBuffer, null, model => {
 
 
 						const INSTANCES_LENGTH = featureTable.getData( 'INSTANCES_LENGTH' );
 						const INSTANCES_LENGTH = featureTable.getData( 'INSTANCES_LENGTH' );
 
 

+ 2 - 2
src/three/PNTSLoader.js

@@ -1,9 +1,9 @@
 import { PNTSLoaderBase } from '../base/PNTSLoaderBase.js';
 import { PNTSLoaderBase } from '../base/PNTSLoaderBase.js';
-import { Points, PointsMaterial, BufferGeometry, BufferAttribute } from 'three';
+import { Points, PointsMaterial, BufferGeometry, BufferAttribute, DefaultLoadingManager } from 'three';
 
 
 export class PNTSLoader extends PNTSLoaderBase {
 export class PNTSLoader extends PNTSLoaderBase {
 
 
-	constructor( manager ) {
+	constructor( manager = DefaultLoadingManager ) {
 
 
 		super();
 		super();
 		this.manager = manager;
 		this.manager = manager;

+ 3 - 1
src/three/TilesRenderer.d.ts

@@ -1,4 +1,4 @@
-import { Box3, Camera, Vector2, WebGLRenderer, Object3D } from 'three';
+import { Box3, Camera, Vector2, WebGLRenderer, Object3D, LoadingManager } from 'three';
 import { TilesRendererBase } from '../base/TilesRendererBase';
 import { TilesRendererBase } from '../base/TilesRendererBase';
 import { TilesGroup } from './TilesGroup';
 import { TilesGroup } from './TilesGroup';
 
 
@@ -6,6 +6,8 @@ export class TilesRenderer extends TilesRendererBase {
 
 
 	autoDisableRendererCulling : Boolean;
 	autoDisableRendererCulling : Boolean;
 
 
+	manager : LoadingManager;
+
 	group : TilesGroup;
 	group : TilesGroup;
 
 
 	getBounds( box : Box3 ) : Boolean;
 	getBounds( box : Box3 ) : Boolean;

+ 36 - 30
src/three/TilesRenderer.js

@@ -85,6 +85,30 @@ export class TilesRenderer extends TilesRendererBase {
 		this.onLoadModel = null;
 		this.onLoadModel = null;
 		this.onDisposeModel = null;
 		this.onDisposeModel = null;
 
 
+		this.manager = new LoadingManager();
+		if ( useImageBitmap ) {
+
+			// TODO: We should verify that `flipY` is false on the resulting texture after load because it can't be modified after
+			// the fact. Premultiply alpha default behavior is not well defined, either.
+			// TODO: Determine whether or not options are supported before using this so we can force flipY false and premultiply alpha
+			// behavior. Fall back to regular texture loading
+			this.manager.addHandler( /(^blob:)|(\.png$)|(\.jpg$)|(\.jpeg$)/g, {
+
+				load( url, onComplete, onProgress, onError ) {
+
+					const loader = new ImageBitmapLoader( this.manager );
+					loader.load( url, res => {
+
+						onComplete( new CanvasTexture( res ) );
+
+					}, onProgress, onError);
+
+				}
+
+			} );
+
+		}
+
 	}
 	}
 
 
 	/* Public API */
 	/* Public API */
@@ -445,49 +469,32 @@ export class TilesRenderer extends TilesRendererBase {
 		tile._loadIndex = tile._loadIndex || 0;
 		tile._loadIndex = tile._loadIndex || 0;
 		tile._loadIndex ++;
 		tile._loadIndex ++;
 
 
+		const manager = this.manager;
 		const loadIndex = tile._loadIndex;
 		const loadIndex = tile._loadIndex;
-		const manager = new LoadingManager();
 		let promise = null;
 		let promise = null;
 
 
-		if ( useImageBitmap ) {
-
-			// TODO: We should verify that `flipY` is false on the resulting texture after load because it can't be modified after
-			// the fact. Premultiply alpha default behavior is not well defined, either.
-			// TODO: Determine whether or not options are supported before using this so we can force flipY false and premultiply alpha
-			// behavior. Fall back to regular texture loading
-			manager.addHandler( /(^blob:)|(\.png$)|(\.jpg$)|(\.jpeg$)/g, {
-
-				load( url, onComplete, onProgress, onError ) {
-
-					const loader = new ImageBitmapLoader();
-					loader.load( url, res => {
-
-						onComplete( new CanvasTexture( res ) );
-
-					}, onProgress, onError);
-
-				}
-
-			} );
-
-		}
-
 		switch ( extension ) {
 		switch ( extension ) {
 
 
 			case 'b3dm':
 			case 'b3dm':
-				promise = new B3DMLoader( manager ).parse( buffer );
+				promise = new B3DMLoader( manager )
+					.parse( buffer )
+					.then( res => res.scene );
 				break;
 				break;
 
 
 			case 'pnts':
 			case 'pnts':
-				promise = Promise.resolve( new PNTSLoader( manager ).parse( buffer ) );
+				promise = Promise.resolve( new PNTSLoader( manager ).parse( buffer ).scene );
 				break;
 				break;
 
 
 			case 'i3dm':
 			case 'i3dm':
-				promise = new I3DMLoader( manager ).parse( buffer );
+				promise = new I3DMLoader( manager )
+					.parse( buffer )
+					.then( res => res.scene );
 				break;
 				break;
 
 
 			case 'cmpt':
 			case 'cmpt':
-				promise = new CMPTLoader( manager ).parse( buffer );
+				promise = new CMPTLoader( manager )
+					.parse( buffer )
+					.then( res => res.scene	);
 				break;
 				break;
 
 
 			default:
 			default:
@@ -497,7 +504,7 @@ export class TilesRenderer extends TilesRendererBase {
 
 
 		}
 		}
 
 
-		return promise.then( res => {
+		return promise.then( scene => {
 
 
 			if ( tile._loadIndex !== loadIndex ) {
 			if ( tile._loadIndex !== loadIndex ) {
 
 
@@ -509,7 +516,6 @@ export class TilesRenderer extends TilesRendererBase {
 			const cached = tile.cached;
 			const cached = tile.cached;
 			const cachedTransform = cached.transform;
 			const cachedTransform = cached.transform;
 
 
-			const scene = res ? res.scene : new Group();
 			switch ( upAxis.toLowerCase() ) {
 			switch ( upAxis.toLowerCase() ) {
 
 
 				case 'x':
 				case 'x':