Browse Source

Merge pull request #81 from NASA-AMMOS/cmpt-progress

Add initial I3DM, PNTS, CMPT loaders
Garrett Johnson 5 years ago
parent
commit
823b95fe00
52 changed files with 132970 additions and 339 deletions
  1. 9 9
      example/b3dmExample.html
  2. 0 28
      example/bundle/b3dmExample.4256bbd5.html
  3. 754 82
      example/bundle/b3dmExample.d88db709.js
  4. 1 1
      example/bundle/b3dmExample.d88db709.js.map
  5. 9 9
      example/bundle/b3dmExample.html
  6. 1 1
      example/bundle/b3dmExample.js
  7. 42939 0
      example/bundle/cmptExample.4b2a3f0d.js
  8. 1 0
      example/bundle/cmptExample.4b2a3f0d.js.map
  9. 28 0
      example/bundle/cmptExample.html
  10. 2 2
      example/bundle/b3dmExample.4256bbd5.js
  11. 1 1
      example/bundle/b3dmExample.4256bbd5.js.map
  12. 754 82
      example/bundle/customMaterial.dd39ecee.js
  13. 1 1
      example/bundle/customMaterial.dd39ecee.js.map
  14. 1 1
      example/bundle/customMaterial.js
  15. 754 82
      example/bundle/example.e31bb0bc.js
  16. 1 1
      example/bundle/example.e31bb0bc.js.map
  17. 42967 0
      example/bundle/i3dmExample.c6cc930a.js
  18. 1 0
      example/bundle/i3dmExample.c6cc930a.js.map
  19. 28 0
      example/bundle/i3dmExample.html
  20. 392 0
      example/bundle/i3dmExample.js
  21. 1 0
      example/bundle/i3dmExample.js.map
  22. 1 1
      example/bundle/index.js
  23. 42939 0
      example/bundle/pntsExample.1cabf3ff.js
  24. 1 0
      example/bundle/pntsExample.1cabf3ff.js.map
  25. 28 0
      example/bundle/pntsExample.html
  26. 392 0
      example/bundle/pntsExample.js
  27. 1 0
      example/bundle/pntsExample.js.map
  28. 30 0
      example/cmptExample.html
  29. 102 0
      example/cmptExample.js
  30. 30 0
      example/i3dmExample.html
  31. 140 0
      example/i3dmExample.js
  32. 30 0
      example/pntsExample.html
  33. 100 0
      example/pntsExample.js
  34. 11 1
      src/base/B3DMLoaderBase.js
  35. 21 0
      src/base/CMPTLoaderBase.d.ts
  36. 10 1
      src/base/CMPTLoaderBase.js
  37. 17 0
      src/base/I3DMLoaderBase.d.ts
  38. 32 20
      src/base/I3DMLoaderBase.js
  39. 16 0
      src/base/PNTSLoaderBase.d.ts
  40. 13 4
      src/base/PNTSLoaderBase.js
  41. 12 0
      src/index.js
  42. 5 8
      src/three/B3DMLoader.d.ts
  43. 19 0
      src/three/CMPTLoader.d.ts
  44. 88 0
      src/three/CMPTLoader.js
  45. 13 2
      src/three/DebugTilesRenderer.js
  46. 17 0
      src/three/I3DMLoader.d.ts
  47. 117 0
      src/three/I3DMLoader.js
  48. 16 0
      src/three/PNTSLoader.d.ts
  49. 65 0
      src/three/PNTSLoader.js
  50. 13 1
      src/three/TilesRenderer.js
  51. 39 0
      src/utilities/FeatureTable.d.ts
  52. 7 1
      src/utilities/FeatureTable.js

+ 9 - 9
example/b3dmExample.html

@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
     <head>
-		<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
-		<meta charset="utf-8"/>
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+        <meta charset="utf-8"/>
 
-		<title>3D Tiles Renderer Batch Example</title>
+        <title>3D Tiles Renderer Batch Example</title>
 
         <style>
             * {
@@ -14,14 +14,14 @@
 
             html {
                 overflow: hidden;
-				font-family: Arial, Helvetica, sans-serif;
-				user-select: none;
+                font-family: Arial, Helvetica, sans-serif;
+                user-select: none;
             }
 
-			canvas {
-				image-rendering: pixelated;
-				outline: none;
-			}
+            canvas {
+                image-rendering: pixelated;
+                outline: none;
+            }
         </style>
     </head>
     <body>

+ 0 - 28
example/bundle/b3dmExample.4256bbd5.html

@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-		<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
-		<meta charset="utf-8">
-
-		<title>3D Tiles Renderer Batch Example</title>
-
-        <style>* {
-                margin: 0;
-                padding: 0;
-            }
-
-            html {
-                overflow: hidden;
-				font-family: Arial, Helvetica, sans-serif;
-				user-select: none;
-            }
-
-			canvas {
-				image-rendering: pixelated;
-				outline: none;
-			}</style>
-    </head>
-    <body>
-        <script src="batchExample.ff06acdf.js"></script>
-    </body>
-</html>

File diff suppressed because it is too large
+ 754 - 82
example/bundle/b3dmExample.d88db709.js


File diff suppressed because it is too large
+ 1 - 1
example/bundle/b3dmExample.d88db709.js.map


+ 9 - 9
example/bundle/b3dmExample.html

@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
     <head>
-		<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
-		<meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+        <meta charset="utf-8">
 
-		<title>3D Tiles Renderer Batch Example</title>
+        <title>3D Tiles Renderer Batch Example</title>
 
         <style>* {
                 margin: 0;
@@ -13,14 +13,14 @@
 
             html {
                 overflow: hidden;
-				font-family: Arial, Helvetica, sans-serif;
-				user-select: none;
+                font-family: Arial, Helvetica, sans-serif;
+                user-select: none;
             }
 
-			canvas {
-				image-rendering: pixelated;
-				outline: none;
-			}</style>
+            canvas {
+                image-rendering: pixelated;
+                outline: none;
+            }</style>
     </head>
     <body>
         <script src="b3dmExample.d88db709.js"></script>

+ 1 - 1
example/bundle/b3dmExample.js

@@ -212,7 +212,7 @@ var parent = module.bundle.parent;
 if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
   var hostname = "" || location.hostname;
   var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
-  var ws = new WebSocket(protocol + '://' + hostname + ':' + "64703" + '/');
+  var ws = new WebSocket(protocol + '://' + hostname + ':' + "54493" + '/');
 
   ws.onmessage = function (event) {
     checkedAssets = {};

File diff suppressed because it is too large
+ 42939 - 0
example/bundle/cmptExample.4b2a3f0d.js


File diff suppressed because it is too large
+ 1 - 0
example/bundle/cmptExample.4b2a3f0d.js.map


+ 28 - 0
example/bundle/cmptExample.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+        <meta charset="utf-8">
+
+        <title>3D Tiles Renderer Composite Format Example</title>
+
+        <style>* {
+                margin: 0;
+                padding: 0;
+            }
+
+            html {
+                overflow: hidden;
+                font-family: Arial, Helvetica, sans-serif;
+                user-select: none;
+            }
+
+            canvas {
+                image-rendering: pixelated;
+                outline: none;
+            }</style>
+    </head>
+    <body>
+        <script src="cmptExample.4b2a3f0d.js"></script>
+    </body>
+</html>

+ 2 - 2
example/bundle/b3dmExample.4256bbd5.js

@@ -212,7 +212,7 @@ var parent = module.bundle.parent;
 if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
   var hostname = "" || location.hostname;
   var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
-  var ws = new WebSocket(protocol + '://' + hostname + ':' + "62153" + '/');
+  var ws = new WebSocket(protocol + '://' + hostname + ':' + "54493" + '/');
 
   ws.onmessage = function (event) {
     checkedAssets = {};
@@ -389,4 +389,4 @@ function hmrAcceptRun(bundle, id) {
   }
 }
 },{}]},{},["../node_modules/parcel-bundler/src/builtins/hmr-runtime.js"], null)
-//# sourceMappingURL=b3dmExample.4256bbd5.js.map
+//# sourceMappingURL=cmptExample.js.map

File diff suppressed because it is too large
+ 1 - 1
example/bundle/b3dmExample.4256bbd5.js.map


File diff suppressed because it is too large
+ 754 - 82
example/bundle/customMaterial.dd39ecee.js


File diff suppressed because it is too large
+ 1 - 1
example/bundle/customMaterial.dd39ecee.js.map


+ 1 - 1
example/bundle/customMaterial.js

@@ -212,7 +212,7 @@ var parent = module.bundle.parent;
 if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
   var hostname = "" || location.hostname;
   var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
-  var ws = new WebSocket(protocol + '://' + hostname + ':' + "64703" + '/');
+  var ws = new WebSocket(protocol + '://' + hostname + ':' + "54493" + '/');
 
   ws.onmessage = function (event) {
     checkedAssets = {};

File diff suppressed because it is too large
+ 754 - 82
example/bundle/example.e31bb0bc.js


File diff suppressed because it is too large
+ 1 - 1
example/bundle/example.e31bb0bc.js.map


File diff suppressed because it is too large
+ 42967 - 0
example/bundle/i3dmExample.c6cc930a.js


File diff suppressed because it is too large
+ 1 - 0
example/bundle/i3dmExample.c6cc930a.js.map


+ 28 - 0
example/bundle/i3dmExample.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+        <meta charset="utf-8">
+
+        <title>3D Tiles Renderer Instanced Example</title>
+
+        <style>* {
+                margin: 0;
+                padding: 0;
+            }
+
+            html {
+                overflow: hidden;
+                font-family: Arial, Helvetica, sans-serif;
+                user-select: none;
+            }
+
+            canvas {
+                image-rendering: pixelated;
+                outline: none;
+            }</style>
+    </head>
+    <body>
+        <script src="i3dmExample.c6cc930a.js"></script>
+    </body>
+</html>

File diff suppressed because it is too large
+ 392 - 0
example/bundle/i3dmExample.js


File diff suppressed because it is too large
+ 1 - 0
example/bundle/i3dmExample.js.map


+ 1 - 1
example/bundle/index.js

@@ -212,7 +212,7 @@ var parent = module.bundle.parent;
 if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
   var hostname = "" || location.hostname;
   var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
-  var ws = new WebSocket(protocol + '://' + hostname + ':' + "64703" + '/');
+  var ws = new WebSocket(protocol + '://' + hostname + ':' + "54493" + '/');
 
   ws.onmessage = function (event) {
     checkedAssets = {};

File diff suppressed because it is too large
+ 42939 - 0
example/bundle/pntsExample.1cabf3ff.js


File diff suppressed because it is too large
+ 1 - 0
example/bundle/pntsExample.1cabf3ff.js.map


+ 28 - 0
example/bundle/pntsExample.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+        <meta charset="utf-8">
+
+        <title>3D Tiles Renderer Points Example</title>
+
+        <style>* {
+                margin: 0;
+                padding: 0;
+            }
+
+            html {
+                overflow: hidden;
+                font-family: Arial, Helvetica, sans-serif;
+                user-select: none;
+            }
+
+            canvas {
+                image-rendering: pixelated;
+                outline: none;
+            }</style>
+    </head>
+    <body>
+        <script src="pntsExample.1cabf3ff.js"></script>
+    </body>
+</html>

File diff suppressed because it is too large
+ 392 - 0
example/bundle/pntsExample.js


File diff suppressed because it is too large
+ 1 - 0
example/bundle/pntsExample.js.map


+ 30 - 0
example/cmptExample.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+        <meta charset="utf-8"/>
+
+        <title>3D Tiles Renderer Composite Format Example</title>
+
+        <style>
+            * {
+                margin: 0;
+                padding: 0;
+            }
+
+            html {
+                overflow: hidden;
+                font-family: Arial, Helvetica, sans-serif;
+                user-select: none;
+            }
+
+            canvas {
+                image-rendering: pixelated;
+                outline: none;
+            }
+        </style>
+    </head>
+    <body>
+        <script src="./cmptExample.js"></script>
+    </body>
+</html>

+ 102 - 0
example/cmptExample.js

@@ -0,0 +1,102 @@
+import { CMPTLoader } from '../src/index.js';
+import {
+	Scene,
+	DirectionalLight,
+	AmbientLight,
+	WebGLRenderer,
+	PerspectiveCamera,
+	Box3,
+	sRGBEncoding,
+	PCFSoftShadowMap,
+} from 'three';
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
+
+let camera, controls, scene, renderer;
+let box, dirLight;
+
+init();
+animate();
+
+function init() {
+
+	scene = new Scene();
+
+	// primary camera view
+	renderer = new WebGLRenderer( { antialias: true } );
+	renderer.setPixelRatio( window.devicePixelRatio );
+	renderer.setSize( window.innerWidth, window.innerHeight );
+	renderer.setClearColor( 0x151c1f );
+	renderer.shadowMap.enabled = true;
+	renderer.shadowMap.type = PCFSoftShadowMap;
+	renderer.outputEncoding = sRGBEncoding;
+
+	document.body.appendChild( renderer.domElement );
+
+	camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 4000 );
+	camera.position.set( 400, 400, 400 );
+
+	// controls
+	controls = new OrbitControls( camera, renderer.domElement );
+	controls.screenSpacePanning = false;
+	controls.minDistance = 1;
+	controls.maxDistance = 2000;
+
+	// lights
+	dirLight = new DirectionalLight( 0xffffff, 1.25 );
+	dirLight.position.set( 1, 2, 3 ).multiplyScalar( 40 );
+	dirLight.castShadow = true;
+	dirLight.shadow.bias = - 0.01;
+	dirLight.shadow.mapSize.setScalar( 2048 );
+
+	const shadowCam = dirLight.shadow.camera;
+	shadowCam.left = - 200;
+	shadowCam.bottom = - 200;
+	shadowCam.right = 200;
+	shadowCam.top = 200;
+	shadowCam.updateProjectionMatrix();
+
+	scene.add( dirLight );
+
+	const ambLight = new AmbientLight( 0xffffff, 0.05 );
+	scene.add( ambLight );
+
+	box = new Box3();
+
+	new CMPTLoader()
+		.load( '...' )
+		.then( res => {
+
+			console.log(res);
+
+			// console.log( res );
+			// scene.add( res.scene );
+
+		} );
+
+	onWindowResize();
+	window.addEventListener( 'resize', onWindowResize, false );
+
+}
+
+function onWindowResize() {
+
+	camera.aspect = window.innerWidth / window.innerHeight;
+	renderer.setPixelRatio( window.devicePixelRatio );
+	renderer.setSize( window.innerWidth, window.innerHeight );
+	camera.updateProjectionMatrix();
+
+}
+
+function animate() {
+
+	requestAnimationFrame( animate );
+
+	render();
+
+}
+
+function render() {
+
+	renderer.render( scene, camera );
+
+}

+ 30 - 0
example/i3dmExample.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+        <meta charset="utf-8"/>
+
+        <title>3D Tiles Renderer Instanced Example</title>
+
+        <style>
+            * {
+                margin: 0;
+                padding: 0;
+            }
+
+            html {
+                overflow: hidden;
+                font-family: Arial, Helvetica, sans-serif;
+                user-select: none;
+            }
+
+            canvas {
+                image-rendering: pixelated;
+                outline: none;
+            }
+        </style>
+    </head>
+    <body>
+        <script src="./i3dmExample.js"></script>
+    </body>
+</html>

+ 140 - 0
example/i3dmExample.js

@@ -0,0 +1,140 @@
+import { I3DMLoader } from '../src/index.js';
+import {
+	Scene,
+	DirectionalLight,
+	AmbientLight,
+	WebGLRenderer,
+	PerspectiveCamera,
+	Box3,
+	sRGBEncoding,
+	PCFSoftShadowMap,
+	Vector3,
+	Quaternion,
+	Matrix4,
+} from 'three';
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
+
+let camera, controls, scene, renderer;
+let box, dirLight;
+
+init();
+animate();
+
+function init() {
+
+	scene = new Scene();
+
+	// primary camera view
+	renderer = new WebGLRenderer( { antialias: true } );
+	renderer.setPixelRatio( window.devicePixelRatio );
+	renderer.setSize( window.innerWidth, window.innerHeight );
+	renderer.setClearColor( 0x151c1f );
+	renderer.shadowMap.enabled = true;
+	renderer.shadowMap.type = PCFSoftShadowMap;
+	renderer.outputEncoding = sRGBEncoding;
+
+	document.body.appendChild( renderer.domElement );
+
+	camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 4000 );
+	camera.position.set( 100, 100, 100 );
+
+	// controls
+	controls = new OrbitControls( camera, renderer.domElement );
+	controls.screenSpacePanning = false;
+	controls.minDistance = 1;
+	controls.maxDistance = 2000;
+
+	// lights
+	dirLight = new DirectionalLight( 0xffffff, 1.25 );
+	dirLight.position.set( 1, 2, 3 ).multiplyScalar( 40 );
+	dirLight.castShadow = true;
+	dirLight.shadow.bias = - 0.01;
+	dirLight.shadow.mapSize.setScalar( 2048 );
+
+	const shadowCam = dirLight.shadow.camera;
+	shadowCam.left = - 200;
+	shadowCam.bottom = - 200;
+	shadowCam.right = 200;
+	shadowCam.top = 200;
+	shadowCam.updateProjectionMatrix();
+
+	scene.add( dirLight );
+
+	const ambLight = new AmbientLight( 0xffffff, 0.05 );
+	scene.add( ambLight );
+
+	box = new Box3();
+
+	new I3DMLoader()
+		.load( 'https://raw.githubusercontent.com/CesiumGS/3d-tiles-samples/master/tilesets/TilesetWithTreeBillboards/tree.i3dm' )
+		.then( res => {
+
+			let instance = null;
+			res.scene.traverse( c => {
+
+				if ( ! instance && c.isInstancedMesh ) {
+
+					instance = c;
+
+				}
+
+			} );
+
+			if ( instance ) {
+
+				res.scene.updateMatrixWorld( true );
+
+				const pos = new Vector3();
+				const quat = new Quaternion();
+				const sca = new Vector3();
+				const mat = new Matrix4();
+				const averagePos = new Vector3();
+
+				for ( let i = 0, l = instance.count; i < l; i ++ ) {
+
+					instance.getMatrixAt( i, mat );
+					mat.premultiply( instance.matrixWorld );
+					mat.decompose( pos, quat, sca );
+					averagePos.add( pos );
+
+				}
+
+				averagePos.divideScalar( instance.count );
+				controls.target.copy( averagePos );
+				camera.position.add( averagePos )
+				controls.update();
+
+			}
+
+			console.log( res );
+			scene.add( res.scene );
+
+		} );
+
+	onWindowResize();
+	window.addEventListener( 'resize', onWindowResize, false );
+
+}
+
+function onWindowResize() {
+
+	camera.aspect = window.innerWidth / window.innerHeight;
+	renderer.setPixelRatio( window.devicePixelRatio );
+	renderer.setSize( window.innerWidth, window.innerHeight );
+	camera.updateProjectionMatrix();
+
+}
+
+function animate() {
+
+	requestAnimationFrame( animate );
+
+	render();
+
+}
+
+function render() {
+
+	renderer.render( scene, camera );
+
+}

+ 30 - 0
example/pntsExample.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+        <meta charset="utf-8"/>
+
+        <title>3D Tiles Renderer Points Example</title>
+
+        <style>
+            * {
+                margin: 0;
+                padding: 0;
+            }
+
+            html {
+                overflow: hidden;
+                font-family: Arial, Helvetica, sans-serif;
+                user-select: none;
+            }
+
+            canvas {
+                image-rendering: pixelated;
+                outline: none;
+            }
+        </style>
+    </head>
+    <body>
+        <script src="./pntsExample.js"></script>
+    </body>
+</html>

+ 100 - 0
example/pntsExample.js

@@ -0,0 +1,100 @@
+import { PNTSLoader } from '../src/index.js';
+import {
+	Scene,
+	DirectionalLight,
+	AmbientLight,
+	WebGLRenderer,
+	PerspectiveCamera,
+	Box3,
+	sRGBEncoding,
+	PCFSoftShadowMap,
+} from 'three';
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
+
+let camera, controls, scene, renderer;
+let box, dirLight;
+
+init();
+animate();
+
+function init() {
+
+	scene = new Scene();
+
+	// primary camera view
+	renderer = new WebGLRenderer( { antialias: true } );
+	renderer.setPixelRatio( window.devicePixelRatio );
+	renderer.setSize( window.innerWidth, window.innerHeight );
+	renderer.setClearColor( 0x151c1f );
+	renderer.shadowMap.enabled = true;
+	renderer.shadowMap.type = PCFSoftShadowMap;
+	renderer.outputEncoding = sRGBEncoding;
+
+	document.body.appendChild( renderer.domElement );
+
+	camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 4000 );
+	camera.position.set( 2, 2, 2 );
+
+	// controls
+	controls = new OrbitControls( camera, renderer.domElement );
+	controls.screenSpacePanning = false;
+	controls.minDistance = 1;
+	controls.maxDistance = 2000;
+
+	// lights
+	dirLight = new DirectionalLight( 0xffffff, 1.25 );
+	dirLight.position.set( 1, 2, 3 ).multiplyScalar( 40 );
+	dirLight.castShadow = true;
+	dirLight.shadow.bias = - 0.01;
+	dirLight.shadow.mapSize.setScalar( 2048 );
+
+	const shadowCam = dirLight.shadow.camera;
+	shadowCam.left = - 200;
+	shadowCam.bottom = - 200;
+	shadowCam.right = 200;
+	shadowCam.top = 200;
+	shadowCam.updateProjectionMatrix();
+
+	scene.add( dirLight );
+
+	const ambLight = new AmbientLight( 0xffffff, 0.05 );
+	scene.add( ambLight );
+
+	box = new Box3();
+
+	new PNTSLoader()
+		.load( 'https://raw.githubusercontent.com/CesiumGS/3d-tiles-samples/master/tilesets/TilesetWithRequestVolume/points.pnts' )
+		.then( res => {
+
+			console.log( res );
+			scene.add( res.scene );
+
+		} );
+
+	onWindowResize();
+	window.addEventListener( 'resize', onWindowResize, false );
+
+}
+
+function onWindowResize() {
+
+	camera.aspect = window.innerWidth / window.innerHeight;
+	renderer.setPixelRatio( window.devicePixelRatio );
+	renderer.setSize( window.innerWidth, window.innerHeight );
+	camera.updateProjectionMatrix();
+
+}
+
+function animate() {
+
+	requestAnimationFrame( animate );
+
+	render();
+
+}
+
+function render() {
+
+	renderer.render( scene, camera );
+
+}

+ 11 - 1
src/base/B3DMLoaderBase.js

@@ -14,13 +14,23 @@ export class B3DMLoaderBase {
 	load( url ) {
 
 		return fetch( url, this.fetchOptions )
-			.then( res => res.arrayBuffer() )
+			.then( res => {
+
+				if ( ! res.ok ) {
+
+					throw new Error( `Failed to load file "${ url }" with status ${ res.status } : ${ res.statusText }` );
+
+				}
+				return res.arrayBuffer();
+
+			} )
 			.then( buffer => this.parse( buffer ) );
 
 	}
 
 	parse( buffer ) {
 
+		// TODO: this should be able to take a uint8array with an offset and length
 		const dataView = new DataView( buffer );
 
 		// 28-byte header

+ 21 - 0
src/base/CMPTLoaderBase.d.ts

@@ -0,0 +1,21 @@
+interface TileInfo {
+
+	type : String;
+	buffer : Uint8Array;
+	version : String;
+
+}
+
+export interface CMPTBaseResult {
+
+	version : String;
+	tiles : Array< TileInfo >;
+
+}
+
+export class CMPTLoaderBase {
+
+	load( url : String ) : Promise< CMPTBaseResult >;
+	parse( buffer : ArrayBuffer ) : CMPTBaseResult;
+
+}

+ 10 - 1
src/base/CMPTLoaderBase.js

@@ -12,7 +12,16 @@ export class CMPTLoaderBase {
 	load( url ) {
 
 		return fetch( url, this.fetchOptions )
-			.then( res => res.arrayBuffer() )
+			.then( res => {
+
+				if ( ! res.ok ) {
+
+					throw new Error( `Failed to load file "${ url }" with status ${ res.status } : ${ res.statusText }` );
+
+				}
+				return res.arrayBuffer();
+
+			} )
 			.then( buffer => this.parse( buffer ) );
 
 	}

+ 17 - 0
src/base/I3DMLoaderBase.d.ts

@@ -0,0 +1,17 @@
+import { FeatureTable, BatchTable } from '../utilities/FeatureTable';
+
+export interface I3DMLoaderBaseResult {
+
+	version : String;
+	featureTable: FeatureTable;
+	batchTable : BatchTable;
+	glbBytes : Uint8Array;
+
+}
+
+export class I3DMLoaderLoaderBase {
+
+	load( url : string ) : Promise< I3DMLoaderBaseResult >;
+	parse( buffer : ArrayBuffer ) : Promise< I3DMLoaderBaseResult >;
+
+}

+ 32 - 20
src/base/I3DMLoaderBase.js

@@ -1,6 +1,7 @@
 // I3DM File Format
 // https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/Instanced3DModel/README.md
 
+import { FeatureTable, BatchTable } from '../utilities/FeatureTable.js';
 import { arrayToString } from '../utilities/arrayToString.js';
 
 export class I3DMLoaderBase {
@@ -14,7 +15,16 @@ export class I3DMLoaderBase {
 	load( url ) {
 
 		return fetch( url, this.fetchOptions )
-			.then( res => res.arrayBuffer() )
+			.then( res => {
+
+				if ( ! res.ok ) {
+
+					throw new Error( `Failed to load file "${ url }" with status ${ res.status } : ${ res.statusText }` );
+
+				}
+				return res.arrayBuffer();
+
+			} )
 			.then( buffer => this.parse( buffer ) );
 
 	}
@@ -64,41 +74,43 @@ export class I3DMLoaderBase {
 		const featureTable = new FeatureTable( buffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength );
 
 		// Batch Table
-		const BATCH_ID = featureTable.getData( 'BATCH_ID', 'UNSIGNED_SHORT' );
-		let maxBatchId = - 1;
-		for ( let i = 0, l = BATCH_ID.length; i < l; i ++ ) {
-
-			maxBatchId = Math.max( BATCH_ID[ i ], maxBatchId );
-
-		}
-
-		const batchLength = maxBatchId === - 1 ? 0 : maxBatchId + 1;
+		const batchLength = featureTable.getData( 'INSTANCES_LENGTH' );
 		const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
 		const batchTable = new BatchTable( buffer, batchLength, batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength );
 
 		const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength;
 		const bodyBytes = new Uint8Array( buffer, glbStart, byteLength - glbStart );
 
-		// TODO: Consider just loading the data here rather than making the follow on function load it.
 		let glbBytes = null;
-		let externalUri = null;
+		let promise = null;
 		if ( gltfFormat ) {
 
 			glbBytes = bodyBytes;
+			promise = Promise.resolve();
 
 		} else {
 
-			externalUri = arrayToString( bodyBytes );
+			const externalUri = arrayToString( bodyBytes );
+			promise = fetch( externalUri, this.fetchOptions )
+				.then( res => res.buffer )
+				.then( buffer => {
+
+					glbBytes = new Uint8Array( buffer );
+
+				} );
 
 		}
 
-		return {
-			version,
-			featureTable,
-			batchTable,
-			glbBytes,
-			externalUri,
-		};
+		return promise.then( () => {
+
+			return {
+				version,
+				featureTable,
+				batchTable,
+				glbBytes,
+			};
+
+		} );
 
 	}
 

+ 16 - 0
src/base/PNTSLoaderBase.d.ts

@@ -0,0 +1,16 @@
+import { FeatureTable, BatchTable } from '../utilities/FeatureTable';
+
+export interface PNTSBaseResult {
+
+	version : String;
+	featureTable: FeatureTable;
+	batchTable : BatchTable;
+
+}
+
+export class PNTSLoaderBase {
+
+	load( url : string ) : Promise< PNTSBaseResult >;
+	parse( buffer : ArrayBuffer ) : PNTSBaseResult;
+
+}

+ 13 - 4
src/base/PNTSLoaderBase.js

@@ -1,9 +1,9 @@
 // PNTS File Format
 // https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/PointCloud/README.md
 
-import { BatchTable } from "../utilities/FeatureTable";
+import { FeatureTable, BatchTable } from "../utilities/FeatureTable.js";
 
-export class I3DMLoaderBase {
+export class PNTSLoaderBase {
 
 	constructor() {
 
@@ -14,7 +14,16 @@ export class I3DMLoaderBase {
 	load( url ) {
 
 		return fetch( url, this.fetchOptions )
-			.then( res => res.arrayBuffer() )
+			.then( res => {
+
+				if ( ! res.ok ) {
+
+					throw new Error( `Failed to load file "${ url }" with status ${ res.status } : ${ res.statusText }` );
+
+				}
+				return res.arrayBuffer();
+
+			} )
 			.then( buffer => this.parse( buffer ) );
 
 	}
@@ -61,7 +70,7 @@ export class I3DMLoaderBase {
 		const featureTable = new FeatureTable( buffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength );
 
 		// Batch Table
-		const batchLength = featureTable.getData( 'BATCH_LENGTH' ) || 0;
+		const batchLength = featureTable.getData( 'BATCH_LENGTH' ) || featureTable.getData( 'POINTS_LENGTH' );
 		const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
 		const batchTable = new BatchTable( buffer, batchLength, batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength );
 

+ 12 - 0
src/index.js

@@ -11,9 +11,15 @@ import {
 } from './three/DebugTilesRenderer.js';
 import { TilesRenderer } from './three/TilesRenderer.js';
 import { B3DMLoader } from './three/B3DMLoader.js';
+import { PNTSLoader } from './three/PNTSLoader.js';
+import { I3DMLoader } from './three/I3DMLoader.js';
+import { CMPTLoader } from './three/CMPTLoader.js';
 
 import { TilesRendererBase } from './base/TilesRendererBase.js';
 import { B3DMLoaderBase } from './base/B3DMLoaderBase.js';
+import { I3DMLoaderBase } from './base/I3DMLoaderBase.js';
+import { PNTSLoaderBase } from './base/PNTSLoaderBase.js';
+import { CMPTLoaderBase } from './base/CMPTLoaderBase.js';
 
 import { LRUCache } from './utilities/LRUCache.js';
 import { PriorityQueue } from './utilities/PriorityQueue.js';
@@ -22,9 +28,15 @@ export {
 	DebugTilesRenderer,
 	TilesRenderer,
 	B3DMLoader,
+	PNTSLoader,
+	I3DMLoader,
+	CMPTLoader,
 
 	TilesRendererBase,
 	B3DMLoaderBase,
+	I3DMLoaderBase,
+	PNTSLoaderBase,
+	CMPTLoaderBase,
 
 	LRUCache,
 	PriorityQueue,

+ 5 - 8
src/three/B3DMLoader.d.ts

@@ -1,15 +1,12 @@
-import { B3DMLoaderBase, B3DMBaseResult } from '../base/B3DMLoaderBase';
+import { B3DMBaseResult } from '../base/B3DMLoaderBase';
+import { LoadingManager } from 'three';
 import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
 
-export interface B3DMResult extends GLTF, B3DMBaseResult {
+export interface B3DMResult extends GLTF, B3DMBaseResult {}
 
-	batchTable : Object;
-	featureTable : Object;
-
-}
-
-export class B3DMLoader extends B3DMLoaderBase {
+export class B3DMLoader {
 
+	constructor( manager : LoadingManager );
 	load( url : String ) : Promise< B3DMResult >;
 	parse( buffer : ArrayBuffer ) : B3DMResult;
 

+ 19 - 0
src/three/CMPTLoader.d.ts

@@ -0,0 +1,19 @@
+import { B3DMBaseResult } from '../base/B3DMLoaderBase';
+import { I3DMBaseResult } from '../base/I3DMLoaderBase';
+import { PNTSBaseResult } from '../base/B3DMLoaderBase';
+import { Group } from 'three';
+
+export interface CMPTResult {
+
+	tiles : Array< B3DMBaseResult, I3DMBaseResult, PNTSBaseResult >;
+	scene : Group;
+
+}
+
+export class CMPTLoader {
+
+	constructor( manager : LoadingManager );
+	load( url : String ) : Promise< CMPTResult >;
+	parse( buffer : ArrayBuffer ) : CMPTResult;
+
+}

+ 88 - 0
src/three/CMPTLoader.js

@@ -0,0 +1,88 @@
+import { Group } from 'three';
+import { CMPTLoaderBase } from '../base/CMPTLoaderBase.js';
+import { B3DMLoader } from './B3DMLoader.js';
+import { PNTSLoader } from './PNTSLoader.js';
+
+export class CMPTLoader extends CMPTLoaderBase {
+
+	constructor( manager ) {
+
+		super();
+		this.manager = manager;
+
+	}
+
+	parse( buffer ) {
+
+		const result = super.parse( buffer );
+		const manager = this.manager;
+		const group = new Group();
+		const results = [];
+		const promises = [];
+
+		for ( const i in result.tiles ) {
+
+			const { type, buffer } = result.tiles[ i ];
+			switch ( type ) {
+
+				case 'b3dm': {
+
+					const slicedBuffer = buffer.slice();
+					const promise = new B3DMLoader( manager )
+						.parse( slicedBuffer.buffer )
+						.then( res => {
+
+							results.push( res );
+							group.add( res.scene );
+
+						} );
+
+					promises.push(promise);
+					break;
+
+				}
+
+				case 'pnts': {
+
+					const slicedBuffer = buffer.slice();
+					const pointsResult = new PNTSLoader( manager ).parse( slicedBuffer.buffer );
+					results.push( pointsResult );
+					group.add( pointsResult.scene );
+					break;
+
+				}
+
+				case 'i3dm': {
+
+					const slicedBuffer = buffer.slice();
+					const promise = new I3DMLoader( manager )
+						.parse( slicedBuffer.buffer )
+						.then( res => {
+
+							results.push( res );
+							group.add( res.scene );
+
+						} );
+					promises.push(promise);
+					break;
+
+				}
+
+			}
+
+		}
+
+		return Promise.all( promises ).then( () => {
+
+			return {
+
+				tiles: results,
+				scene: group,
+
+			};
+
+		} );
+
+	}
+
+}

+ 13 - 2
src/three/DebugTilesRenderer.js

@@ -1,4 +1,4 @@
-import { Box3Helper, Group, MeshBasicMaterial } from 'three';
+import { Box3Helper, Group, MeshBasicMaterial, PointsMaterial } from 'three';
 import { TilesRenderer } from './TilesRenderer.js';
 import { SphereHelper } from './SphereHelper.js';
 
@@ -193,7 +193,18 @@ export class DebugTilesRenderer extends TilesRenderer {
 
 					} else if ( colorMode !== NONE && currMaterial === originalMaterial ) {
 
-						c.material = new MeshBasicMaterial();
+						if ( c.isPoints ) {
+
+							const pointsMaterial= new PointsMaterial();
+							pointsMaterial.size = originalMaterial.size;
+							pointsMaterial.sizeAttenuation = originalMaterial.sizeAttenuation;
+							c.material = pointsMaterial;
+
+						} else {
+
+							c.material = new MeshBasicMaterial();
+
+						}
 
 					}
 

+ 17 - 0
src/three/I3DMLoader.d.ts

@@ -0,0 +1,17 @@
+import { I3DMBaseResult } from '../base/I3DMLoaderBase';
+import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
+
+export interface I3DMResult extends GLTF, I3DMBaseResult {
+
+	batchTable : Object;
+	featureTable : Object;
+
+}
+
+export class I3DMLoader {
+
+	constructor( manager : LoadingManager );
+	load( url : String ) : Promise< I3DMResult >;
+	parse( buffer : ArrayBuffer ) : I3DMResult;
+
+}

+ 117 - 0
src/three/I3DMLoader.js

@@ -0,0 +1,117 @@
+import { I3DMLoaderBase } from '../base/I3DMLoaderBase.js';
+import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
+import { Matrix4, InstancedMesh, Vector3, Quaternion, MeshBasicMaterial, BoxBufferGeometry } from 'three';
+
+const tempPos = new Vector3();
+const tempQuat = new Quaternion();
+const tempSca = new Vector3();
+const tempMat = new Matrix4();
+export class I3DMLoader extends I3DMLoaderBase {
+
+	constructor( manager ) {
+
+		super();
+		this.manager = manager;
+
+	}
+
+	parse( buffer ) {
+
+		return super
+			.parse( buffer )
+			.then( i3dm => {
+
+				const { featureTable, batchTable } = i3dm;
+				const gltfBuffer = i3dm.glbBytes.slice().buffer;
+				return new Promise( ( resolve, reject ) => {
+
+					const manager = this.manager;
+					new GLTFLoader( manager ).parse( gltfBuffer, null, model => {
+
+						const INSTANCES_LENGTH = featureTable.getData( 'INSTANCES_LENGTH' );
+
+						// RTC_CENTER
+						// QUANTIZED_VOLUME_OFFSET
+						// QUANTIZED_VOLUME_SCALE
+						// EAST_NORTH_UP
+
+						const POSITION = featureTable.getData( 'POSITION', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
+
+						// POSITION_QUANTIZED
+						// NORMAL_UP
+						// NORMAL_RIGHT
+						// NORMAL_UP_OCT32P
+						// NORMAL_RIGHT_OCT32P
+						// SCALE
+						// SCALE_NON_UNIFORM
+						// BATCH_ID
+
+						const instanceMap = new Map();
+						const instances = [];
+						model.scene.traverse( child => {
+
+							if ( child.isMesh ) {
+
+								const { geometry, material } = child;
+								const instancedMesh = new InstancedMesh( geometry, material, INSTANCES_LENGTH );
+								instances.push( instancedMesh );
+								instanceMap.set( child, instancedMesh );
+
+							}
+
+						} );
+
+						// replace the meshes with instanced meshes
+						instanceMap.forEach( ( instancedMesh, mesh ) => {
+
+							const parent = mesh.parent;
+							if ( parent ) {
+
+								// Mesh have no children
+								parent.remove( mesh );
+								parent.add( instancedMesh );
+
+							}
+
+
+						} );
+
+						for ( let i = 0; i < INSTANCES_LENGTH; i ++ ) {
+
+							// TODO: handle quantized position
+							tempPos.set(
+								POSITION[ i * 3 + 0 ],
+								POSITION[ i * 3 + 1 ],
+								POSITION[ i * 3 + 2 ],
+							);
+
+							// TODO: handle normal orientation features
+							tempQuat.set( 0, 0, 0, 1 );
+
+							// TODO: handle scale features
+							tempSca.set( 1, 1, 1 );
+
+							tempMat.compose( tempPos, tempQuat, tempSca );
+
+							for ( let j = 0, l = instances.length; j < l; j ++ ) {
+
+								const instance = instances[ j ];
+								instance.setMatrixAt( i, tempMat );
+
+							}
+
+						}
+
+						model.batchTable = batchTable;
+						model.featureTable = featureTable;
+						resolve( model );
+
+					}, reject );
+
+				} );
+
+			} );
+
+	}
+
+}

+ 16 - 0
src/three/PNTSLoader.d.ts

@@ -0,0 +1,16 @@
+import { PNTSBaseResult } from '../base/PNTSLoaderBase';
+import { Points } from 'three';
+
+export interface PNTSResult extends PNTSBaseResult {
+
+	scene: Points;
+
+}
+
+export class PNTSLoader {
+
+	constructor( manager : LoadingManager );
+	load( url : String ) : Promise< PNTSResult >;
+	parse( buffer : ArrayBuffer ) : PNTSResult;
+
+}

+ 65 - 0
src/three/PNTSLoader.js

@@ -0,0 +1,65 @@
+import { PNTSLoaderBase } from '../base/PNTSLoaderBase.js';
+import { Points, PointsMaterial, BufferGeometry, BufferAttribute } from 'three';
+
+export class PNTSLoader extends PNTSLoaderBase {
+
+	constructor( manager ) {
+
+		super();
+		this.manager = manager;
+
+	}
+
+	parse( buffer ) {
+
+		const result = super.parse( buffer );
+		const { featureTable } = result;
+		window.data = result
+
+		// global semantics
+		const POINTS_LENGTH = featureTable.getData( 'POINTS_LENGTH' );
+
+		// RTC_CENTER
+		// QUANTIZED_VOLUME_OFFSET
+		// QUANTIZED_VOLUME_SCALE
+		// CONSTANT_RGBA
+		// BATCH_LENGTH
+
+		const POSITION = featureTable.getData( 'POSITION', POINTS_LENGTH, 'FLOAT', 'VEC3' );
+		const RGB = featureTable.getData( 'RGB', POINTS_LENGTH, 'UNSIGNED_BYTE', 'VEC3' );
+
+		// POSITION_QUANTIZED
+		// RGBA
+		// RGB565
+		// NORMAL
+		// NORMAL_OCT16P
+		// BATCH_ID
+
+		if ( POSITION === null ) {
+
+			throw new Error( 'PNTSLoader : POSITION_QUANTIZED feature type is not supported.' );
+
+		}
+
+		const geometry = new BufferGeometry();
+		geometry.setAttribute( 'position', new BufferAttribute( POSITION, 3, false ) );
+
+		const material = new PointsMaterial();
+		material.size = 2;
+		material.sizeAttenuation = false;
+
+		if ( RGB !== null ) {
+
+			geometry.setAttribute( 'color', new BufferAttribute( RGB, 3, true ) );
+			material.vertexColors = true;
+
+		}
+
+		const object = new Points( geometry, material );
+		result.scene = object;
+
+		return result;
+
+	}
+
+}

+ 13 - 1
src/three/TilesRenderer.js

@@ -1,5 +1,8 @@
 import { TilesRendererBase } from '../base/TilesRendererBase.js';
 import { B3DMLoader } from './B3DMLoader.js';
+import { PNTSLoader } from './PNTSLoader.js';
+import { I3DMLoader } from './I3DMLoader.js';
+import { CMPTLoader } from './CMPTLoader.js';
 import { TilesGroup } from './TilesGroup.js';
 import {
 	Matrix4,
@@ -438,8 +441,17 @@ export class TilesRenderer extends TilesRendererBase {
 				break;
 
 			case 'pnts':
-			case 'cmpt':
+				promise = Promise.resolve( new PNTSLoader( manager ).parse( buffer ) );
+				break;
+
 			case 'i3dm':
+				promise = new I3DMLoader( manager ).parse( buffer );
+				break;
+
+			case 'cmpt':
+				promise = new CMPTLoader( manager ).parse( buffer );
+				break;
+
 			default:
 				console.warn( `TilesRenderer: Content type "${ extension }" not supported.` );
 				promise = Promise.resolve( null );

+ 39 - 0
src/utilities/FeatureTable.d.ts

@@ -0,0 +1,39 @@
+export class FeatureTable {
+
+	constructor(
+		buffer : ArrayBuffer,
+		start : Number,
+		headerLength : Number,
+		binLength : Number
+	);
+
+	getKeys() : Array< String >;
+
+	getData(
+		key : String,
+		count : Number,
+		defaultComponentType? : String | null,
+		defaultType? : String | null
+	) : Number | String | ArrayBufferView;
+
+}
+
+export class BatchTable {
+
+	constructor(
+		buffer : ArrayBuffer,
+		batchSize : Number,
+		start : Number,
+		headerLength : Number,
+		binLength : Number
+	);
+
+	getKeys() : Array< String >;
+
+	getData(
+		key : String,
+		componentType : String | null,
+		type : String | null
+	) : Number | String | ArrayBufferView;
+
+}

+ 7 - 1
src/utilities/FeatureTable.js

@@ -80,6 +80,9 @@ export class FeatureTable {
 					stride = 4;
 					break;
 
+				default:
+					throw new Error( `FeatureTable : Feature type not provided for "${ key }".` );
+
 			}
 
 			let data;
@@ -120,6 +123,9 @@ export class FeatureTable {
 					data = new Float64Array( buffer, arrayStart, arrayLength );
 					break;
 
+				default:
+					throw new Error( `FeatureTable : Feature component type not provided for "${ key }".` );
+
 			}
 
 			const dataEnd = arrayStart + arrayLength * data.BYTES_PER_ELEMENT;
@@ -148,7 +154,7 @@ export class BatchTable extends FeatureTable {
 
 	getData( key, componentType = null, type = null ) {
 
-		return this.getData( key, this.batchSize, type, componentType );
+		return super.getData( key, this.batchSize, type, componentType );
 
 	}