@loaders.gl/tiles 5.0.0-alpha.1 → 5.0.0-alpha.3
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/LICENSE +14 -3
- package/dist/dist.dev.js +17482 -3685
- package/dist/dist.min.js +4 -1
- package/dist/index.cjs +4594 -422
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +16 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/point-cloud/point-cloud-tile.d.ts.map +1 -1
- package/dist/point-cloud/point-cloud-tile.js +3 -0
- package/dist/point-cloud/point-cloud-tile.js.map +1 -1
- package/dist/point-cloud/point-cloud-tileset.d.ts +4 -0
- package/dist/point-cloud/point-cloud-tileset.d.ts.map +1 -1
- package/dist/point-cloud/point-cloud-tileset.js +54 -12
- package/dist/point-cloud/point-cloud-tileset.js.map +1 -1
- package/dist/point-cloud/types.d.ts +17 -0
- package/dist/point-cloud/types.d.ts.map +1 -1
- package/dist/point-cloud/types.js +3 -0
- package/dist/point-cloud/types.js.map +1 -1
- package/dist/raster-set.d.ts +37 -29
- package/dist/raster-set.d.ts.map +1 -1
- package/dist/raster-set.js +25 -2
- package/dist/raster-set.js.map +1 -1
- package/dist/spatial/format-spatial-reference.d.ts +67 -0
- package/dist/spatial/format-spatial-reference.d.ts.map +1 -0
- package/dist/spatial/format-spatial-reference.js +233 -0
- package/dist/spatial/format-spatial-reference.js.map +1 -0
- package/dist/spatial/get-spatial-coordinate-frame.d.ts +9 -0
- package/dist/spatial/get-spatial-coordinate-frame.d.ts.map +1 -0
- package/dist/spatial/get-spatial-coordinate-frame.js +58 -0
- package/dist/spatial/get-spatial-coordinate-frame.js.map +1 -0
- package/dist/spatial/i3s-elevation.d.ts +20 -0
- package/dist/spatial/i3s-elevation.d.ts.map +1 -0
- package/dist/spatial/i3s-elevation.js +90 -0
- package/dist/spatial/i3s-elevation.js.map +1 -0
- package/dist/spatial/i3s-spatial-transformer.d.ts +189 -0
- package/dist/spatial/i3s-spatial-transformer.d.ts.map +1 -0
- package/dist/spatial/i3s-spatial-transformer.js +686 -0
- package/dist/spatial/i3s-spatial-transformer.js.map +1 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts +48 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts.map +1 -0
- package/dist/spatial/spatial-coordinate-transformer.js +211 -0
- package/dist/spatial/spatial-coordinate-transformer.js.map +1 -0
- package/dist/spatial/spatial-resource-registry.d.ts +44 -0
- package/dist/spatial/spatial-resource-registry.d.ts.map +1 -0
- package/dist/spatial/spatial-resource-registry.js +67 -0
- package/dist/spatial/spatial-resource-registry.js.map +1 -0
- package/dist/spatial/spatial-types.d.ts +190 -0
- package/dist/spatial/spatial-types.d.ts.map +1 -0
- package/dist/spatial/spatial-types.js +192 -0
- package/dist/spatial/spatial-types.js.map +1 -0
- package/dist/tileset-3d/common/tile-3d.d.ts +147 -4
- package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tile-3d.js +358 -76
- package/dist/tileset-3d/common/tile-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.d.ts +168 -3
- package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.js +306 -23
- package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-cache.d.ts +11 -1
- package/dist/tileset-3d/common/tileset-cache.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-cache.js +11 -3
- package/dist/tileset-3d/common/tileset-cache.js.map +1 -1
- package/dist/tileset-3d/common/tileset-source.d.ts +32 -0
- package/dist/tileset-3d/common/tileset-source.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-source.js.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts +19 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.js +39 -7
- package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts +136 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js +384 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts +86 -3
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js +196 -21
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts +36 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js +66 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts +14 -1
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.js +107 -17
- package/dist/tileset-3d/format-i3s/i3s-source.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/helpers/3d-tiles-options.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/3d-tiles-options.js +3 -0
- package/dist/tileset-3d/helpers/3d-tiles-options.js.map +1 -1
- package/dist/tileset-3d/helpers/bounding-volume.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/bounding-volume.js +4 -33
- package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.d.ts +62 -2
- package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.js +85 -9
- package/dist/tileset-3d/helpers/frame-state.js.map +1 -1
- package/dist/tileset-3d/helpers/i3s-lod.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/i3s-lod.js +20 -8
- package/dist/tileset-3d/helpers/i3s-lod.js.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts +61 -9
- package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-lod.js +198 -93
- package/dist/tileset-3d/helpers/tiles-3d-lod.js.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.d.ts +134 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.d.ts.map +1 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.js +179 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.js.map +1 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/doubly-linked-list.d.ts.map +1 -1
- package/dist/utils/doubly-linked-list.js +1 -0
- package/dist/utils/doubly-linked-list.js.map +1 -1
- package/dist/utils/managed-array.d.ts.map +1 -1
- package/dist/utils/managed-array.js +1 -0
- package/dist/utils/managed-array.js.map +1 -1
- package/package.json +12 -9
- package/src/index.ts +61 -1
- package/src/point-cloud/point-cloud-tile.ts +4 -0
- package/src/point-cloud/point-cloud-tileset.ts +70 -12
- package/src/point-cloud/types.ts +21 -0
- package/src/raster-set.ts +118 -45
- package/src/spatial/format-spatial-reference.ts +311 -0
- package/src/spatial/get-spatial-coordinate-frame.ts +74 -0
- package/src/spatial/i3s-elevation.ts +96 -0
- package/src/spatial/i3s-spatial-transformer.ts +957 -0
- package/src/spatial/spatial-coordinate-transformer.ts +276 -0
- package/src/spatial/spatial-resource-registry.ts +79 -0
- package/src/spatial/spatial-types.ts +422 -0
- package/src/tileset-3d/common/tile-3d.ts +435 -84
- package/src/tileset-3d/common/tileset-3d.ts +445 -23
- package/src/tileset-3d/common/tileset-cache.ts +15 -7
- package/src/tileset-3d/common/tileset-source.ts +36 -0
- package/src/tileset-3d/common/tileset-traverser.ts +40 -7
- package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +612 -0
- package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +254 -21
- package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +77 -0
- package/src/tileset-3d/format-i3s/i3s-pending-tiles-register.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-source.ts +119 -18
- package/src/tileset-3d/format-i3s/i3s-tile-manager.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-tileset-traverser.ts +4 -0
- package/src/tileset-3d/helpers/3d-tiles-options.ts +4 -0
- package/src/tileset-3d/helpers/bounding-volume.ts +5 -55
- package/src/tileset-3d/helpers/frame-state.ts +142 -11
- package/src/tileset-3d/helpers/i3s-lod.ts +22 -8
- package/src/tileset-3d/helpers/tiles-3d-lod.ts +291 -112
- package/src/tileset-3d/helpers/tiles-3d-request-priority.ts +301 -0
- package/src/types.ts +9 -0
- package/src/utils/doubly-linked-list.ts +2 -0
- package/src/utils/managed-array.ts +2 -0
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
import {Vector3, Matrix4} from '@math.gl/core';
|
|
9
9
|
import {CullingVolume} from '@math.gl/culling';
|
|
10
|
+
import type {CullingResult} from '@math.gl/culling';
|
|
10
11
|
|
|
11
12
|
// Note: circular dependency
|
|
12
13
|
import type {Tileset3D} from './tileset-3d';
|
|
13
14
|
import type {DoublyLinkedListNode} from '../../utils/doubly-linked-list-node';
|
|
14
15
|
import {LOD_METRIC_TYPE, TILE_REFINEMENT, TILE_CONTENT_STATE, TILESET_TYPE} from '../../constants';
|
|
15
|
-
import type {TileContentLoadResult} from './tileset-source';
|
|
16
|
+
import type {TileChildrenLoadResult, TileContentLoadResult} from './tileset-source';
|
|
16
17
|
|
|
17
18
|
import {FrameState} from '../helpers/frame-state';
|
|
18
19
|
import {
|
|
@@ -23,9 +24,67 @@ import {
|
|
|
23
24
|
import {getTiles3DScreenSpaceError} from '../helpers/tiles-3d-lod';
|
|
24
25
|
import {getProjectedRadius} from '../helpers/i3s-lod';
|
|
25
26
|
import {TilesetTraverser} from './tileset-traverser';
|
|
27
|
+
import {
|
|
28
|
+
calculateFoveatedFactor,
|
|
29
|
+
calculateTileRequestPriority,
|
|
30
|
+
isFoveatedRequestDelayActive,
|
|
31
|
+
isFoveatedRequestDeferred,
|
|
32
|
+
isProgressiveResolutionPriority
|
|
33
|
+
} from '../helpers/tiles-3d-request-priority';
|
|
26
34
|
|
|
27
35
|
const scratchVector = new Vector3();
|
|
28
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Classifies render-content visibility across all content volumes owned by a tile.
|
|
39
|
+
*
|
|
40
|
+
* Content volumes form a union: one visible content entry keeps the tile renderable even when
|
|
41
|
+
* another entry is outside the frustum or clipping planes. The traversal volume is intentionally
|
|
42
|
+
* not used here except as a fallback when a tile has no content-specific volume. This separation
|
|
43
|
+
* keeps clipping render-only and prevents a tight content volume from pruning descendants.
|
|
44
|
+
*
|
|
45
|
+
* @param contentVolumes - Transformed content volumes in source order.
|
|
46
|
+
* @param fallbackVolume - Tile volume used when content does not declare its own volume.
|
|
47
|
+
* @param cullingVolume - Current view frustum.
|
|
48
|
+
* @param visibilityPlaneMask - Parent visibility mask optimization.
|
|
49
|
+
* @param clippingPlanes - Optional world-space planes applied to render content only.
|
|
50
|
+
* @returns Union visibility classification for the renderable content.
|
|
51
|
+
*/
|
|
52
|
+
export function getContentVisibility(
|
|
53
|
+
contentVolumes: any[],
|
|
54
|
+
fallbackVolume: any,
|
|
55
|
+
cullingVolume: CullingVolume,
|
|
56
|
+
visibilityPlaneMask: number | undefined,
|
|
57
|
+
clippingPlanes: any[] = []
|
|
58
|
+
): CullingResult {
|
|
59
|
+
const volumes = contentVolumes.length ? contentVolumes : [fallbackVolume];
|
|
60
|
+
let visibleVolume = false;
|
|
61
|
+
let intersectingVolume = false;
|
|
62
|
+
for (const contentVolume of volumes) {
|
|
63
|
+
let visibility: CullingResult = 'inside';
|
|
64
|
+
if (visibilityPlaneMask !== CullingVolume.MASK_INSIDE) {
|
|
65
|
+
visibility = cullingVolume.computeVisibility(contentVolume);
|
|
66
|
+
if (visibility === 'outside') {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
let clipped = false;
|
|
71
|
+
for (const clippingPlane of clippingPlanes) {
|
|
72
|
+
if (contentVolume.intersectPlane(clippingPlane) === 'outside') {
|
|
73
|
+
clipped = true;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!clipped) {
|
|
78
|
+
visibleVolume = true;
|
|
79
|
+
intersectingVolume = intersectingVolume || visibility === 'intersecting';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!visibleVolume) {
|
|
83
|
+
return 'outside';
|
|
84
|
+
}
|
|
85
|
+
return intersectingVolume ? 'intersecting' : 'inside';
|
|
86
|
+
}
|
|
87
|
+
|
|
29
88
|
function defined(x) {
|
|
30
89
|
return x !== undefined && x !== null;
|
|
31
90
|
}
|
|
@@ -44,6 +103,9 @@ export type Tile3DProps = {
|
|
|
44
103
|
extendedId: string;
|
|
45
104
|
};
|
|
46
105
|
|
|
106
|
+
/** Lifecycle of a source-managed lazy child-header group. */
|
|
107
|
+
export type TileChildrenState = 'unloaded' | 'loading' | 'ready' | 'failed';
|
|
108
|
+
|
|
47
109
|
/**
|
|
48
110
|
* A Tile3DHeader represents a tile as Tileset3D. When a tile is first created, its content is not loaded;
|
|
49
111
|
* the content is loaded on-demand when needed based on the view.
|
|
@@ -59,6 +121,8 @@ export class Tile3D {
|
|
|
59
121
|
refine: TILE_REFINEMENT;
|
|
60
122
|
type: string;
|
|
61
123
|
contentUrl: string;
|
|
124
|
+
/** Resolved render-content URLs in source order; empty for contentless tiles. */
|
|
125
|
+
contentUrls: string[] = [];
|
|
62
126
|
/** Different refinement algorithms used by I3S and 3D tiles */
|
|
63
127
|
lodMetricType = 'geometricError';
|
|
64
128
|
/**
|
|
@@ -81,11 +145,24 @@ export class Tile3D {
|
|
|
81
145
|
* not the content's metadata in the tileset JSON file.
|
|
82
146
|
*/
|
|
83
147
|
content: any = null;
|
|
148
|
+
/** Loaded payloads in the same order as {@link contentUrls}; `content` remains the primary payload. */
|
|
149
|
+
contents: any[] = [];
|
|
150
|
+
/**
|
|
151
|
+
* Metadata entity attached to this tile in the source tileset, if present.
|
|
152
|
+
*
|
|
153
|
+
* This is the raw 3D Tiles metadata reference. The generic tiles runtime preserves it without
|
|
154
|
+
* decoding schema classes or binary property tables.
|
|
155
|
+
*/
|
|
156
|
+
metadata: Record<string, any> | null = null;
|
|
157
|
+
/** Raw metadata entities attached to tile contents, in content source order. */
|
|
158
|
+
contentMetadata: Array<Record<string, any> | null> = [];
|
|
84
159
|
contentState: number = TILE_CONTENT_STATE.UNLOADED;
|
|
85
160
|
gpuMemoryUsageInBytes: number = 0;
|
|
86
161
|
|
|
87
162
|
/** The tile's children - an array of Tile3D objects. */
|
|
88
163
|
children: Tile3D[] = [];
|
|
164
|
+
/** Current lifecycle state for a lazy implicit subtree rooted at this tile. */
|
|
165
|
+
childrenState: TileChildrenState = 'ready';
|
|
89
166
|
depth: number = 0;
|
|
90
167
|
viewportIds: any[] = [];
|
|
91
168
|
transform = new Matrix4();
|
|
@@ -111,17 +188,46 @@ export class Tile3D {
|
|
|
111
188
|
private _expireDate: any = null;
|
|
112
189
|
private _expiredContent: any = null;
|
|
113
190
|
|
|
191
|
+
/** In-flight source request shared by repeated traversal frames. */
|
|
192
|
+
private _childrenPromise: Promise<TileChildrenLoadResult> | null = null;
|
|
193
|
+
|
|
114
194
|
private _boundingBox?: CartographicBounds = undefined;
|
|
115
195
|
|
|
116
196
|
/** updated every frame for tree traversal and rendering optimizations: */
|
|
117
197
|
public _distanceToCamera: number = 0;
|
|
118
198
|
_screenSpaceError: number = 0;
|
|
199
|
+
/** SSE calculated at the reduced viewport height used to prioritize coarse coverage. */
|
|
200
|
+
_screenSpaceErrorProgressiveResolution: number = 0;
|
|
201
|
+
/** Whether this tile should be promoted into the progressive-resolution request pass. */
|
|
202
|
+
_priorityProgressiveResolution: boolean = false;
|
|
203
|
+
/** Angular distance from the camera view axis used to prioritize center tiles. */
|
|
204
|
+
_foveatedFactor: number = 0;
|
|
205
|
+
/** Whether this peripheral request is currently inside the camera-motion deferral window. */
|
|
206
|
+
priorityDeferred: boolean = false;
|
|
119
207
|
private _visibilityPlaneMask: any;
|
|
120
208
|
private _visible: boolean | undefined = undefined;
|
|
121
209
|
|
|
122
210
|
private _contentBoundingVolume: any;
|
|
211
|
+
private _contentBoundingVolumes: any[] = [];
|
|
212
|
+
/** Source content-volume headers retained after render content is unloaded. */
|
|
213
|
+
private _contentBoundingVolumeHeaders: any[] = [];
|
|
123
214
|
private _viewerRequestVolume: any;
|
|
124
215
|
|
|
216
|
+
/** Bounding volume used to cull the tile's first renderable content entry. */
|
|
217
|
+
get contentBoundingVolume(): any {
|
|
218
|
+
return this._contentBoundingVolume;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** All transformed render-content bounding volumes, including tile-volume fallbacks. */
|
|
222
|
+
get contentBoundingVolumes(): any[] {
|
|
223
|
+
return this._contentBoundingVolumes;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Bounding volume that limits when this tile may be requested, when declared. */
|
|
227
|
+
get viewerRequestVolume(): any {
|
|
228
|
+
return this._viewerRequestVolume;
|
|
229
|
+
}
|
|
230
|
+
|
|
125
231
|
_initialTransform: Matrix4 = new Matrix4();
|
|
126
232
|
|
|
127
233
|
// Used by traverser, cannot be marked private
|
|
@@ -176,6 +282,13 @@ export class Tile3D {
|
|
|
176
282
|
this.refine = this._getRefine(header.refine);
|
|
177
283
|
this.type = header.type;
|
|
178
284
|
this.contentUrl = header.contentUrl;
|
|
285
|
+
this.contentUrls = header.contentUrls || (header.contentUrl ? [header.contentUrl] : []);
|
|
286
|
+
this.metadata = header.metadata || null;
|
|
287
|
+
const contentHeaders = Array.isArray(header.content) ? header.content : [header.content];
|
|
288
|
+
this.contentMetadata = contentHeaders
|
|
289
|
+
.filter(Boolean)
|
|
290
|
+
.map(contentHeader => contentHeader.metadata || null);
|
|
291
|
+
this.childrenState = header.implicitSubtree ? 'unloaded' : 'ready';
|
|
179
292
|
|
|
180
293
|
this._initializeLodMetric(header);
|
|
181
294
|
this._initializeTransforms(header);
|
|
@@ -214,7 +327,24 @@ export class Tile3D {
|
|
|
214
327
|
|
|
215
328
|
/** Returns true if tile has children */
|
|
216
329
|
get hasChildren() {
|
|
217
|
-
return
|
|
330
|
+
return (
|
|
331
|
+
this.children.length > 0 ||
|
|
332
|
+
(this.header.children && this.header.children.length > 0) ||
|
|
333
|
+
Boolean(this.header.implicitSubtree && this.childrenState !== 'ready')
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Returns whether traversal may request an unresolved lazy child-header group. */
|
|
338
|
+
get hasUnloadedChildren(): boolean {
|
|
339
|
+
return Boolean(
|
|
340
|
+
this.header.implicitSubtree &&
|
|
341
|
+
(this.childrenState === 'unloaded' || this.childrenState === 'failed')
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Returns whether a lazy child-header request is currently in flight. */
|
|
346
|
+
get childrenLoading(): boolean {
|
|
347
|
+
return this.childrenState === 'loading';
|
|
218
348
|
}
|
|
219
349
|
|
|
220
350
|
/**
|
|
@@ -287,13 +417,28 @@ export class Tile3D {
|
|
|
287
417
|
return this._boundingBox;
|
|
288
418
|
}
|
|
289
419
|
|
|
290
|
-
/**
|
|
291
|
-
|
|
420
|
+
/**
|
|
421
|
+
* Gets the tile's screen-space error for normal refinement or a reduced-height priority pass.
|
|
422
|
+
*
|
|
423
|
+
* I3S already supplies a screen-oriented LOD metric and intentionally ignores the optional 3D
|
|
424
|
+
* Tiles progressive-resolution height fraction.
|
|
425
|
+
*
|
|
426
|
+
* @param frameState - Current camera and viewport measurements.
|
|
427
|
+
* @param useParentLodMetric - Whether to substitute the parent LOD metric.
|
|
428
|
+
* @param viewportHeightFraction - Fraction of viewport height represented by the priority pass.
|
|
429
|
+
* @returns Screen-space LOD error for the current tileset format.
|
|
430
|
+
*/
|
|
431
|
+
getScreenSpaceError(frameState, useParentLodMetric, viewportHeightFraction = 1) {
|
|
292
432
|
switch (this.tileset.type) {
|
|
293
433
|
case TILESET_TYPE.I3S:
|
|
294
434
|
return getProjectedRadius(this, frameState);
|
|
295
435
|
case TILESET_TYPE.TILES3D:
|
|
296
|
-
return getTiles3DScreenSpaceError(
|
|
436
|
+
return getTiles3DScreenSpaceError(
|
|
437
|
+
this,
|
|
438
|
+
frameState,
|
|
439
|
+
useParentLodMetric,
|
|
440
|
+
viewportHeightFraction
|
|
441
|
+
);
|
|
297
442
|
default:
|
|
298
443
|
// eslint-disable-next-line
|
|
299
444
|
throw new Error('Unsupported tileset type');
|
|
@@ -312,15 +457,43 @@ export class Tile3D {
|
|
|
312
457
|
* Memory usage of tile on GPU
|
|
313
458
|
*/
|
|
314
459
|
_getGpuMemoryUsageInBytes(): number {
|
|
315
|
-
|
|
460
|
+
const contents = this.contents.length ? this.contents : [this.content];
|
|
461
|
+
return contents.reduce(
|
|
462
|
+
(total, content) => total + (content?.gpuMemoryUsageInBytes || content?.byteLength || 0),
|
|
463
|
+
0
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Returns scheduler priority for render-content requests.
|
|
469
|
+
*
|
|
470
|
+
* @returns Numeric priority, or a negative value when the queued request should be cancelled.
|
|
471
|
+
*/
|
|
472
|
+
_getPriority(): number {
|
|
473
|
+
return this._calculateRequestPriority(false);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Returns scheduler priority for lazy child-header requests.
|
|
478
|
+
*
|
|
479
|
+
* Contentless implicit placeholders intentionally retain `UNLOADED` content state, so metadata
|
|
480
|
+
* scheduling skips only that render-content cancellation check and preserves every visibility,
|
|
481
|
+
* recency, progressive, foveated, and motion-deferral rule.
|
|
482
|
+
*
|
|
483
|
+
* @returns Numeric priority, or a negative value when the queued request should be cancelled.
|
|
484
|
+
*/
|
|
485
|
+
private _getChildrenPriority(): number {
|
|
486
|
+
return this._calculateRequestPriority(true);
|
|
316
487
|
}
|
|
317
488
|
|
|
318
|
-
|
|
319
|
-
*
|
|
320
|
-
*
|
|
489
|
+
/**
|
|
490
|
+
* Calculates the common scheduler priority for content or hierarchy metadata.
|
|
491
|
+
*
|
|
492
|
+
* @param allowUnloadedContent - Whether an empty placeholder may request child metadata.
|
|
493
|
+
* @returns Numeric priority, or a negative value when the queued request should be cancelled.
|
|
321
494
|
*/
|
|
322
495
|
// eslint-disable-next-line complexity
|
|
323
|
-
|
|
496
|
+
private _calculateRequestPriority(allowUnloadedContent: boolean): number {
|
|
324
497
|
const traverser = this.tileset._traverser;
|
|
325
498
|
const {skipLevelOfDetail} = traverser.options;
|
|
326
499
|
|
|
@@ -340,7 +513,13 @@ export class Tile3D {
|
|
|
340
513
|
if (this.tileset._frameNumber - this._touchedFrame >= 1) {
|
|
341
514
|
return -1;
|
|
342
515
|
}
|
|
343
|
-
|
|
516
|
+
// RequestScheduler re-evaluates this callback before a queued request receives a slot. A
|
|
517
|
+
// negative priority cancels work that became deferred after it was queued; the scheduled
|
|
518
|
+
// follow-up traversal submits it again after the motion delay expires.
|
|
519
|
+
if (this.priorityDeferred) {
|
|
520
|
+
return -1;
|
|
521
|
+
}
|
|
522
|
+
if (!allowUnloadedContent && this.contentState === TILE_CONTENT_STATE.UNLOADED) {
|
|
344
523
|
return -1;
|
|
345
524
|
}
|
|
346
525
|
|
|
@@ -354,8 +533,15 @@ export class Tile3D {
|
|
|
354
533
|
|
|
355
534
|
const rootScreenSpaceError = traverser.root ? traverser.root._screenSpaceError : 0.0;
|
|
356
535
|
|
|
357
|
-
// Map higher SSE to lower values (e.g. root tile is highest priority)
|
|
358
|
-
|
|
536
|
+
// Map higher SSE to lower values (e.g. root tile is highest priority), then combine the
|
|
537
|
+
// existing order with independent progressive and foveated priority bands.
|
|
538
|
+
const reverseScreenSpaceError = Math.max(rootScreenSpaceError - screenSpaceError, 0);
|
|
539
|
+
return calculateTileRequestPriority({
|
|
540
|
+
priorityProgressiveResolution: this._priorityProgressiveResolution,
|
|
541
|
+
foveatedFactor: this._foveatedFactor,
|
|
542
|
+
reverseScreenSpaceError,
|
|
543
|
+
rootScreenSpaceError
|
|
544
|
+
});
|
|
359
545
|
}
|
|
360
546
|
|
|
361
547
|
/**
|
|
@@ -394,6 +580,11 @@ export class Tile3D {
|
|
|
394
580
|
try {
|
|
395
581
|
const loadResult = await this.tileset.source.loadTileContent(this);
|
|
396
582
|
|
|
583
|
+
if (loadResult.contents) {
|
|
584
|
+
this.contents = loadResult.contents;
|
|
585
|
+
this.content = this.contents[0] || null;
|
|
586
|
+
}
|
|
587
|
+
|
|
397
588
|
if (this.tileset.options.contentLoader) {
|
|
398
589
|
await this.tileset.options.contentLoader(this);
|
|
399
590
|
}
|
|
@@ -410,11 +601,107 @@ export class Tile3D {
|
|
|
410
601
|
}
|
|
411
602
|
}
|
|
412
603
|
|
|
604
|
+
/**
|
|
605
|
+
* Requests and installs this tile's lazy child-header group through its source.
|
|
606
|
+
*
|
|
607
|
+
* The same request scheduler and SSE/foveated priority value used for render content are reused
|
|
608
|
+
* for subtree metadata. Repeated traversal frames share one promise, and scheduler cancellation
|
|
609
|
+
* restores the unloaded state so a later frame can retry.
|
|
610
|
+
*
|
|
611
|
+
* @param frameState - View state that made the subtree eligible for refinement.
|
|
612
|
+
* @returns Source load result, or an unloaded result if scheduling was cancelled.
|
|
613
|
+
*/
|
|
614
|
+
async loadChildren(frameState: FrameState): Promise<TileChildrenLoadResult> {
|
|
615
|
+
if (!this.header.implicitSubtree || this.childrenState === 'ready') {
|
|
616
|
+
return {loaded: false, tileCount: 0, childSubtreeCount: 0};
|
|
617
|
+
}
|
|
618
|
+
if (this._childrenPromise) {
|
|
619
|
+
return await this._childrenPromise;
|
|
620
|
+
}
|
|
621
|
+
if (!this.tileset.source.loadTileChildren) {
|
|
622
|
+
throw new Error('Tileset source does not support lazy tile children');
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
this.childrenState = 'loading';
|
|
626
|
+
this._childrenPromise = this._loadChildrenWithScheduler(frameState);
|
|
627
|
+
try {
|
|
628
|
+
return await this._childrenPromise;
|
|
629
|
+
} finally {
|
|
630
|
+
this._childrenPromise = null;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Runs one lazy child-header load after obtaining a scheduler token.
|
|
636
|
+
*
|
|
637
|
+
* @param frameState - View state forwarded to the source implementation.
|
|
638
|
+
* @returns Source load result.
|
|
639
|
+
*/
|
|
640
|
+
private async _loadChildrenWithScheduler(
|
|
641
|
+
frameState: FrameState
|
|
642
|
+
): Promise<TileChildrenLoadResult> {
|
|
643
|
+
const requestToken = await this.tileset._requestScheduler.scheduleRequest(
|
|
644
|
+
`${this.id}:implicit-subtree`,
|
|
645
|
+
this._getChildrenPriority.bind(this)
|
|
646
|
+
);
|
|
647
|
+
if (!requestToken) {
|
|
648
|
+
this.childrenState = 'unloaded';
|
|
649
|
+
return {loaded: false, tileCount: 0, childSubtreeCount: 0};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
try {
|
|
653
|
+
const loadResult = await this.tileset.source.loadTileChildren!(this, frameState);
|
|
654
|
+
this.childrenState = loadResult.loaded ? 'ready' : 'unloaded';
|
|
655
|
+
return loadResult;
|
|
656
|
+
} catch (error) {
|
|
657
|
+
this.childrenState = 'failed';
|
|
658
|
+
throw error;
|
|
659
|
+
} finally {
|
|
660
|
+
requestToken.done();
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Replaces a contentless implicit placeholder with its materialized subtree-root header.
|
|
666
|
+
*
|
|
667
|
+
* Transform state is intentionally preserved: the placeholder already owns the composed
|
|
668
|
+
* transform, and reapplying the root transform here would double-transform bounds and geometric
|
|
669
|
+
* error. Content and raw geometric error are reinitialized from the newly available header.
|
|
670
|
+
*
|
|
671
|
+
* @param materializedHeader - Available root header produced from one subtree resource.
|
|
672
|
+
*/
|
|
673
|
+
applyImplicitSubtreeHeader(materializedHeader: Record<string, any>): void {
|
|
674
|
+
const existingTransform = this.header.transform;
|
|
675
|
+
const existingTransformMatrix = this.header.transformMatrix;
|
|
676
|
+
this.header = {
|
|
677
|
+
...this.header,
|
|
678
|
+
...materializedHeader,
|
|
679
|
+
transform: existingTransform,
|
|
680
|
+
transformMatrix: existingTransformMatrix,
|
|
681
|
+
implicitSubtree: undefined
|
|
682
|
+
};
|
|
683
|
+
this.refine = this._getRefine(materializedHeader.refine);
|
|
684
|
+
this.type = materializedHeader.type;
|
|
685
|
+
this.contentUrl = materializedHeader.contentUrl;
|
|
686
|
+
this.contentUrls =
|
|
687
|
+
materializedHeader.contentUrls ||
|
|
688
|
+
(materializedHeader.contentUrl ? [materializedHeader.contentUrl] : []);
|
|
689
|
+
this._initializeLodMetric(materializedHeader);
|
|
690
|
+
this._updateLodMetricScale();
|
|
691
|
+
this._initializeBoundingVolumes(this.header);
|
|
692
|
+
// Use the merged header so inherited viewer-request-volume metadata remains available when a
|
|
693
|
+
// materialized implicit tile has no render content of its own.
|
|
694
|
+
this._initializeContent(this.header);
|
|
695
|
+
}
|
|
696
|
+
|
|
413
697
|
// Unloads the tile's content.
|
|
414
698
|
unloadContent() {
|
|
415
|
-
|
|
416
|
-
|
|
699
|
+
for (const content of this.contents.length ? this.contents : [this.content]) {
|
|
700
|
+
if (content && content.destroy) {
|
|
701
|
+
content.destroy();
|
|
702
|
+
}
|
|
417
703
|
}
|
|
704
|
+
this.contents = [];
|
|
418
705
|
this.content = null;
|
|
419
706
|
if (this.header.content && this.header.content.destroy) {
|
|
420
707
|
this.header.content.destroy();
|
|
@@ -450,6 +737,7 @@ export class Tile3D {
|
|
|
450
737
|
|
|
451
738
|
this._distanceToCamera = this.distanceToTile(frameState);
|
|
452
739
|
this._screenSpaceError = this.getScreenSpaceError(frameState, false);
|
|
740
|
+
this._updateRequestPriorityMetrics(frameState);
|
|
453
741
|
this._visibilityPlaneMask = this.visibility(frameState, parentVisibilityPlaneMask); // Use parent's plane mask to speed up visibility test
|
|
454
742
|
this._visible = this._visibilityPlaneMask !== CullingVolume.MASK_OUTSIDE;
|
|
455
743
|
this._inRequestVolume = this.insideViewerRequestVolume(frameState);
|
|
@@ -458,6 +746,71 @@ export class Tile3D {
|
|
|
458
746
|
this.viewportIds = viewportIds;
|
|
459
747
|
}
|
|
460
748
|
|
|
749
|
+
/**
|
|
750
|
+
* Updates progressive-resolution and foveated request metrics for a 3D Tiles traversal frame.
|
|
751
|
+
*
|
|
752
|
+
* I3S retains its format-specific screen-threshold ordering and is explicitly isolated from
|
|
753
|
+
* geometric-error scheduling. Orthographic viewports still receive progressive coverage, but
|
|
754
|
+
* angular foveation is disabled because an orthographic frustum has no perspective field of view.
|
|
755
|
+
*
|
|
756
|
+
* @param frameState - Current camera and viewport measurements.
|
|
757
|
+
*/
|
|
758
|
+
_updateRequestPriorityMetrics(frameState: FrameState): void {
|
|
759
|
+
if (this.tileset.type !== TILESET_TYPE.TILES3D) {
|
|
760
|
+
this._screenSpaceErrorProgressiveResolution = this._screenSpaceError;
|
|
761
|
+
this._priorityProgressiveResolution = false;
|
|
762
|
+
this._foveatedFactor = 0;
|
|
763
|
+
this.priorityDeferred = false;
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
const options = this.tileset.options;
|
|
768
|
+
const progressiveResolutionHeightFraction = options.progressiveResolutionHeightFraction;
|
|
769
|
+
this._screenSpaceErrorProgressiveResolution = this.getScreenSpaceError(
|
|
770
|
+
frameState,
|
|
771
|
+
false,
|
|
772
|
+
progressiveResolutionHeightFraction
|
|
773
|
+
);
|
|
774
|
+
this._priorityProgressiveResolution = isProgressiveResolutionPriority(
|
|
775
|
+
this._screenSpaceErrorProgressiveResolution,
|
|
776
|
+
this.parent?._screenSpaceErrorProgressiveResolution,
|
|
777
|
+
this.tileset.memoryAdjustedScreenSpaceError,
|
|
778
|
+
progressiveResolutionHeightFraction
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
if (
|
|
782
|
+
!options.foveatedScreenSpaceError ||
|
|
783
|
+
frameState.viewport?.orthographic ||
|
|
784
|
+
!frameState.camera?.position ||
|
|
785
|
+
!frameState.camera?.direction
|
|
786
|
+
) {
|
|
787
|
+
this._foveatedFactor = 0;
|
|
788
|
+
this.priorityDeferred = false;
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
this._foveatedFactor = calculateFoveatedFactor(this.boundingVolume, frameState.camera);
|
|
793
|
+
const deferralEligible = isFoveatedRequestDeferred({
|
|
794
|
+
refinement: this.refine,
|
|
795
|
+
skipLevelOfDetail: this.tileset._traverser.options.skipLevelOfDetail,
|
|
796
|
+
foveatedScreenSpaceError: options.foveatedScreenSpaceError,
|
|
797
|
+
foveatedConeSize: options.foveatedConeSize,
|
|
798
|
+
minimumScreenSpaceErrorRelaxation: options.foveatedMinimumScreenSpaceErrorRelaxation,
|
|
799
|
+
interpolationCallback: options.foveatedInterpolationCallback,
|
|
800
|
+
foveatedFactor: this._foveatedFactor,
|
|
801
|
+
verticalFieldOfView: frameState.camera.verticalFieldOfView,
|
|
802
|
+
screenSpaceError: this._screenSpaceError,
|
|
803
|
+
parentScreenSpaceError: this.parent?._screenSpaceError,
|
|
804
|
+
maximumScreenSpaceError: this.tileset.memoryAdjustedScreenSpaceError,
|
|
805
|
+
priorityProgressiveResolution: this._priorityProgressiveResolution
|
|
806
|
+
});
|
|
807
|
+
this.priorityDeferred = isFoveatedRequestDelayActive(
|
|
808
|
+
deferralEligible,
|
|
809
|
+
frameState.camera.timeSinceMovement,
|
|
810
|
+
options.foveatedTimeDelay
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
|
|
461
814
|
// Determines whether the tile's bounding volume intersects the culling volume.
|
|
462
815
|
// @param {FrameState} frameState The frame state.
|
|
463
816
|
// @param {Number} parentVisibilityPlaneMask The parent's plane mask to speed up the visibility check.
|
|
@@ -483,47 +836,22 @@ export class Tile3D {
|
|
|
483
836
|
return cullingVolume.computeVisibilityWithPlaneMask(boundingVolume, parentVisibilityPlaneMask);
|
|
484
837
|
}
|
|
485
838
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
// The tile's bounding volume is completely inside the culling volume so
|
|
503
|
-
// the content bounding volume must also be inside.
|
|
504
|
-
return Intersect.INSIDE;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// PERFORMANCE_IDEA: is it possible to burn less CPU on this test since we know the
|
|
508
|
-
// tile's (not the content's) bounding volume intersects the culling volume?
|
|
509
|
-
const cullingVolume = frameState.cullingVolume;
|
|
510
|
-
const boundingVolume = tile.contentBoundingVolume;
|
|
511
|
-
|
|
512
|
-
const tileset = this.tileset;
|
|
513
|
-
const clippingPlanes = tileset.clippingPlanes;
|
|
514
|
-
if (defined(clippingPlanes) && clippingPlanes.enabled) {
|
|
515
|
-
const intersection = clippingPlanes.computeIntersectionWithBoundingVolume(
|
|
516
|
-
boundingVolume,
|
|
517
|
-
tileset.clippingPlanesOriginMatrix
|
|
518
|
-
);
|
|
519
|
-
this._isClipped = intersection !== Intersect.INSIDE;
|
|
520
|
-
if (intersection === Intersect.OUTSIDE) {
|
|
521
|
-
return Intersect.OUTSIDE;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
return cullingVolume.computeVisibility(boundingVolume);
|
|
526
|
-
*/
|
|
839
|
+
/**
|
|
840
|
+
* Determines whether renderable content intersects the view and configured clipping planes.
|
|
841
|
+
*
|
|
842
|
+
* Clipping planes are render-only constraints; traversal continues to use the tile volume.
|
|
843
|
+
*
|
|
844
|
+
* @param frameState Current camera, culling, and optional clipping-plane state.
|
|
845
|
+
* @returns The content visibility classification.
|
|
846
|
+
*/
|
|
847
|
+
contentVisibility(frameState: FrameState): CullingResult {
|
|
848
|
+
return getContentVisibility(
|
|
849
|
+
this._contentBoundingVolumes,
|
|
850
|
+
this.boundingVolume,
|
|
851
|
+
frameState.cullingVolume,
|
|
852
|
+
this._visibilityPlaneMask,
|
|
853
|
+
frameState.clippingPlanes
|
|
854
|
+
);
|
|
527
855
|
}
|
|
528
856
|
|
|
529
857
|
/**
|
|
@@ -649,6 +977,7 @@ export class Tile3D {
|
|
|
649
977
|
|
|
650
978
|
_initializeBoundingVolumes(tileHeader) {
|
|
651
979
|
this._contentBoundingVolume = null;
|
|
980
|
+
this._contentBoundingVolumeHeaders = [];
|
|
652
981
|
this._viewerRequestVolume = null;
|
|
653
982
|
|
|
654
983
|
this._updateBoundingVolume(tileHeader);
|
|
@@ -657,6 +986,7 @@ export class Tile3D {
|
|
|
657
986
|
_initializeContent(tileHeader) {
|
|
658
987
|
// Empty tile by default
|
|
659
988
|
this.content = {_tileset: this.tileset, _tile: this};
|
|
989
|
+
this.contents = [];
|
|
660
990
|
this.hasEmptyContent = true;
|
|
661
991
|
this.contentState = TILE_CONTENT_STATE.UNLOADED;
|
|
662
992
|
|
|
@@ -664,7 +994,7 @@ export class Tile3D {
|
|
|
664
994
|
// This is `false` until the tile's content is loaded.
|
|
665
995
|
this.hasTilesetContent = false;
|
|
666
996
|
|
|
667
|
-
if (tileHeader.contentUrl) {
|
|
997
|
+
if (tileHeader.contentUrl || tileHeader.contentUrls?.length) {
|
|
668
998
|
this.content = null;
|
|
669
999
|
this.hasEmptyContent = false;
|
|
670
1000
|
}
|
|
@@ -679,6 +1009,10 @@ export class Tile3D {
|
|
|
679
1009
|
this._distanceToCamera = 0;
|
|
680
1010
|
this._centerZDepth = 0;
|
|
681
1011
|
this._screenSpaceError = 0;
|
|
1012
|
+
this._screenSpaceErrorProgressiveResolution = 0;
|
|
1013
|
+
this._priorityProgressiveResolution = false;
|
|
1014
|
+
this._foveatedFactor = 0;
|
|
1015
|
+
this.priorityDeferred = false;
|
|
682
1016
|
this._visibilityPlaneMask = CullingVolume.MASK_INDETERMINATE;
|
|
683
1017
|
this._visible = undefined;
|
|
684
1018
|
this._inRequestVolume = false;
|
|
@@ -700,19 +1034,31 @@ export class Tile3D {
|
|
|
700
1034
|
return refine || (this.parent && this.parent.refine) || TILE_REFINEMENT.REPLACE;
|
|
701
1035
|
}
|
|
702
1036
|
|
|
703
|
-
|
|
704
|
-
|
|
1037
|
+
/**
|
|
1038
|
+
* Returns whether loaded content is an external tileset.
|
|
1039
|
+
*
|
|
1040
|
+
* Parsed shape is authoritative because valid external resources may be extensionless, signed,
|
|
1041
|
+
* or use a misleading filename. This method is called only after source loading has populated
|
|
1042
|
+
* `content`.
|
|
1043
|
+
*/
|
|
1044
|
+
_isTileset(): boolean {
|
|
1045
|
+
return (this.contents.length ? this.contents : [this.content]).some(
|
|
1046
|
+
content => content?.shape === 'tileset3d'
|
|
1047
|
+
);
|
|
705
1048
|
}
|
|
706
1049
|
|
|
707
1050
|
_onContentLoaded() {
|
|
708
1051
|
// Vector and Geometry tile rendering do not support the skip LOD optimization.
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
1052
|
+
const contents = this.contents.length ? this.contents : [this.content];
|
|
1053
|
+
for (const content of contents) {
|
|
1054
|
+
switch (content && content.type) {
|
|
1055
|
+
case 'vctr':
|
|
1056
|
+
case 'geom':
|
|
1057
|
+
// @ts-ignore
|
|
1058
|
+
this.tileset._traverser.disableSkipLevelOfDetail = true;
|
|
1059
|
+
break;
|
|
1060
|
+
default:
|
|
1061
|
+
}
|
|
716
1062
|
}
|
|
717
1063
|
|
|
718
1064
|
// The content may be tileset json
|
|
@@ -731,24 +1077,9 @@ export class Tile3D {
|
|
|
731
1077
|
this.boundingVolume
|
|
732
1078
|
);
|
|
733
1079
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// TODO Cesium specific
|
|
740
|
-
// Non-leaf tiles may have a content bounding-volume, which is a tight-fit bounding volume
|
|
741
|
-
// around only the features in the tile. This box is useful for culling for rendering,
|
|
742
|
-
// but not for culling for traversing the tree since it does not guarantee spatial coherence, i.e.,
|
|
743
|
-
// since it only bounds features in the tile, not the entire tile, children may be
|
|
744
|
-
// outside of this box.
|
|
745
|
-
if (content.boundingVolume) {
|
|
746
|
-
this._contentBoundingVolume = createBoundingVolume(
|
|
747
|
-
content.boundingVolume,
|
|
748
|
-
this.computedTransform,
|
|
749
|
-
this._contentBoundingVolume
|
|
750
|
-
);
|
|
751
|
-
}
|
|
1080
|
+
// Viewer request volumes constrain traversal, not just render content. A contentless implicit
|
|
1081
|
+
// connector can still own an inherited request volume, so initialize it before the
|
|
1082
|
+
// content-specific early return below.
|
|
752
1083
|
if (header.viewerRequestVolume) {
|
|
753
1084
|
this._viewerRequestVolume = createBoundingVolume(
|
|
754
1085
|
header.viewerRequestVolume,
|
|
@@ -756,6 +1087,26 @@ export class Tile3D {
|
|
|
756
1087
|
this._viewerRequestVolume
|
|
757
1088
|
);
|
|
758
1089
|
}
|
|
1090
|
+
|
|
1091
|
+
const content = header.content;
|
|
1092
|
+
if (content) {
|
|
1093
|
+
this._contentBoundingVolumeHeaders = Array.isArray(content) ? content : [content];
|
|
1094
|
+
}
|
|
1095
|
+
const contentHeaders = content
|
|
1096
|
+
? Array.isArray(content)
|
|
1097
|
+
? content
|
|
1098
|
+
: [content]
|
|
1099
|
+
: this._contentBoundingVolumeHeaders;
|
|
1100
|
+
// Preserve source order: an unbounded content entry uses the tile volume at its
|
|
1101
|
+
// corresponding index rather than being appended after bounded sibling entries.
|
|
1102
|
+
this._contentBoundingVolumes = contentHeaders.length
|
|
1103
|
+
? contentHeaders.map(headerEntry =>
|
|
1104
|
+
headerEntry?.boundingVolume
|
|
1105
|
+
? createBoundingVolume(headerEntry.boundingVolume, this.computedTransform)
|
|
1106
|
+
: this.boundingVolume
|
|
1107
|
+
)
|
|
1108
|
+
: [this.boundingVolume];
|
|
1109
|
+
this._contentBoundingVolume = this._contentBoundingVolumes[0] || null;
|
|
759
1110
|
}
|
|
760
1111
|
|
|
761
1112
|
/**
|