@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.
@@ -26,12 +26,6 @@ class TileLoader {
26
26
  const self = this;
27
27
  setIntervalAsync(() => {
28
28
  self.download();
29
- /* const start = Date.now();
30
- let uploaded = 0;
31
- do{
32
- uploaded = download();
33
- }while(uploaded > 0 && (Date.now() - start)<= 2 ) */
34
-
35
29
  }, 10);
36
30
  setIntervalAsync(() => {
37
31
  const start = Date.now();
@@ -57,9 +51,6 @@ class TileLoader {
57
51
  nextDownload.doDownload();
58
52
  }
59
53
  }
60
-
61
-
62
-
63
54
  return;
64
55
  }
65
56
  meshReceived(cache, register, key, distanceFunction, getSiblings, level, uuid) {
@@ -76,11 +67,7 @@ class TileLoader {
76
67
  const register = data[1];
77
68
  const key = data[2];
78
69
  const mesh = cache.get(key);
79
- if(mesh instanceof THREE.InstancedMesh){
80
- console.log("instanced");
81
- }else{
82
- console.log(" not instanced");
83
- }
70
+
84
71
  if (!!mesh && !!register[key]) {
85
72
  Object.keys(register[key]).forEach(tile => {
86
73
  const callback = register[key][tile];
@@ -164,10 +151,16 @@ class TileLoader {
164
151
  }
165
152
 
166
153
 
167
- get(tileIdentifier, path, callback, distanceFunction, getSiblings, level) {
154
+ get(abortController, tileIdentifier, path, callback, distanceFunction, getSiblings, level) {
168
155
  const self = this;
169
156
  const key = simplifyPath(path);
170
157
 
158
+ const realAbortController = new AbortController();
159
+ abortController.signal.addEventListener("abort", ()=>{
160
+ if(!self.register[key] || Object.keys(self.register[key]).length == 0){
161
+ realAbortController.abort();
162
+ }
163
+ })
171
164
 
172
165
  if (!path.includes(".b3dm") && !path.includes(".json")) {
173
166
  console.error("the 3DTiles cache can only be used to load B3DM and json data");
@@ -189,40 +182,47 @@ class TileLoader {
189
182
  if (path.includes(".b3dm")) {
190
183
  downloadFunction = () => {
191
184
  concurentDownloads++;
192
- fetch(path).then(result => {
185
+ fetch(path, {signal: realAbortController.signal}).then(result => {
193
186
  concurentDownloads--;
194
187
  if (!result.ok) {
195
188
  console.error("could not load tile with path : " + path)
196
189
  throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
197
190
  }
198
- result.arrayBuffer().then(buffer => B3DMDecoder.parseB3DM(buffer, self.meshCallback)).then(mesh => {
199
- self.cache.put(key, mesh);
191
+ return result.arrayBuffer();
192
+
193
+ })
194
+ .then(resultArrayBuffer=>{
195
+ return B3DMDecoder.parseB3DM(resultArrayBuffer, self.meshCallback);
196
+ })
197
+ .then(mesh=>{
198
+ self.cache.put(key, mesh);
200
199
  self.checkSize();
201
200
  this.meshReceived(self.cache, self.register, key, distanceFunction, getSiblings, level, tileIdentifier);
202
- });
203
-
204
- });
201
+ })
202
+ .catch(()=>{});;
205
203
  }
206
204
  } else if (path.includes(".json")) {
207
205
  downloadFunction = () => {
208
206
  concurentDownloads++;
209
- fetch(path).then(result => {
207
+ fetch(path, {signal: realAbortController.signal}).then(result => {
210
208
  concurentDownloads--;
211
209
  if (!result.ok) {
212
210
  console.error("could not load tile with path : " + path)
213
211
  throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
214
212
  }
215
- result.json().then(json => {
216
- self.cache.put(key, json);
217
- self.checkSize();
218
- this.meshReceived(self.cache, self.register, key);
219
- });
220
- });
213
+ return result.json();
214
+
215
+ }).then(json => {
216
+ self.cache.put(key, json);
217
+ self.checkSize();
218
+ this.meshReceived(self.cache, self.register, key);
219
+ })
220
+ .catch(e=>console.error("tile download aborted"));
221
221
  }
222
222
  }
223
223
  this.scheduleDownload({
224
224
  "shouldDoDownload": () => {
225
- return !!self.register[key] && Object.keys(self.register[key]).length > 0;
225
+ return !abortController.signal.aborted && !!self.register[key] && Object.keys(self.register[key]).length > 0;
226
226
  },
227
227
  "doDownload": downloadFunction,
228
228
  "distanceFunction": distanceFunction,
@@ -0,0 +1,45 @@
1
+ import * as THREE from 'three';
2
+ import {InstancedTile} from "./InstancedTile.js"
3
+
4
+ class InstancedOGC3DTile extends THREE.Object3D {
5
+
6
+ /**
7
+ *
8
+ * @param {
9
+ * json: optional,
10
+ * url: optional,
11
+ * rootPath: optional,
12
+ * parentGeometricError: optional,
13
+ * parentBoundingVolume: optional,
14
+ * parentRefinement: optional,
15
+ * geometricErrorMultiplier: Double,
16
+ * loadOutsideView: Boolean,
17
+ * tileLoader : InstancedTileLoader,
18
+ * meshCallback: function,
19
+ * cameraOnLoad: camera,
20
+ * parentTile: OGC3DTile,
21
+ * onLoadCallback: function,
22
+ * static: Boolean
23
+ * } properties
24
+ */
25
+ constructor(properties) {
26
+ super();
27
+ properties.master = this;
28
+ this.geometricErrorMultiplier = properties.geometricErrorMultiplier? properties.geometricErrorMultiplier:1.0;
29
+ this.tileset = new InstancedTile(properties);
30
+ if (properties.static) {
31
+ this.matrixAutoUpdate = false;
32
+ }
33
+ }
34
+
35
+ update(camera){
36
+ const frustum = new THREE.Frustum();
37
+ frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
38
+ this.tileset._update(camera, frustum);
39
+ }
40
+
41
+ setGeometricErrorMultiplier(geometricErrorMultiplier) {
42
+ this.geometricErrorMultiplier = geometricErrorMultiplier?geometricErrorMultiplier:1.0;
43
+ }
44
+ }
45
+ export { InstancedOGC3DTile };
@@ -0,0 +1,510 @@
1
+ import * as THREE from 'three';
2
+ import { OBB } from "../../geometry/obb";
3
+ import { v4 as uuidv4 } from "uuid";
4
+ import * as path from "path-browserify";
5
+ import * as _ from "lodash";
6
+
7
+ const tempSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0, 1));
8
+
9
+
10
+ class InstancedTile extends THREE.Object3D {
11
+
12
+ /**
13
+ *
14
+ * @param {
15
+ * json: optional,
16
+ * url: optional,
17
+ * rootPath: optional,
18
+ * parentGeometricError: optional,
19
+ * parentBoundingVolume: optional,
20
+ * parentRefinement: optional,
21
+ * loadOutsideView: Boolean,
22
+ * tileLoader : InstancedTileLoader,
23
+ * meshCallback: function,
24
+ * cameraOnLoad: camera,
25
+ * parentTile: OGC3DTile,
26
+ * onLoadCallback: function,
27
+ * static: Boolean
28
+ * } properties
29
+ */
30
+ constructor(properties) {
31
+ super();
32
+ const self = this;
33
+
34
+ this.uuid = uuidv4();
35
+ if (!!properties.tileLoader) {
36
+ this.tileLoader = properties.tileLoader;
37
+ } else {
38
+ console.error("an instanced tileset must be provided an InstancedTilesetLoader");
39
+ }
40
+ // set properties general to the entire tileset
41
+ this.master = properties.master;
42
+ this.meshCallback = properties.meshCallback;
43
+ this.loadOutsideView = properties.loadOutsideView;
44
+ this.cameraOnLoad = properties.cameraOnLoad;
45
+ this.parentTile = properties.parentTile;
46
+
47
+ // declare properties specific to the tile for clarity
48
+ this.childrenTiles = [];
49
+ this.jsonChildren = [];
50
+ this.meshContent;
51
+
52
+ this.tileContent;
53
+ this.refinement; // defaults to "REPLACE"
54
+ this.rootPath;
55
+ this.geometricError;
56
+ this.boundingVolume;
57
+ this.json; // the json corresponding to this tile
58
+ this.materialVisibility = false;
59
+ this.inFrustum = true;
60
+ this.level = properties.level ? properties.level : 0;
61
+ this.hasMeshContent = false; // true when the provided json has a content field pointing to a B3DM file
62
+ this.hasUnloadedJSONContent = false; // true when the provided json has a content field pointing to a JSON file that is not yet loaded
63
+
64
+ this.deleted = false;
65
+ this.abortController = new AbortController();
66
+
67
+ if (!!properties.json) { // If this tile is created as a child of another tile, properties.json is not null
68
+ this.rootPath = !!properties.json.rootPath ? properties.json.rootPath : properties.rootPath;
69
+ if(properties.json.children) this.jsonChildren = properties.json.children;
70
+ self.setup(properties);
71
+ if (properties.onLoadCallback) properties.onLoadCallback(self);
72
+ } else if (properties.url) { // If only the url to the tileset.json is provided
73
+
74
+
75
+ this.loadJson = (json, url)=>{
76
+ //json = _.cloneDeep(json)
77
+ //json = JSON.parse(JSON.stringify(json))
78
+ const p = path.dirname(url);
79
+ self.setup({ rootPath: p, json: json });
80
+ if (properties.onLoadCallback) properties.onLoadCallback(self);
81
+ }
82
+ self.tileLoader.get(self.abortController, properties.url, self.uuid, self);
83
+
84
+ /* fetch(properties.url, { signal: self.abortController.signal }).then(result => {
85
+ if (!result.ok) {
86
+ throw new Error(`couldn't load "${properties.url}". Request failed with status ${result.status} : ${result.statusText}`);
87
+ }
88
+ result.json().then(json => {
89
+ const p = path.dirname(properties.url);
90
+ self.setup({ rootPath: p, json: json });
91
+ if (properties.onLoadCallback) properties.onLoadCallback(self);
92
+ });
93
+ }); */
94
+ }
95
+ }
96
+
97
+ setup(properties) {
98
+ this.isSetup = true;
99
+ if (!!properties.json.root) {
100
+ this.json = properties.json.root;
101
+ this.jsonChildren = this.json.children;
102
+ if (!this.json.refinement) this.json.refinement = properties.json.refinement;
103
+ if (!this.json.geometricError) this.json.geometricError = properties.json.geometricError;
104
+ if (!this.json.transform) this.json.transform = properties.json.transform;
105
+ if (!this.json.boundingVolume) this.json.boundingVolume = properties.json.boundingVolume;
106
+ } else {
107
+ this.json = properties.json;
108
+ }
109
+
110
+ this.rootPath = !!properties.json.rootPath ? properties.json.rootPath : properties.rootPath;
111
+
112
+ // decode refinement
113
+ if (!!this.json.refinement) {
114
+ this.refinement = this.json.refinement;
115
+ } else {
116
+ this.refinement = properties.parentRefinement;
117
+ }
118
+ // decode geometric error
119
+ if (!!this.json.geometricError) {
120
+ this.geometricError = this.json.geometricError;
121
+ } else {
122
+ this.geometricError = properties.parentGeometricError;
123
+ }
124
+ // decode transform
125
+ if (!!this.json.transform) {
126
+ let mat = new THREE.Matrix4();
127
+ mat.elements = this.json.transform;
128
+ this.master.applyMatrix4(mat);
129
+ }
130
+ // decode volume
131
+ if (!!this.json.boundingVolume) {
132
+ if (!!this.json.boundingVolume.box) {
133
+ this.boundingVolume = new OBB(this.json.boundingVolume.box);
134
+ } else if (!!this.json.boundingVolume.region) {
135
+ const region = this.json.boundingVolume.region;
136
+ this.boundingVolume = new THREE.Box3(new THREE.Vector3(region[0], region[2], region[4]), new THREE.Vector3(region[1], region[3], region[5]));
137
+ } else if (!!this.json.boundingVolume.sphere) {
138
+ const sphere = this.json.boundingVolume.sphere;
139
+ this.boundingVolume = new THREE.Sphere(new THREE.Vector3(sphere[0], sphere[2], -sphere[1]), sphere[3]);
140
+ } else {
141
+ this.boundingVolume = properties.parentBoundingVolume;
142
+ }
143
+ } else {
144
+ this.boundingVolume = properties.parentBoundingVolume;
145
+ }
146
+
147
+ if (!!this.json.content) { //if there is a content, json or otherwise, schedule it to be loaded
148
+ if (!!this.json.content.uri && this.json.content.uri.includes("json")) {
149
+ this.hasUnloadedJSONContent = true;
150
+ } else if (!!this.json.content.url && this.json.content.url.includes("json")) {
151
+ this.hasUnloadedJSONContent = true;
152
+ } else {
153
+ this.hasMeshContent = true;
154
+ }
155
+ this.load();
156
+ //scheduleLoadTile(this);
157
+ }
158
+ }
159
+ load() {
160
+ var self = this;
161
+ if (self.deleted) return;
162
+ if (!!self.json.content) {
163
+ let url;
164
+ if (!!self.json.content.uri) {
165
+ if (path.isAbsolute(self.json.content.uri)) {
166
+ url = self.json.content.uri;
167
+ } else {
168
+ url = self.rootPath + path.sep + self.json.content.uri;
169
+ }
170
+ } else if (!!self.json.content.url) {
171
+ if (path.isAbsolute(self.json.content.url)) {
172
+ url = self.json.content.url;
173
+ } else {
174
+ url = self.rootPath + path.sep + self.json.content.url;
175
+ }
176
+ }
177
+
178
+ if (!!url) {
179
+ if (url.includes(".b3dm")) {
180
+ self.contentURL = url;
181
+
182
+ self.tileLoader.get(self.abortController, url, self.uuid, self, !self.cameraOnLoad ? () => 0 : () => {
183
+ return self.calculateDistanceToCamera(self.cameraOnLoad);
184
+ }, () => self.getSiblings(), self.level);
185
+ } else if (url.includes(".json")) {
186
+ self.tileLoader.get(self.abortController, url, self.uuid, self);
187
+
188
+ }
189
+
190
+ }
191
+ }
192
+ }
193
+
194
+ loadMesh(mesh) {
195
+ const self = this;
196
+ if (self.deleted) {
197
+ return;
198
+ }
199
+
200
+ //self.updateWorldMatrix(false, true);
201
+ self.meshContent = mesh;
202
+
203
+ }
204
+
205
+ loadJson(json, url) {
206
+ if (this.deleted) {
207
+ return;
208
+ }
209
+ if(!!this.json.children){
210
+ this.jsonChildren = this.json.children;
211
+ }
212
+
213
+ json.rootPath = path.dirname(url);
214
+ this.jsonChildren.push(json);
215
+ this.hasUnloadedJSONContent = false;
216
+ }
217
+
218
+ dispose() {
219
+
220
+ const self = this;
221
+ self.childrenTiles.forEach(tile => tile.dispose());
222
+ self.deleted = true;
223
+ if (self.abortController) self.abortController.abort();
224
+ this.parent = null;
225
+ this.parentTile = null;
226
+ this.dispatchEvent({ type: 'removed' });
227
+ }
228
+ disposeChildren() {
229
+ var self = this;
230
+
231
+ self.childrenTiles.forEach(tile => tile.dispose());
232
+ self.childrenTiles = [];
233
+ }
234
+
235
+
236
+ _update(camera, frustum) {
237
+ const self = this;
238
+ const visibilityBeforeUpdate = self.materialVisibility;
239
+
240
+ if (!!self.boundingVolume && !!self.geometricError) {
241
+ self.metric = self.calculateUpdateMetric(camera, frustum);
242
+ }
243
+ self.childrenTiles.forEach(child => child._update(camera, frustum));
244
+
245
+ updateNodeVisibility(self.metric);
246
+ updateTree(self.metric);
247
+ trimTree(self.metric, visibilityBeforeUpdate);
248
+
249
+
250
+ function updateTree(metric) {
251
+ // If this tile does not have mesh content but it has children
252
+ if (metric < 0 && self.hasMeshContent) return;
253
+
254
+ if ((!self.hasMeshContent && self.rootPath) || (metric < self.geometricError && !!self.meshContent)) {
255
+ if (!!self.json && !!self.jsonChildren && self.childrenTiles.length != self.jsonChildren.length) {
256
+ loadJsonChildren();
257
+ return;
258
+ }
259
+ }
260
+ }
261
+
262
+ function updateNodeVisibility(metric) {
263
+
264
+ //doesn't have a mesh content
265
+ if (!self.hasMeshContent) return;
266
+
267
+ // mesh content not yet loaded
268
+ if (!self.meshContent) {
269
+ return;
270
+ }
271
+
272
+ // outside frustum
273
+ if (metric < 0) {
274
+ self.inFrustum = false;
275
+ self.changeContentVisibility(!!self.loadOutsideView);
276
+ return;
277
+ } else {
278
+ self.inFrustum = true;
279
+ }
280
+
281
+ // has no children
282
+ if (self.childrenTiles.length == 0) {
283
+ self.changeContentVisibility(true);
284
+ return;
285
+ }
286
+
287
+ // has children
288
+ if (metric >= self.geometricError) { // Ideal LOD or before ideal lod
289
+
290
+ self.changeContentVisibility(true);
291
+ } else if (metric < self.geometricError) { // Ideal LOD is past this one
292
+ // if children are visible and have been displayed, can be hidden
293
+ let allChildrenReady = true;
294
+ self.childrenTiles.every(child => {
295
+
296
+ if (!child.isReady()) {
297
+ allChildrenReady = false;
298
+ return false;
299
+ }
300
+ return true;
301
+ });
302
+ if (allChildrenReady) {
303
+ self.changeContentVisibility(false);
304
+ }
305
+ }
306
+ }
307
+
308
+ function trimTree(metric, visibilityBeforeUpdate) {
309
+ if (!self.hasMeshContent) return;
310
+ if (!self.inFrustum) { // outside frustum
311
+ self.disposeChildren();
312
+ updateNodeVisibility(metric);
313
+ return;
314
+ }
315
+ if (metric >= self.geometricError) {
316
+ self.disposeChildren();
317
+ updateNodeVisibility();
318
+ return;
319
+ }
320
+
321
+ }
322
+
323
+ function loadJsonChildren() {
324
+ self.jsonChildren.forEach(childJSON => {
325
+ let childTile = new InstancedTile({
326
+ parentTile: self,
327
+ parentGeometricError: self.geometricError,
328
+ parentBoundingVolume: self.boundingVolume,
329
+ parentRefinement: self.refinement,
330
+ json: childJSON,
331
+ rootPath: self.rootPath,
332
+ loadOutsideView: self.loadOutsideView,
333
+ level: self.level + 1,
334
+ tileLoader: self.tileLoader,
335
+ cameraOnLoad: camera,
336
+ static: self.static,
337
+ master: self.master
338
+ });
339
+ self.childrenTiles.push(childTile);
340
+ //self.add(childTile);
341
+ });
342
+ }
343
+
344
+ }
345
+
346
+ areAllChildrenLoadedAndHidden() {
347
+ let allLoadedAndHidden = true;
348
+ const self = this;
349
+ this.childrenTiles.every(child => {
350
+ if (child.hasMeshContent) {
351
+ if (child.childrenTiles.length > 0) {
352
+ allLoadedAndHidden = false;
353
+ return false;
354
+ }
355
+ if (!child.inFrustum) {
356
+ return true;
357
+ };
358
+ if (!child.materialVisibility || child.meshesToDisplay != child.meshesDisplayed) {
359
+ allLoadedAndHidden = false;
360
+ return false;
361
+ }
362
+ } else {
363
+ if (!child.areAllChildrenLoadedAndHidden()) {
364
+ allLoadedAndHidden = false;
365
+ return false;
366
+ }
367
+ }
368
+ return true;
369
+ });
370
+ return allLoadedAndHidden;
371
+ }
372
+
373
+ /**
374
+ * Node is ready if it is outside frustum, if it was drawn at least once or if all it's children are ready
375
+ * @returns true if ready
376
+ */
377
+ isReady() {
378
+ // if outside frustum
379
+ if (!this.inFrustum) return true;
380
+
381
+ // if json is not done loading
382
+ if (this.hasUnloadedJSONContent) return false;
383
+
384
+ // if this tile has no mesh content or if it's marked as visible false, look at children
385
+ if ((!this.hasMeshContent || !this.meshContent || !this.materialVisibility) && this.childrenTiles.length > 0) {
386
+ var allChildrenReady = true;
387
+ this.childrenTiles.every(child => {
388
+ if (!child.isReady()) {
389
+ allChildrenReady = false;
390
+ return false;
391
+ }
392
+ return true;
393
+ });
394
+ return allChildrenReady;
395
+ }
396
+
397
+ // if this tile has no mesh content
398
+ if (!this.hasMeshContent) {
399
+ return true;
400
+ }
401
+ // if mesh content not yet loaded
402
+ if (!this.meshContent) {
403
+ return false;
404
+ }
405
+
406
+ // if this tile has been marked to hide it's content
407
+ if (!this.materialVisibility) {
408
+ return false;
409
+ }
410
+
411
+ // if all meshes have been displayed once
412
+ if (!this.meshContent.displayedOnce) {
413
+ return false;
414
+ }
415
+ return true;
416
+
417
+ }
418
+
419
+
420
+ changeContentVisibility(visibility) {
421
+ const self = this;
422
+ self.materialVisibility = visibility;
423
+
424
+ /* self.meshContent.displayedOnce = false;
425
+ if(visibility){
426
+ self.meshContent.onAfterRender = () => {
427
+ delete self.meshContent.onAfterRender;
428
+ self.meshContent.displayedOnce = true;
429
+ };
430
+ } */
431
+
432
+ }
433
+ calculateUpdateMetric(camera, frustum) {
434
+ ////// return -1 if not in frustum
435
+ if (this.boundingVolume instanceof OBB) {
436
+ // box
437
+ tempSphere.copy(this.boundingVolume.sphere);
438
+ tempSphere.applyMatrix4(this.master.matrixWorld);
439
+ if (!frustum.intersectsSphere(tempSphere)) return -1;
440
+ } else if (this.boundingVolume instanceof THREE.Sphere) {
441
+ //sphere
442
+ tempSphere.copy(this.boundingVolume);
443
+ tempSphere.applyMatrix4(this.master.matrixWorld);
444
+ if (!frustum.intersectsSphere(tempSphere)) return -1;
445
+ } else if (this.boundingVolume instanceof THREE.Box3) {
446
+ // Region
447
+ // Region not supported
448
+ //throw Error("Region bounding volume not supported");
449
+ return -1;
450
+ }
451
+
452
+ /////// return metric based on geometric error and distance
453
+ if (this.boundingVolume instanceof OBB || this.boundingVolume instanceof THREE.Sphere) {
454
+ // box
455
+ const distance = Math.max(0, camera.position.distanceTo(tempSphere.center) - tempSphere.radius);
456
+ if (distance == 0) {
457
+ return 0;
458
+ }
459
+ const scale = this.master.matrixWorld.getMaxScaleOnAxis();
460
+ return (((distance / Math.pow(scale, 2)) / 100) / this.master.geometricErrorMultiplier);
461
+ } else if (this.boundingVolume instanceof THREE.Box3) {
462
+ // Region
463
+ // Region not supported
464
+ //throw Error("Region bounding volume not supported");
465
+ return -1;
466
+ }
467
+ }
468
+
469
+ getSiblings() {
470
+ const self = this;
471
+ const tiles = [];
472
+ if (!self.parentTile) return tiles;
473
+ let p = self.parentTile;
474
+ while (!p.hasMeshContent && !!p.parentTile) {
475
+ p = p.parentTile;
476
+ }
477
+ p.childrenTiles.forEach(child => {
478
+ if (!!child && child != self) {
479
+ while (!child.hasMeshContent && !!child.childrenTiles[0]) {
480
+ child = child.childrenTiles[0];
481
+ }
482
+ tiles.push(child);
483
+ }
484
+ });
485
+ return tiles;
486
+ }
487
+ calculateDistanceToCamera(camera) {
488
+ if (this.boundingVolume instanceof OBB) {
489
+ // box
490
+ tempSphere.copy(this.boundingVolume.sphere);
491
+ tempSphere.applyMatrix4(this.master.matrixWorld);
492
+ //if (!frustum.intersectsSphere(tempSphere)) return -1;
493
+ } else if (this.boundingVolume instanceof THREE.Sphere) {
494
+ //sphere
495
+ tempSphere.copy(this.boundingVolume);
496
+ tempSphere.applyMatrix4(this.master.matrixWorld);
497
+ //if (!frustum.intersectsSphere(tempSphere)) return -1;
498
+ }
499
+ if (this.boundingVolume instanceof THREE.Box3) {
500
+ return -1; // region not supported
501
+ }
502
+ return Math.max(0, camera.position.distanceTo(tempSphere.center) - tempSphere.radius);
503
+ }
504
+
505
+ getWorldMatrix(){
506
+ const self = this;
507
+ return self.master.matrixWorld;
508
+ }
509
+ }
510
+ export { InstancedTile };