@jdultra/threedtiles 3.3.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,14 @@
1
- # threedtiles
1
+ # T H R E E D T I L E S : http://www.jdultra.com/
2
2
 
3
- 3DTiles viewer for three.js
4
3
 
5
- Photogrametry : https://ebeaufay.github.io/ThreedTilesViewer.github.io/
6
4
 
7
- IFC : https://storage.googleapis.com/jdultra.com/ifc/index.html
5
+ The fastest 3DTiles viewer for three.js
8
6
 
9
- Occlusion culling : [https://storage.googleapis.com/jdultra.com/occlusionCulling/index.html](https://storage.googleapis.com/www.jdultra.com/occlusion/index.html)
7
+ [Photogrametry (OBJ conversion)](https://ebeaufay.github.io/ThreedTilesViewer.github.io/)
8
+
9
+ [PBR material (GlTF conversion)](https://www.jdultra.com/pbr/)
10
+
11
+ [Occlusion culling (IFC conversion)](https://www.jdultra.com/occlusion/index.html)
10
12
 
11
13
  Adding a tileset to a scene is as easy as :
12
14
 
@@ -26,7 +28,7 @@ It's up to the user to call updates on the tileset. You might call them whenever
26
28
  ```
27
29
  setInterval(function () {
28
30
  ogc3DTile.update(camera);
29
- }, 200);
31
+ }, 20);
30
32
  ```
31
33
 
32
34
  Currently, the library is limmited to B3DM files.
@@ -71,6 +73,21 @@ const ogc3DTile = new OGC3DTile({
71
73
  ```
72
74
 
73
75
  ### Callback
76
+
77
+ #### onLoadCallback
78
+ Add a callback that is called once when the first tile is loaded and geometry is available.
79
+ This can be useful to position the tileset at a specific location when it is not centered on origin for example.
80
+
81
+ ```
82
+ const ogc3DTile = new OGC3DTile({
83
+ url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
84
+ onLoadCallback: tilese => {
85
+ console.log(tileset.boundingVolume);
86
+ }
87
+ });
88
+ ```
89
+
90
+ #### Mesh callback
74
91
  Add a callback on loaded tiles in order to set a material or do some logic on the meshes.
75
92
 
76
93
  ```
@@ -123,8 +140,8 @@ ogc3DTile.rotateOnAxis(new THREE.Vector3(1,0,0), -Math.PI*0.5);
123
140
  ### Occlusion culling
124
141
  Occlusion culling prevents the refinment of data that is hidden by other data, like a wall. It can have a big impact on frame-rate and loading speed for interior scenes.
125
142
 
126
- A word of warning: activating occlusion culling causes an extra render-pass and as such, has an impact on frame-rate.
127
- It will be most beneficial on interior scenes where most of the data is occluded by walls. All the tiles that don't need to be downloaded or drawn will balance out the cost of the extra render pass.
143
+ A word of warning: activating occlusion culling has an impact on frame-rate.
144
+ It will be most beneficial on interior scenes where most of the data is occluded by walls. All the tiles that don't need to be downloaded or drawn will balance out the cost of the occlusion logic.
128
145
 
129
146
 
130
147
  First, instantiate an OcclusionCullingService:
@@ -157,7 +174,7 @@ occlusionCullingService.setSide(THREE.DoubleSide);
157
174
  ```
158
175
 
159
176
 
160
- ### static tilesets (Performance tip)
177
+ ### static tilesets and other performance tips
161
178
  When you know your tileset will be static, you can specify it in the OGC3DTile object constructor parameter.
162
179
  This will skip recalculating the transformation matrix of every tile each frame and give a few extra frames per second.
163
180
 
@@ -168,12 +185,22 @@ const ogc3DTile = new OGC3DTile({
168
185
  });
169
186
  ```
170
187
 
171
- # Displaying meshes on a globe
172
- I'm working on this project in parallel https://github.com/ebeaufay/UltraGlobe which allows displaying a globe with multi resolution imagery, elevation and 3DTiles.
188
+ Either way, it's advised to set the autoUpdate property of the scene to false and update the matrices manually whenever you move things around.
189
+
190
+ ```
191
+ scene.autoUpdate = false;
192
+ ```
193
+
194
+ # Projects that use this library
195
+ https://github.com/ebeaufay/UltraGlobe allows displaying a globe with multi resolution imagery, elevation and 3DTiles.
196
+
197
+ Don't hesitate to tell me if you have a project that stems from this code. I'd love to link to it here and I'm always open to implementing extra features.
198
+ Contact: emeric.beaufays@jdultra.com
199
+
173
200
 
174
201
  # Mesh to 3DTiles Converter
175
202
 
176
203
  I also have code to convert meshes to 3DTiles with no limit to the size of the dataset relative to faces or textures.
177
204
  It works for all types of meshes: photogrametry, BIM, colored or textured meshes with a single texture atlas or many individual textures.
178
205
  I'm keeping the code private for now but feel free to contact me about it.
179
- Contact: emericbeaufays@gmail.com
206
+ Contact: emeric.beaufays@jdultra.com
package/index.html CHANGED
@@ -48,12 +48,9 @@
48
48
  <body>
49
49
  <div id="screen"></div>
50
50
  <div style="position: absolute; top: 1%; z-index: 100; right:1%; ">
51
- <input type="range" min="0.1" max="2" value="1.0", step="0.001" class="slider" id="lodMultiplier" >
51
+ <input type="range" min="0.0" max="1.0" value="1.0", step="0.001" class="slider" id="lodMultiplier" >
52
52
  <p style="color: #0439aa;">LOD multiplier: <span id="multiplierValue"></span></p>
53
53
  </div>
54
- <div style="position: absolute; bottom: 1%; z-index: 100;">
55
- <a href="https://skfb.ly/6UoNJ">ORIGINAL MODEL</a>
56
- </div>
57
54
  </body>
58
55
 
59
56
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jdultra/threedtiles",
3
- "version": "3.3.1",
3
+ "version": "4.0.0",
4
4
  "description": "An OGC 3DTiles viewer for Three.js",
5
5
  "main": "tileset.js",
6
6
  "scripts": {
@@ -23,29 +23,30 @@
23
23
  "author": "Emeric Beaufays",
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
- "gltf-validator": ">=2.0.0-dev.3.3",
26
+ "gltf-validator": "^2.0.0-dev.3.9",
27
27
  "js-utils-z": "1.2.1",
28
28
  "lodash": ">=4.17.20",
29
- "lru-cache": "^7.4.1",
30
- "mnemonist": "^0.39.0",
29
+ "lru-cache": "^7.14.1",
30
+ "mnemonist": "^0.39.5",
31
31
  "path-browserify": "^1.0.1",
32
- "regenerator-runtime": ">=0.13.7",
32
+ "regenerator-runtime": "^0.13.11",
33
33
  "set-interval-async": "^2.0.3",
34
- "three": "0.140.2",
34
+ "three": "0.146.0",
35
35
  "uuid": "^8.3.2"
36
36
  },
37
37
  "devDependencies": {
38
- "@babel/core": "^7.12.9",
39
- "@babel/preset-env": "^7.12.7",
40
- "babel-loader": "^8.2.2",
38
+ "@babel/core": "^7.20.2",
39
+ "@babel/preset-env": "^7.20.2",
40
+ "babel-loader": "^8.3.0",
41
41
  "copy-webpack-plugin": "^6.3.2",
42
- "core-js": "^3.8.0",
42
+ "core-js": "^3.26.1",
43
43
  "html-loader": "^1.3.2",
44
44
  "html-webpack-plugin": "^4.5.0",
45
- "mini-css-extract-plugin": "^1.3.1",
46
- "webpack": "^5.65.0",
45
+ "mini-css-extract-plugin": "^1.6.2",
46
+ "webpack": "^5.75.0",
47
47
  "webpack-cli": "4.9.1",
48
- "webpack-dev-server": "^4.7.4",
48
+ "webpack-dev-server": "^4.11.1",
49
+ "webpack-glsl-loader": "^1.0.1",
49
50
  "whatwg-fetch": "^3.5.0"
50
51
  }
51
52
  }
@@ -1,92 +1,91 @@
1
1
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
2
2
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
3
- //import { LegacyGLTFLoader } from './LegacyGLTFLoader.js';
3
+ import * as THREE from 'three';
4
4
 
5
5
  const gltfLoader = new GLTFLoader();
6
6
  const dracoLoader = new DRACOLoader();
7
- dracoLoader.setDecoderPath( 'https://www.gstatic.com/draco/versioned/decoders/1.4.3/' );
8
- gltfLoader.setDRACOLoader( dracoLoader );
7
+ dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.4.3/');
8
+ gltfLoader.setDRACOLoader(dracoLoader);
9
+ const dummy = new THREE.Object3D();
9
10
  //const legacyGLTFLoader = new LegacyGLTFLoader();
10
- const B3DMDecoder = {
11
- parseB3DM: (arrayBuffer, meshCallback) => {
12
- const dataView = new DataView(arrayBuffer);
13
11
 
14
- const magic =
15
- String.fromCharCode(dataView.getUint8(0)) +
16
- String.fromCharCode(dataView.getUint8(1)) +
17
- String.fromCharCode(dataView.getUint8(2)) +
18
- String.fromCharCode(dataView.getUint8(3));
19
- console.assert(magic === 'b3dm');
12
+ function parseB3DM(arrayBuffer, meshCallback) {
13
+ const dataView = new DataView(arrayBuffer);
20
14
 
21
- const version = dataView.getUint32(4, true);
22
- console.assert(version === 1);
15
+ const magic =
16
+ String.fromCharCode(dataView.getUint8(0)) +
17
+ String.fromCharCode(dataView.getUint8(1)) +
18
+ String.fromCharCode(dataView.getUint8(2)) +
19
+ String.fromCharCode(dataView.getUint8(3));
20
+ console.assert(magic === 'b3dm');
23
21
 
24
- const byteLength = dataView.getUint32(8, true);
25
- console.assert(byteLength === arrayBuffer.byteLength);
22
+ const version = dataView.getUint32(4, true);
23
+ console.assert(version === 1);
26
24
 
27
- const featureTableJSONByteLength = dataView.getUint32(12, true);
28
- const featureTableBinaryByteLength = dataView.getUint32(16, true);
29
- const batchTableJSONByteLength = dataView.getUint32(20, true);
30
- const batchTableBinaryByteLength = dataView.getUint32(24, true);
25
+ const byteLength = dataView.getUint32(8, true);
26
+ console.assert(byteLength === arrayBuffer.byteLength);
31
27
 
32
- const featureTableStart = 28;
33
- //const featureTable = new FeatureTable( arrayBuffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength );
28
+ const featureTableJSONByteLength = dataView.getUint32(12, true);
29
+ const featureTableBinaryByteLength = dataView.getUint32(16, true);
30
+ const batchTableJSONByteLength = dataView.getUint32(20, true);
31
+ const batchTableBinaryByteLength = dataView.getUint32(24, true);
34
32
 
35
- const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
36
- //const batchTable = new BatchTable( arrayBuffer, featureTable.getData( 'BATCH_LENGTH' ), batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength );
33
+ const featureTableStart = 28;
34
+ //const featureTable = new FeatureTable( arrayBuffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength );
37
35
 
38
- const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength;
39
- const glbBytes = new Uint8Array(arrayBuffer, glbStart, byteLength - glbStart);
36
+ const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
37
+ //const batchTable = new BatchTable( arrayBuffer, featureTable.getData( 'BATCH_LENGTH' ), batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength );
40
38
 
39
+ const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength;
40
+ const glbBytes = new Uint8Array(arrayBuffer, glbStart, byteLength - glbStart);
41
41
 
42
- const gltfBuffer = glbBytes.slice().buffer;
43
42
 
43
+ const gltfBuffer = glbBytes.slice().buffer;
44
44
 
45
- return new Promise((resolve, reject) => {
46
45
 
47
- gltfLoader.parse(gltfBuffer, null, model => {
46
+ return new Promise((resolve, reject) => {
48
47
 
49
- ////TODO
50
- //model.batchTable = b3dm.batchTable;
51
- //model.featureTable = b3dm.featureTable;
48
+ gltfLoader.parse(gltfBuffer, null, model => {
52
49
 
53
- //model.scene.batchTable = b3dm.batchTable;
54
- //model.scene.featureTable = b3dm.featureTable;
50
+ ////TODO
51
+ //model.batchTable = b3dm.batchTable;
52
+ //model.featureTable = b3dm.featureTable;
55
53
 
56
- //const scene = mergeColoredObject(model.scene);
57
- model.scene.traverse((o) => {
58
- if (o.isMesh) {
59
- if (!!meshCallback) {
60
- meshCallback(o);
61
- }
54
+ //model.scene.batchTable = b3dm.batchTable;
55
+ //model.scene.featureTable = b3dm.featureTable;
62
56
 
57
+ //const scene = mergeColoredObject(model.scene);
58
+ model.scene.traverse((o) => {
59
+ if (o.isMesh) {
60
+ if (!!meshCallback) {
61
+ meshCallback(o);
63
62
  }
64
- });
65
- resolve(model.scene);
66
- }, error=>{
67
- console.error(error);
68
- /* legacyGLTFLoader.parse(gltfBuffer, model => {
69
-
70
- ////TODO
71
- //model.batchTable = b3dm.batchTable;
72
- //model.featureTable = b3dm.featureTable;
73
-
74
- //model.scene.batchTable = b3dm.batchTable;
75
- //model.scene.featureTable = b3dm.featureTable;
76
-
77
- //const scene = mergeColoredObject(model.scene);
78
- model.scene.traverse((o) => {
79
- if (o.isMesh) {
80
- if (!!meshCallback) {
81
- meshCallback(o);
82
- }
83
-
84
- }
85
- });
86
- resolve(model.scene);
87
- }, null); */
63
+
64
+ }
88
65
  });
66
+ resolve(model.scene);
67
+ }, error => {
68
+ console.error(error);
89
69
  });
70
+ });
71
+ }
72
+
73
+ const B3DMDecoder = {
74
+ parseB3DM: parseB3DM,
75
+ parseB3DMInstanced: (arrayBuffer, meshCallback, maxCount) => { // expects GLTF with one node level
76
+
77
+ return parseB3DM(arrayBuffer, meshCallback).then(mesh => {
78
+ let instancedMesh;
79
+ mesh.traverse(child => {
80
+ if (child.isMesh) {
81
+ instancedMesh = new THREE.InstancedMesh(child.geometry, child.material, maxCount);
82
+ instancedMesh.baseMatrix = child.matrix;
83
+ //console.log(child.matrix.elements[12])
84
+ }
85
+ });
86
+ return instancedMesh;
87
+ });
88
+
90
89
  }
91
90
  }
92
91
 
package/src/index.js CHANGED
@@ -6,33 +6,86 @@ import { TileLoader } from "./tileset/TileLoader";
6
6
  import { MapControls, OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
7
7
  import { setIntervalAsync } from 'set-interval-async/dynamic';
8
8
  import { OcclusionCullingService } from "./tileset/OcclusionCullingService";
9
+ import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
10
+ import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
11
+ import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
12
+ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
9
13
 
14
+ import { InstancedOGC3DTile} from "./tileset/instanced/InstancedOGC3DTile.js"
15
+ import { InstancedTileLoader} from "./tileset/instanced/InstancedTileLoader.js"
16
+
17
+ import { B3DMDecoder } from "./decoder/B3DMDecoder";
10
18
 
11
19
  const occlusionCullingService = new OcclusionCullingService();
12
20
  occlusionCullingService.setSide(THREE.DoubleSide);
13
21
  const scene = initScene();
22
+
14
23
  const domContainer = initDomContainer("screen");
15
24
  const camera = initCamera();
16
- const ogc3DTiles = initTileset(scene);
17
- initLODMultiplierSlider(ogc3DTiles)
25
+ //const ogc3DTiles = initTileset(scene);
26
+
27
+
28
+ const instancedTileLoader = createInstancedTileLoader(scene);
29
+ initInstancedTilesets(instancedTileLoader);
30
+
18
31
  const controller = initController(camera, domContainer);
19
32
 
20
33
  const stats = initStats(domContainer);
21
34
  const renderer = initRenderer(camera, domContainer);
35
+ const composer = initComposer(scene, camera, renderer);
36
+
37
+
38
+ /* fetch("https://storage.googleapis.com/ogc-3d-tiles/droneship/1/2007.b3dm").then(result => {
39
+
40
+ if (!result.ok) {
41
+ console.error("could not load tile with path : " + path)
42
+ throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
43
+ }
44
+ return result.arrayBuffer();
45
+
46
+ })
47
+ .then(resultArrayBuffer=>{
48
+ return B3DMDecoder.parseB3DMInstanced(resultArrayBuffer, self.meshCallback, 1);
49
+ })
50
+ .then(mesh=>{
51
+ scene.add(mesh)
52
+
53
+ }) */
22
54
 
23
55
 
24
56
  animate();
25
57
 
58
+
59
+ function initComposer(scene, camera, renderer) {
60
+ const renderScene = new RenderPass(scene, camera);
61
+ const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.4, 0.5, 0);
62
+
63
+
64
+ const composer = new EffectComposer(renderer);
65
+ composer.addPass(renderScene);
66
+ composer.addPass(bloomPass);
67
+ return composer;
68
+ }
26
69
  function initScene() {
27
70
  const scene = new THREE.Scene();
28
71
  scene.matrixAutoUpdate = false;
29
- scene.background = new THREE.Color(0xaaffcc);
30
- scene.add(new THREE.AmbientLight(0xFFFFFF, 0.8));
31
- const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.2 );
32
- directionalLight.position.set(100,100,100)
33
- directionalLight.lookAt(-1,-1,-1)
34
- scene.add( directionalLight );
35
- scene.autoUpdate = false;
72
+ scene.background = new THREE.Color(0x000000);
73
+ scene.add(new THREE.AmbientLight(0xFFFFFF, 0.2));
74
+
75
+ const light = new THREE.PointLight(0xbbbbff, 2, 5000);
76
+ const sphere = new THREE.SphereGeometry(2, 16, 8);
77
+ light.add(new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ color: 0xbbbbff })));
78
+ scene.add(light);
79
+ light.position.set(200, 200, 200);
80
+
81
+
82
+ const light2 = new THREE.PointLight(0xffbbbb, 2, 5000);
83
+ const sphere2 = new THREE.SphereGeometry(2, 16, 8);
84
+ light2.add(new THREE.Mesh(sphere2, new THREE.MeshBasicMaterial({ color: 0xffbbbb })));
85
+ scene.add(light2);
86
+ light2.position.set(200, 100, -100);
87
+
88
+ scene.matrixWorldAutoUpdate = true;
36
89
  return scene;
37
90
  }
38
91
 
@@ -51,6 +104,8 @@ function initRenderer(camera, dom) {
51
104
  renderer.setPixelRatio(window.devicePixelRatio);
52
105
  renderer.setSize(dom.offsetWidth, dom.offsetHeight);
53
106
  renderer.outputEncoding = THREE.sRGBEncoding;
107
+ //renderer.toneMapping = THREE.ReinhardToneMapping;
108
+ //renderer.toneMappingExposure = Math.pow(0.8, 4.0);
54
109
  renderer.autoClear = false;
55
110
 
56
111
  dom.appendChild(renderer.domElement);
@@ -77,8 +132,8 @@ function initStats(dom) {
77
132
 
78
133
 
79
134
  function initCamera() {
80
- const camera = new THREE.PerspectiveCamera(70, window.offsetWidth / window.offsetHeight, 0.1, 1000);
81
- camera.position.set(-10, 5, 20);
135
+ const camera = new THREE.PerspectiveCamera(40, window.offsetWidth / window.offsetHeight, 1, 100000);
136
+ camera.position.set(100, 10, 100);
82
137
  camera.matrixAutoUpdate = true;
83
138
  return camera;
84
139
  }
@@ -88,70 +143,117 @@ function initTileset(scene) {
88
143
  const tileLoader = new TileLoader(mesh => {
89
144
  //// Insert code to be called on every newly decoded mesh e.g.:
90
145
  mesh.material.wireframe = false;
91
- mesh.material.side = THREE.DoubleSide;
146
+ mesh.material.side = THREE.FrontSide;
92
147
  }, 1000)
93
148
  const ogc3DTile = new OGC3DTile({
94
- url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tiledWithSkirts/tileset.json",
95
- //url: "http://localhost:8080/tileset.json",
96
- geometricErrorMultiplier: 0.5,
149
+ url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
150
+ //url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
151
+ geometricErrorMultiplier: 1.0,
97
152
  loadOutsideView: false,
98
153
  tileLoader: tileLoader,
99
- occlusionCullingService: occlusionCullingService,
100
- static: false
101
- });
102
- ogc3DTile.translateZ(200) // Z-UP to Y-UP
103
- const ogc3DTile2 = new OGC3DTile({
104
- url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tiledWithSkirts/tileset.json",
105
- //url: "http://localhost:8080/tileset.json",
106
- geometricErrorMultiplier: 0.5,
107
- loadOutsideView: false,
108
- //tileLoader: tileLoader,
109
- occlusionCullingService: occlusionCullingService,
110
- static: false
154
+ //occlusionCullingService: occlusionCullingService,
155
+ static: false,
156
+
111
157
  });
112
158
 
113
159
 
114
-
160
+
161
+
115
162
  //// The OGC3DTile object is a threejs Object3D so you may do all the usual opperations like transformations e.g.:
116
163
  //ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
117
164
  //// If the OGC3DTile object is marked as "static" (constructorParameter), these operations will not work.
118
-
119
-
165
+
166
+
167
+
120
168
  //// It's up to the user to call updates on the tileset. You might call them whenever the camera moves or at regular time intervals like here
121
169
 
122
170
 
123
-
171
+
124
172
  var interval;
125
173
  document.addEventListener('keyup', (e) => {
126
174
  console.log(camera.position)
127
- if (!e.key || e.key !== "p") return;
128
- if (!!interval) {
129
- clearInterval(interval);
130
- interval = null;
131
- } else {
132
- startInterval();
175
+ if (!!e.key && e.key !== "p") {
176
+
177
+ if (!!interval) {
178
+ clearInterval(interval);
179
+ interval = null;
180
+ } else {
181
+ startInterval();
182
+ }
183
+ }
184
+ if (!!e.key && e.key !== "l") {
185
+
186
+ console.log("new THREE.Vector3(" + camera.position.x + "," + camera.position.y + "," + camera.position.z + ")");
187
+ console.log("new THREE.Quaternion(" + camera.quaternion.x + "," + camera.quaternion.y + "," + camera.quaternion.z + "," + camera.quaternion.w + ")");
188
+
133
189
  }
190
+
134
191
  });
135
192
  function startInterval() {
136
193
  interval = setIntervalAsync(function () {
137
194
  ogc3DTile.update(camera);
138
- ogc3DTile2.update(camera);
195
+
139
196
  }, 20);
140
197
  }
141
198
  startInterval();
142
199
 
143
200
  scene.add(ogc3DTile)
144
- scene.add(ogc3DTile2)
145
201
  return ogc3DTile;
146
202
  }
147
203
 
148
- function initLODMultiplierSlider(tileset) {
204
+ function createInstancedTileLoader(scene){
205
+ return new InstancedTileLoader(scene, mesh => {
206
+ //// Insert code to be called on every newly decoded mesh e.g.:
207
+ mesh.material.wireframe = false;
208
+ mesh.material.side = THREE.FrontSide;
209
+ }, 1000, 1000);
210
+ }
211
+ function initInstancedTilesets(instancedTileLoader){
212
+
213
+ const instancedTilesets = [];
214
+
215
+ for(let x = 0; x<10; x++){
216
+ for(let y = 0; y<10; y++){
217
+ for(let z = 0; z<10; z++){
218
+ const tileset = new InstancedOGC3DTile({
219
+ url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
220
+ //url: "http://localhost:8080/tileset.json",
221
+ geometricErrorMultiplier: 0.5,
222
+ loadOutsideView: false,
223
+ tileLoader: instancedTileLoader,
224
+ static: false,
225
+ });
226
+ tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 50*x)
227
+ tileset.translateOnAxis(new THREE.Vector3(0, 1, 0), 15*y)
228
+ tileset.translateOnAxis(new THREE.Vector3(0, 0, 1), 25*z)
229
+ scene.add(tileset);
230
+ instancedTilesets.push(tileset);
231
+
232
+ idleCallback();
233
+
234
+ function idleCallback(){
235
+ tileset.update(camera);
236
+ setTimeout(()=>{
237
+ window.requestIdleCallback(idleCallback,{timeout:50})
238
+ },20)
239
+
240
+ }
241
+ }
242
+ }
243
+ }
244
+
245
+ initLODMultiplierSlider(instancedTilesets);
246
+ }
247
+
248
+ function initLODMultiplierSlider(instancedTilesets) {
149
249
  var slider = document.getElementById("lodMultiplier");
150
250
  var output = document.getElementById("multiplierValue");
151
251
  output.innerHTML = slider.value;
152
252
 
153
253
  slider.oninput = () => {
154
- tileset.setGeometricErrorMultiplier(slider.value)
254
+ instancedTilesets.forEach(tileset=>{
255
+ tileset.setGeometricErrorMultiplier(slider.value)
256
+ })
155
257
  output.innerHTML = slider.value;
156
258
  }
157
259
  }
@@ -160,8 +262,8 @@ function initController(camera, dom) {
160
262
  const controller = new OrbitControls(camera, dom);
161
263
 
162
264
  controller.target.set(0, 0, 0);
163
- controller.minDistance = 1;
164
- controller.maxDistance = 5000;
265
+ controller.minDistance = 0.01;
266
+ controller.maxDistance = 100000;
165
267
  controller.update();
166
268
  return controller;
167
269
  }
@@ -169,13 +271,13 @@ function initController(camera, dom) {
169
271
 
170
272
  function animate() {
171
273
  requestAnimationFrame(animate);
172
- renderer.render(scene, camera);
173
- occlusionCullingService.update(scene, renderer, camera)
274
+ instancedTileLoader.update();
275
+ composer.render();
276
+ //occlusionCullingService.update(scene, renderer, camera)
174
277
  stats.update();
175
-
176
-
177
278
  }
178
279
 
179
280
 
180
281
 
181
282
 
283
+
@@ -76,14 +76,14 @@ class OGC3DTile extends THREE.Object3D {
76
76
  this.hasMeshContent = false; // true when the provided json has a content field pointing to a B3DM file
77
77
  this.hasUnloadedJSONContent = false; // true when the provided json has a content field pointing to a JSON file that is not yet loaded
78
78
 
79
+ this.abortController = new AbortController();
79
80
  this.layers.disable(0);
80
81
 
81
82
  if (!!properties.json) { // If this tile is created as a child of another tile, properties.json is not null
82
83
  self.setup(properties);
83
84
  if (properties.onLoadCallback) properties.onLoadCallback(self);
84
85
  } else if (properties.url) { // If only the url to the tileset.json is provided
85
- self.controller = new AbortController();
86
- fetch(properties.url, { signal: self.controller.signal }).then(result => {
86
+ fetch(properties.url, { signal: self.abortController.signal }).then(result => {
87
87
  if (!result.ok) {
88
88
  throw new Error(`couldn't load "${properties.url}". Request failed with status ${result.status} : ${result.statusText}`);
89
89
  }
@@ -176,7 +176,7 @@ class OGC3DTile extends THREE.Object3D {
176
176
  if (!!url) {
177
177
  if (url.includes(".b3dm")) {
178
178
  self.contentURL = url;
179
- self.tileLoader.get(this.uuid, url, mesh => {
179
+ self.tileLoader.get(self.abortController,this.uuid, url, mesh => {
180
180
  if (!!self.deleted) return;
181
181
  mesh.traverse((o) => {
182
182
  if (o.isMesh) {
@@ -192,7 +192,7 @@ class OGC3DTile extends THREE.Object3D {
192
192
  if(self.static){
193
193
  o.matrixAutoUpdate = false;
194
194
  }
195
- o.material.visible = false;
195
+ //o.material.visible = false;
196
196
  }
197
197
  });
198
198
 
@@ -204,7 +204,7 @@ class OGC3DTile extends THREE.Object3D {
204
204
  return self.calculateDistanceToCamera(self.cameraOnLoad);
205
205
  }, () => self.getSiblings(), self.level);
206
206
  } else if (url.includes(".json")) {
207
- self.tileLoader.get(this.uuid, url, json => {
207
+ self.tileLoader.get(self.abortController,this.uuid, url, json => {
208
208
  if (!!self.deleted) return;
209
209
  if (!self.json.children) self.json.children = [];
210
210
  json.rootPath = path.dirname(url);
@@ -228,8 +228,8 @@ class OGC3DTile extends THREE.Object3D {
228
228
  if (!!element.contentURL) {
229
229
  self.tileLoader.invalidate(element.contentURL, element.uuid);
230
230
  }
231
- if (!!element.controller) { // abort tile request
232
- element.controller.abort();
231
+ if (!!element.abortController) { // abort tile request
232
+ element.abortController.abort();
233
233
  }
234
234
 
235
235
  });
@@ -450,7 +450,7 @@ class OGC3DTile extends THREE.Object3D {
450
450
  return true;
451
451
  }
452
452
 
453
- return true;
453
+ return false;
454
454
 
455
455
  }
456
456