@jdultra/threedtiles 4.0.3 → 4.0.4

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
@@ -177,10 +177,60 @@ occlusionCullingService.setSide(THREE.DoubleSide);
177
177
  ```
178
178
 
179
179
  ### Instanced Tilesets
180
+
181
+ <p align="center">
182
+ <img src="https://storage.googleapis.com/jdultra-website/assets/instancedPic.png" width="800" style="display: block; margin: 0 auto"/>
183
+ </p>
184
+
180
185
  Using InstancedTileLoader and InstancedOGC3DTile allows displaying the same Tileset at many different places with little impact on performance.
181
186
  Each Tileset is independent in terms of it's position, orientation and level of detail but each tile is created as an "InstancedMesh" giving much
182
187
  higher performance when displaying the same Tileset many times.
183
188
 
189
+ ```
190
+ // First create the InstancedTileLoader that will manage caching
191
+ const instancedTileLoader = new InstancedTileLoader(scene, mesh => {
192
+ //// Insert code to be called on every newly decoded mesh e.g.:
193
+ mesh.material.wireframe = false;
194
+ mesh.material.side = THREE.DoubleSide;
195
+ },
196
+ 1000, // cache size as in the number of tiles cached in memory
197
+ 100, // max number of tilesets from the same source
198
+ );
199
+
200
+ // then create some tilesets
201
+ const instancedTilesets = [];
202
+ for (let i = 0; i < 100; i++) {
203
+ const tileset = new InstancedOGC3DTile({
204
+ url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
205
+ geometricErrorMultiplier: 1.0,
206
+ loadOutsideView: false,
207
+ tileLoader: instancedTileLoader,
208
+ static: true // when static is set to true, don't forget to call InstancedOGC3DTile#updateMatrix manually
209
+ });
210
+
211
+ tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 50 * i);
212
+ tileset.updateMatrix();
213
+ scene.add(tileset);
214
+ instancedTilesets.push(tileset);
215
+ }
216
+
217
+ //setup an update loop for the LODs
218
+ setInterval(() => {
219
+ instancedTilesets[updateIndex].update(camera);
220
+ updateIndex= (updateIndex+1)%instancedTilesets.length;
221
+ },50);
222
+
223
+ //in the animate function, you also need to update the instancedTileLoader
224
+ function animate() {
225
+ requestAnimationFrame(animate);
226
+ instancedTileLoader.update();
227
+
228
+ ... // rest of render loop
229
+ }
230
+ animate();
231
+
232
+ ```
233
+
184
234
  ### static tilesets and other performance tips
185
235
  When you know your tileset will be static, you can specify it in the OGC3DTile object constructor parameter.
186
236
  This will skip recalculating the transformation matrix of every tile each frame and give a few extra frames per second.
@@ -192,16 +242,50 @@ const ogc3DTile = new OGC3DTile({
192
242
  });
193
243
  ```
194
244
 
195
- 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.
245
+ Either way, it's advised to set the autoUpdate property of the scene to false and call Scene#updateMatrixWorld manually whenever you move things around.
246
+
247
+ ```
248
+ scene.matrixAutoUpdate = false;
249
+ scene.matrixWorldAutoUpdate = false;
250
+
251
+ // and when objects move:
252
+ scene.updateMatrixWorld(true);
196
253
 
197
254
  ```
198
- scene.autoUpdate = false;
255
+ #### tileset update loop
256
+ Updating a single tileset via OGC3DTile#update or InstancedOGC3DTile#update is quite fast, even when the tree is deep.
257
+ For a single tileset, it's safe to call it regularly with a setInterval:
258
+ ```
259
+ function startInterval() {
260
+ interval = setIntervalAsync(function () {
261
+ ogc3DTile.update(camera);
262
+ }, 20);
263
+ }
199
264
  ```
200
265
 
266
+ However, with instancedTilesets, you may have hundreds or even thousands of LOD trees that need to be updated individually. In order to preserve frame-rate,
267
+ you may want to implement something a little smarter that yields the CPU to the render loop. In the example below, the process tries to update as many tilesets as it can in under 4 ms.
268
+
269
+ ```
270
+ function now() {
271
+ return (typeof performance === 'undefined' ? Date : performance).now();
272
+ }
273
+ let updateIndex = 0;
274
+ setInterval(() => {
275
+ let startTime = now();
276
+ do{
277
+ instancedTilesets[updateIndex].update(camera);
278
+ updateIndex= (updateIndex+1)%instancedTilesets.length;
279
+ }while(updateIndex < instancedTilesets.length && now()-startTime<4);
280
+ },50);
281
+ ```
282
+
283
+ window#requestIdleCallback is also a good option but the rate of updates becomes slightly unpredictable.
284
+
201
285
  # Projects that use this library
202
286
  https://github.com/ebeaufay/UltraGlobe allows displaying a globe with multi resolution imagery, elevation and 3DTiles.
203
287
 
204
- 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.
288
+ 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.
205
289
  Contact: emeric.beaufays@jdultra.com
206
290
 
207
291
 
@@ -209,5 +293,5 @@ Contact: emeric.beaufays@jdultra.com
209
293
 
210
294
  I also have code to convert meshes to 3DTiles with no limit to the size of the dataset relative to faces or textures.
211
295
  It works for all types of meshes: photogrametry, BIM, colored or textured meshes with a single texture atlas or many individual textures.
212
- I'm keeping the code private for now but feel free to contact me about it.
296
+ The code is not open source but feel free to contact me for a trial.
213
297
  Contact: emeric.beaufays@jdultra.com
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jdultra/threedtiles",
3
- "version": "4.0.3",
3
+ "version": "4.0.4",
4
4
  "description": "An OGC 3DTiles viewer for Three.js",
5
5
  "main": "tileset.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -69,6 +69,7 @@ function initComposer(scene, camera, renderer) {
69
69
  function initScene() {
70
70
  const scene = new THREE.Scene();
71
71
  scene.matrixAutoUpdate = false;
72
+ scene.matrixWorldAutoUpdate = false;
72
73
  scene.background = new THREE.Color(0x000000);
73
74
  scene.add(new THREE.AmbientLight(0xFFFFFF, 1.0));
74
75
 
@@ -85,7 +86,7 @@ function initScene() {
85
86
  scene.add(light2);
86
87
  light2.position.set(200, 100, -100);*/
87
88
 
88
- scene.matrixWorldAutoUpdate = true;
89
+
89
90
  return scene;
90
91
  }
91
92
 
@@ -209,28 +210,29 @@ function createInstancedTileLoader(scene) {
209
210
  //// Insert code to be called on every newly decoded mesh e.g.:
210
211
  mesh.material.wireframe = false;
211
212
  mesh.material.side = THREE.DoubleSide;
212
- }, 1000, 125);
213
+ }, 1000, 3375);
213
214
  }
214
215
  function initInstancedTilesets(instancedTileLoader) {
215
216
 
216
217
  const instancedTilesets = [];
217
218
 
218
- for (let x = 0; x < 5; x++) {
219
- for (let y = 0; y < 5; y++) {
220
- for (let z = 0; z < 5; z++) {
219
+ for (let x = 0; x < 15; x++) {
220
+ for (let y = 0; y < 15; y++) {
221
+ for (let z = 0; z < 15; z++) {
221
222
  const tileset = new InstancedOGC3DTile({
222
- //url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
223
- url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
223
+ url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
224
+ //url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
224
225
  //url: "http://localhost:8080/tileset.json",
225
- geometricErrorMultiplier: 0.001,
226
+ geometricErrorMultiplier: 1.0,
226
227
  loadOutsideView: true,
227
228
  tileLoader: instancedTileLoader,
228
- static: false,
229
+ static: true,
229
230
  });
230
- tileset.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
231
- tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 3500 * x)
232
- tileset.translateOnAxis(new THREE.Vector3(0, 1, 0), 3500 * y)
233
- //tileset.translateOnAxis(new THREE.Vector3(0, 0, 1), 50 * z)
231
+ //tileset.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
232
+ tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 50 * x)
233
+ tileset.translateOnAxis(new THREE.Vector3(0, 1, 0), 50 * y)
234
+ tileset.translateOnAxis(new THREE.Vector3(0, 0, 1), 50 * z)
235
+ tileset.updateMatrix()
234
236
  scene.add(tileset);
235
237
  instancedTilesets.push(tileset);
236
238
 
@@ -238,17 +240,21 @@ function initInstancedTilesets(instancedTileLoader) {
238
240
  }
239
241
  }
240
242
  }
243
+
244
+ scene.updateMatrixWorld(true)
241
245
  function now() {
242
- return (typeof performance === 'undefined' ? Date : performance).now(); // see #10732
246
+ return (typeof performance === 'undefined' ? Date : performance).now();
243
247
  }
244
248
  let updateIndex = 0;
245
249
  setInterval(() => {
246
250
  let startTime = now();
247
251
  do{
248
- instancedTilesets[updateIndex].update(camera);
252
+ const frustum = new THREE.Frustum();
253
+ frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
254
+ instancedTilesets[updateIndex].update(camera, frustum);
249
255
  updateIndex= (updateIndex+1)%instancedTilesets.length;
250
256
  }while(updateIndex < instancedTilesets.length && now()-startTime<4);
251
- },50);
257
+ },40);
252
258
 
253
259
  //initLODMultiplierSlider(instancedTilesets);
254
260
  }
@@ -32,9 +32,17 @@ class InstancedOGC3DTile extends THREE.Object3D {
32
32
  }
33
33
  }
34
34
 
35
- update(camera){
36
- const frustum = new THREE.Frustum();
37
- frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
35
+ update(camera, frustum){
36
+ if(!!frustum){
37
+ this.tileset._update(camera, frustum);
38
+ }else{
39
+ const frustum = new THREE.Frustum();
40
+ frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
41
+ this.tileset._update(camera, frustum);
42
+ }
43
+
44
+ }
45
+ updateWithFrustum(camera, frustum){
38
46
  this.tileset._update(camera, frustum);
39
47
  }
40
48
 
@@ -23,8 +23,7 @@ class InstancedTile extends THREE.Object3D {
23
23
  * meshCallback: function,
24
24
  * cameraOnLoad: camera,
25
25
  * parentTile: OGC3DTile,
26
- * onLoadCallback: function,
27
- * static: Boolean
26
+ * onLoadCallback: function
28
27
  * } properties
29
28
  */
30
29
  constructor(properties) {
@@ -333,7 +332,6 @@ class InstancedTile extends THREE.Object3D {
333
332
  level: self.level + 1,
334
333
  tileLoader: self.tileLoader,
335
334
  cameraOnLoad: camera,
336
- static: self.static,
337
335
  master: self.master
338
336
  });
339
337
  self.childrenTiles.push(childTile);