@jdultra/threedtiles 4.0.3 → 5.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
@@ -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": "5.0.0",
4
4
  "description": "An OGC 3DTiles viewer for Three.js",
5
5
  "main": "tileset.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -21,7 +21,9 @@ occlusionCullingService.setSide(THREE.DoubleSide);
21
21
  const scene = initScene();
22
22
 
23
23
  const domContainer = initDomContainer("screen");
24
- const camera = initCamera();
24
+ const camera = initCamera(domContainer.offsetWidth, domContainer.offsetHeight);
25
+ const stats = initStats(domContainer);
26
+ const renderer = initRenderer(camera, domContainer);
25
27
  //const ogc3DTiles = initTileset(scene);
26
28
 
27
29
 
@@ -30,8 +32,6 @@ initInstancedTilesets(instancedTileLoader);
30
32
 
31
33
  const controller = initController(camera, domContainer);
32
34
 
33
- const stats = initStats(domContainer);
34
- const renderer = initRenderer(camera, domContainer);
35
35
  const composer = initComposer(scene, camera, renderer);
36
36
 
37
37
 
@@ -69,7 +69,8 @@ function initComposer(scene, camera, renderer) {
69
69
  function initScene() {
70
70
  const scene = new THREE.Scene();
71
71
  scene.matrixAutoUpdate = false;
72
- scene.background = new THREE.Color(0x000000);
72
+ //scene.matrixWorldAutoUpdate = false;
73
+ scene.background = new THREE.Color(0x404040);
73
74
  scene.add(new THREE.AmbientLight(0xFFFFFF, 1.0));
74
75
 
75
76
  /*const light = new THREE.PointLight(0xbbbbff, 2, 5000);
@@ -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
 
@@ -131,9 +132,10 @@ function initStats(dom) {
131
132
  }
132
133
 
133
134
 
134
- function initCamera() {
135
- const camera = new THREE.PerspectiveCamera(70, window.offsetWidth / window.offsetHeight, 1.0, 100000);
136
- camera.position.set(-800, 800, 800);
135
+ function initCamera(width, height) {
136
+ const camera = new THREE.PerspectiveCamera(60, width / height, 1, 100000);
137
+ camera.position.set(-400.060421028462592,-14.561785966685625,700.123058268059668);
138
+
137
139
  camera.matrixAutoUpdate = true;
138
140
  return camera;
139
141
  }
@@ -144,17 +146,22 @@ function initTileset(scene) {
144
146
  //// Insert code to be called on every newly decoded mesh e.g.:
145
147
  mesh.material.wireframe = false;
146
148
  mesh.material.side = THREE.DoubleSide;
149
+ mesh.material.metalness = 0.0
147
150
  }, 1000)
148
151
  const ogc3DTile = new OGC3DTile({
149
152
  //url: "http://localhost:8080/tileset.json",
150
153
  //url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
151
154
  url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
152
155
  //url: "https://s3.eu-central-2.wasabisys.com/construkted-assets-eu/ands2ty8orz/tileset.json",
156
+ //url: "https://s3.eu-central-2.wasabisys.com/construkted-assets-eu/an7opcnyije/tileset.json",
157
+ //url: "https://s3.eu-central-2.wasabisys.com/construkted-assets-eu/ands2ty8orz/tileset.json",
158
+ //url: "https://s3.eu-central-2.wasabisys.com/construkted-assets-eu/a88b3sungng/tileset.json",
153
159
  geometricErrorMultiplier: 0.01,
154
160
  loadOutsideView: false,
155
161
  tileLoader: tileLoader,
156
162
  //occlusionCullingService: occlusionCullingService,
157
163
  static: false,
164
+ renderer: renderer
158
165
 
159
166
  });
160
167
 
@@ -163,7 +170,7 @@ function initTileset(scene) {
163
170
 
164
171
  //// The OGC3DTile object is a threejs Object3D so you may do all the usual opperations like transformations e.g.:
165
172
  ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
166
- //ogc3DTile.scale.set(10.0,10.0,10.0)
173
+ ogc3DTile.scale.set(100.0,100.0,100.0)
167
174
  //// If the OGC3DTile object is marked as "static" (constructorParameter), these operations will not work.
168
175
 
169
176
 
@@ -209,28 +216,30 @@ function createInstancedTileLoader(scene) {
209
216
  //// Insert code to be called on every newly decoded mesh e.g.:
210
217
  mesh.material.wireframe = false;
211
218
  mesh.material.side = THREE.DoubleSide;
212
- }, 1000, 125);
219
+ }, 1000, 3375);
213
220
  }
214
221
  function initInstancedTilesets(instancedTileLoader) {
215
222
 
216
223
  const instancedTilesets = [];
217
224
 
218
- for (let x = 0; x < 5; x++) {
219
- for (let y = 0; y < 5; y++) {
220
- for (let z = 0; z < 5; z++) {
225
+ for (let x = 0; x < 15; x++) {
226
+ for (let y = 0; y < 15; y++) {
227
+ for (let z = 0; z < 15; z++) {
221
228
  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",
229
+ url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
230
+ //url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
224
231
  //url: "http://localhost:8080/tileset.json",
225
- geometricErrorMultiplier: 0.001,
232
+ geometricErrorMultiplier: 1.0,
226
233
  loadOutsideView: true,
227
234
  tileLoader: instancedTileLoader,
228
- static: false,
235
+ static: true,
236
+ renderer: renderer
229
237
  });
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)
238
+ //tileset.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
239
+ tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 50 * x)
240
+ tileset.translateOnAxis(new THREE.Vector3(0, 1, 0), 50 * y)
241
+ tileset.translateOnAxis(new THREE.Vector3(0, 0, 1), 50 * z)
242
+ tileset.updateMatrix()
234
243
  scene.add(tileset);
235
244
  instancedTilesets.push(tileset);
236
245
 
@@ -238,17 +247,21 @@ function initInstancedTilesets(instancedTileLoader) {
238
247
  }
239
248
  }
240
249
  }
250
+
251
+ scene.updateMatrixWorld(true)
241
252
  function now() {
242
- return (typeof performance === 'undefined' ? Date : performance).now(); // see #10732
253
+ return (typeof performance === 'undefined' ? Date : performance).now();
243
254
  }
244
255
  let updateIndex = 0;
245
256
  setInterval(() => {
246
257
  let startTime = now();
247
258
  do{
248
- instancedTilesets[updateIndex].update(camera);
259
+ const frustum = new THREE.Frustum();
260
+ frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
261
+ instancedTilesets[updateIndex].update(camera, frustum);
249
262
  updateIndex= (updateIndex+1)%instancedTilesets.length;
250
263
  }while(updateIndex < instancedTilesets.length && now()-startTime<4);
251
- },50);
264
+ },40);
252
265
 
253
266
  //initLODMultiplierSlider(instancedTilesets);
254
267
  }
@@ -269,7 +282,7 @@ function initLODMultiplierSlider(instancedTilesets) {
269
282
  function initController(camera, dom) {
270
283
  const controller = new OrbitControls(camera, dom);
271
284
 
272
- controller.target.set(0, 0, 0);
285
+ controller.target.set(0,0,0);
273
286
  controller.minDistance = 0.01;
274
287
  controller.maxDistance = 100000;
275
288
  controller.update();
@@ -6,7 +6,7 @@ import * as path from "path-browserify"
6
6
  import { clamp } from "three/src/math/MathUtils";
7
7
 
8
8
  const tempSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0, 1));
9
-
9
+ const rendererSize = new THREE.Vector2();
10
10
 
11
11
  class OGC3DTile extends THREE.Object3D {
12
12
 
@@ -27,7 +27,8 @@ class OGC3DTile extends THREE.Object3D {
27
27
  * parentTile: OGC3DTile,
28
28
  * onLoadCallback: function,
29
29
  * occlusionCullingService: OcclusionCullingService,
30
- * static: Boolean
30
+ * static: Boolean,
31
+ * renderer: Renderer
31
32
  * } properties
32
33
  */
33
34
  constructor(properties) {
@@ -43,10 +44,11 @@ class OGC3DTile extends THREE.Object3D {
43
44
  mesh.material.wireframe = false;
44
45
  mesh.material.side = THREE.DoubleSide;
45
46
  } : properties.meshCallback);
46
- }
47
- // set properties general to the entire tileset
48
- this.geometricErrorMultiplier = !!properties.geometricErrorMultiplier ? properties.geometricErrorMultiplier : 1.0;
49
-
47
+ }
48
+ // set properties general to the entire tileset
49
+ this.geometricErrorMultiplier = !!properties.geometricErrorMultiplier ? properties.geometricErrorMultiplier : 1.0;
50
+
51
+ this.renderer = properties.renderer;
50
52
  this.meshCallback = properties.meshCallback;
51
53
  this.loadOutsideView = properties.loadOutsideView;
52
54
  this.cameraOnLoad = properties.cameraOnLoad;
@@ -58,7 +60,7 @@ class OGC3DTile extends THREE.Object3D {
58
60
  this.color.setHex(Math.random() * 0xffffff);
59
61
  this.colorID = clamp(self.color.r * 255, 0, 255) << 16 ^ clamp(self.color.g * 255, 0, 255) << 8 ^ clamp(self.color.b * 255, 0, 255) << 0;
60
62
  }
61
- if(this.static){
63
+ if (this.static) {
62
64
  this.matrixAutoUpdate = false;
63
65
  }
64
66
  // declare properties specific to the tile for clarity
@@ -176,7 +178,7 @@ class OGC3DTile extends THREE.Object3D {
176
178
  if (!!url) {
177
179
  if (url.includes(".b3dm")) {
178
180
  self.contentURL = url;
179
- self.tileLoader.get(self.abortController,this.uuid, url, mesh => {
181
+ self.tileLoader.get(self.abortController, this.uuid, url, mesh => {
180
182
  if (!!self.deleted) return;
181
183
  mesh.traverse((o) => {
182
184
  if (o.isMesh) {
@@ -189,13 +191,13 @@ class OGC3DTile extends THREE.Object3D {
189
191
  }
190
192
  o.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
191
193
  }
192
- if(self.static){
194
+ if (self.static) {
193
195
  o.matrixAutoUpdate = false;
194
196
  }
195
197
  //o.material.visible = false;
196
198
  }
197
199
  });
198
-
200
+
199
201
  self.add(mesh);
200
202
  self.updateWorldMatrix(false, true);
201
203
  // mesh.layers.disable(0);
@@ -204,7 +206,7 @@ class OGC3DTile extends THREE.Object3D {
204
206
  return self.calculateDistanceToCamera(self.cameraOnLoad);
205
207
  }, () => self.getSiblings(), self.level);
206
208
  } else if (url.includes(".json")) {
207
- self.tileLoader.get(self.abortController,this.uuid, url, json => {
209
+ self.tileLoader.get(self.abortController, this.uuid, url, json => {
208
210
  if (!!self.deleted) return;
209
211
  if (!self.json.children) self.json.children = [];
210
212
  json.rootPath = path.dirname(url);
@@ -273,7 +275,7 @@ class OGC3DTile extends THREE.Object3D {
273
275
  if (self.occlusionCullingService && self.hasMeshContent && !self.occlusionCullingService.hasID(self.colorID)) {
274
276
  return;
275
277
  }
276
- if (!self.hasMeshContent || (metric < self.geometricError && !!self.meshContent)) {
278
+ if (!self.hasMeshContent || (metric < self.geometricErrorMultiplier * self.geometricError && !!self.meshContent)) {
277
279
  if (!!self.json && !!self.json.children && self.childrenTiles.length != self.json.children.length) {
278
280
  loadJsonChildren();
279
281
  return;
@@ -307,10 +309,10 @@ class OGC3DTile extends THREE.Object3D {
307
309
  }
308
310
 
309
311
  // has children
310
- if (metric >= self.geometricError) { // Ideal LOD or before ideal lod
312
+ if (metric >= self.geometricErrorMultiplier * self.geometricError) { // Ideal LOD or before ideal lod
311
313
 
312
314
  self.changeContentVisibility(true);
313
- } else if (metric < self.geometricError) { // Ideal LOD is past this one
315
+ } else if (metric < self.geometricErrorMultiplier * self.geometricError) { // Ideal LOD is past this one
314
316
  // if children are visible and have been displayed, can be hidden
315
317
  let allChildrenReady = true;
316
318
  self.childrenTiles.every(child => {
@@ -345,7 +347,7 @@ class OGC3DTile extends THREE.Object3D {
345
347
  updateNodeVisibility(metric);
346
348
  return;
347
349
  }
348
- if (metric >= self.geometricError) {
350
+ if (metric >= self.geometricErrorMultiplier * self.geometricError) {
349
351
  self.disposeChildren();
350
352
  updateNodeVisibility();
351
353
  return;
@@ -367,7 +369,8 @@ class OGC3DTile extends THREE.Object3D {
367
369
  level: self.level + 1,
368
370
  tileLoader: self.tileLoader,
369
371
  cameraOnLoad: camera,
370
- occlusionCullingService:self.occlusionCullingService,
372
+ occlusionCullingService: self.occlusionCullingService,
373
+ renderer: self.renderer,
371
374
  static: self.static
372
375
  });
373
376
  self.childrenTiles.push(childTile);
@@ -382,11 +385,11 @@ class OGC3DTile extends THREE.Object3D {
382
385
  const self = this;
383
386
  this.childrenTiles.every(child => {
384
387
  if (child.hasMeshContent) {
385
- if(child.childrenTiles.length>0){
388
+ if (child.childrenTiles.length > 0) {
386
389
  allLoadedAndHidden = false;
387
390
  return false;
388
391
  }
389
- if (!child.inFrustum ) {
392
+ if (!child.inFrustum) {
390
393
  return true;
391
394
  };
392
395
  if (!child.materialVisibility || child.meshesToDisplay != child.meshesDisplayed) {
@@ -459,15 +462,15 @@ class OGC3DTile extends THREE.Object3D {
459
462
 
460
463
  changeContentVisibility(visibility) {
461
464
  const self = this;
462
- if(self.hasMeshContent && self.meshContent){
463
- if(visibility){
464
-
465
+ if (self.hasMeshContent && self.meshContent) {
466
+ if (visibility) {
467
+
465
468
  self.meshContent.traverse((o) => {
466
469
  if (o.isMesh) {
467
470
  o.layers.enable(0);
468
471
  }
469
472
  });
470
- }else{
473
+ } else {
471
474
  self.meshContent.traverse((o) => {
472
475
  if (o.isMesh) {
473
476
  o.layers.disable(0);
@@ -530,8 +533,18 @@ class OGC3DTile extends THREE.Object3D {
530
533
  return 0;
531
534
  }
532
535
  const scale = this.matrixWorld.getMaxScaleOnAxis();
533
- return Math.pow(distance, 2) /(this.geometricErrorMultiplier*this.geometricError*Math.pow(scale,2.0)*35);
534
- //return (((distance / Math.pow(scale, 2)) / 100) / this.geometricErrorMultiplier);
536
+ this.renderer.getDrawingBufferSize(rendererSize);
537
+ let s = rendererSize.y;
538
+ let fov = camera.fov;
539
+ if(camera.aspect < 1){
540
+ fov *= camera.aspect;
541
+ s = rendererSize.x;
542
+ }
543
+
544
+ let lambda = 2.0 * Math.tan(0.5 * fov * 0.01745329251994329576923690768489) * distance;
545
+
546
+ return (window.devicePixelRatio * 16 * lambda) / (s * scale);
547
+
535
548
  } else if (this.boundingVolume instanceof THREE.Box3) {
536
549
  // Region
537
550
  // Region not supported
@@ -19,12 +19,14 @@ class InstancedOGC3DTile extends THREE.Object3D {
19
19
  * cameraOnLoad: camera,
20
20
  * parentTile: OGC3DTile,
21
21
  * onLoadCallback: function,
22
+ * renderer: Renderer
22
23
  * static: Boolean
23
24
  * } properties
24
25
  */
25
26
  constructor(properties) {
26
27
  super();
27
28
  properties.master = this;
29
+ this.renderer = properties.renderer;
28
30
  this.geometricErrorMultiplier = properties.geometricErrorMultiplier? properties.geometricErrorMultiplier:1.0;
29
31
  this.tileset = new InstancedTile(properties);
30
32
  if (properties.static) {
@@ -32,9 +34,17 @@ class InstancedOGC3DTile extends THREE.Object3D {
32
34
  }
33
35
  }
34
36
 
35
- update(camera){
36
- const frustum = new THREE.Frustum();
37
- frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
37
+ update(camera, frustum){
38
+ if(!!frustum){
39
+ this.tileset._update(camera, frustum);
40
+ }else{
41
+ const frustum = new THREE.Frustum();
42
+ frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
43
+ this.tileset._update(camera, frustum);
44
+ }
45
+
46
+ }
47
+ updateWithFrustum(camera, frustum){
38
48
  this.tileset._update(camera, frustum);
39
49
  }
40
50
 
@@ -5,7 +5,7 @@ import * as path from "path-browserify";
5
5
  import * as _ from "lodash";
6
6
 
7
7
  const tempSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0, 1));
8
-
8
+ const rendererSize = new THREE.Vector2();
9
9
 
10
10
  class InstancedTile extends THREE.Object3D {
11
11
 
@@ -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) {
@@ -251,7 +250,7 @@ class InstancedTile extends THREE.Object3D {
251
250
  // If this tile does not have mesh content but it has children
252
251
  if (metric < 0 && self.hasMeshContent) return;
253
252
 
254
- if ((!self.hasMeshContent && self.rootPath) || (metric < self.geometricError && !!self.meshContent)) {
253
+ if ((!self.hasMeshContent && self.rootPath) || (metric < self.master.geometricErrorMultiplier * self.geometricError && !!self.meshContent)) {
255
254
  if (!!self.json && !!self.jsonChildren && self.childrenTiles.length != self.jsonChildren.length) {
256
255
  loadJsonChildren();
257
256
  return;
@@ -285,10 +284,10 @@ class InstancedTile extends THREE.Object3D {
285
284
  }
286
285
 
287
286
  // has children
288
- if (metric >= self.geometricError) { // Ideal LOD or before ideal lod
287
+ if (metric >= self.master.geometricErrorMultiplier * self.geometricError) { // Ideal LOD or before ideal lod
289
288
 
290
289
  self.changeContentVisibility(true);
291
- } else if (metric < self.geometricError) { // Ideal LOD is past this one
290
+ } else if (metric < self.master.geometricErrorMultiplier * self.geometricError) { // Ideal LOD is past this one
292
291
  // if children are visible and have been displayed, can be hidden
293
292
  let allChildrenReady = true;
294
293
  self.childrenTiles.every(child => {
@@ -312,7 +311,7 @@ class InstancedTile extends THREE.Object3D {
312
311
  updateNodeVisibility(metric);
313
312
  return;
314
313
  }
315
- if (metric >= self.geometricError) {
314
+ if (metric >= self.master.geometricErrorMultiplier * self.geometricError) {
316
315
  self.disposeChildren();
317
316
  updateNodeVisibility();
318
317
  return;
@@ -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);
@@ -457,8 +455,18 @@ class InstancedTile extends THREE.Object3D {
457
455
  return 0;
458
456
  }
459
457
  const scale = this.master.matrixWorld.getMaxScaleOnAxis();
460
- //return (((distance / Math.pow(scale, 2)) / 100) / this.master.geometricErrorMultiplier);
461
- return Math.pow(distance, 2) /(this.master.geometricErrorMultiplier*this.geometricError*Math.pow(scale,2.0)*35);
458
+
459
+ this.master.renderer.getDrawingBufferSize(rendererSize);
460
+ let s = rendererSize.y;
461
+ let fov = camera.fov;
462
+ if(camera.aspect < 1){
463
+ fov *= camera.aspect;
464
+ s = rendererSize.x;
465
+ }
466
+
467
+ let lambda = 2.0 * Math.tan(0.5 * fov * 0.01745329251994329576923690768489) * distance;
468
+
469
+ return (window.devicePixelRatio * 16 * lambda) / (s * scale);
462
470
  } else if (this.boundingVolume instanceof THREE.Box3) {
463
471
  // Region
464
472
  // Region not supported