@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
|
@@ -5,162 +5,214 @@
|
|
|
5
5
|
// This file is derived from the Cesium code base under Apache 2 license
|
|
6
6
|
// See LICENSE.md and https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
import {Matrix4, Quaternion, Vector3, clamp} from '@math.gl/core';
|
|
9
|
+
import {Ellipsoid} from '@math.gl/geospatial';
|
|
10
|
+
import type {Tile3D} from '../common/tile-3d';
|
|
11
|
+
import type {FrameState} from './frame-state';
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
/** Options that control the perspective dynamic screen-space error optimization. */
|
|
14
|
+
export type DynamicScreenSpaceErrorOptions = {
|
|
15
|
+
/** Base fog density used to reduce distant, horizon-facing screen-space error. */
|
|
16
|
+
dynamicScreenSpaceErrorDensity: number;
|
|
17
|
+
/** Maximum number of logical pixels subtracted from perspective screen-space error. */
|
|
18
|
+
dynamicScreenSpaceErrorFactor: number;
|
|
19
|
+
/** Fraction of the tileset height at which the optimization begins to fade. */
|
|
20
|
+
dynamicScreenSpaceErrorHeightFalloff: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type TileBoundingVolumeHeader = {
|
|
24
|
+
box?: number[];
|
|
25
|
+
region?: number[];
|
|
26
|
+
sphere?: number[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type TilesetHeightRange = {
|
|
30
|
+
cameraHeight: number;
|
|
31
|
+
minimumHeight: number;
|
|
32
|
+
maximumHeight: number;
|
|
33
|
+
cameraDirection: Vector3;
|
|
34
|
+
upDirection: Vector3;
|
|
35
|
+
};
|
|
14
36
|
|
|
15
37
|
const scratchPositionNormal = new Vector3();
|
|
16
38
|
const scratchCartographic = new Vector3();
|
|
17
|
-
const scratchMatrix = new Matrix4();
|
|
18
39
|
const scratchCenter = new Vector3();
|
|
19
40
|
const scratchPosition = new Vector3();
|
|
20
41
|
const scratchDirection = new Vector3();
|
|
42
|
+
const scratchBoxXAxis = new Vector3();
|
|
43
|
+
const scratchBoxYAxis = new Vector3();
|
|
44
|
+
const scratchBoxZAxis = new Vector3();
|
|
45
|
+
const scratchBoxQuaternion = new Quaternion();
|
|
46
|
+
const unitZDirection = new Vector3(0, 0, 1);
|
|
21
47
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
maximumHeight = tileBoundingVolume.maximumHeight;
|
|
41
|
-
} else {
|
|
42
|
-
// Transform camera position and direction into the local coordinate system of the tileset
|
|
43
|
-
const transformLocal = Matrix4.inverseTransformation(root.computedTransform, scratchMatrix);
|
|
44
|
-
const ellipsoid = mapProjection.ellipsoid;
|
|
45
|
-
const boundingVolume = tileBoundingVolume.boundingVolume;
|
|
46
|
-
const centerLocal = Matrix4.multiplyByPoint(
|
|
47
|
-
transformLocal,
|
|
48
|
-
boundingVolume.center,
|
|
49
|
-
scratchCenter
|
|
50
|
-
);
|
|
51
|
-
if (Cartesian3.magnitude(centerLocal) > ellipsoid.minimumRadius) {
|
|
52
|
-
// The tileset is defined in WGS84. Approximate the minimum and maximum height.
|
|
53
|
-
const centerCartographic = Cartographic.fromCartesian(
|
|
54
|
-
centerLocal,
|
|
55
|
-
ellipsoid,
|
|
56
|
-
scratchCartographic
|
|
57
|
-
);
|
|
58
|
-
up = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
|
|
59
|
-
direction = camera.directionWC;
|
|
60
|
-
height = camera.positionCartographic.height;
|
|
61
|
-
minimumHeight = 0.0;
|
|
62
|
-
maximumHeight = centerCartographic.height * 2.0;
|
|
63
|
-
} else {
|
|
64
|
-
// The tileset is defined in local coordinates (z-up)
|
|
65
|
-
const positionLocal = Matrix4.multiplyByPoint(
|
|
66
|
-
transformLocal,
|
|
67
|
-
camera.positionWC,
|
|
68
|
-
scratchPosition
|
|
69
|
-
);
|
|
70
|
-
up = Cartesian3.UNIT_Z;
|
|
71
|
-
direction = Matrix4.multiplyByPointAsVector(
|
|
72
|
-
transformLocal,
|
|
73
|
-
camera.directionWC,
|
|
74
|
-
scratchDirection
|
|
75
|
-
);
|
|
76
|
-
direction = Cartesian3.normalize(direction, direction);
|
|
77
|
-
height = positionLocal.z;
|
|
78
|
-
if (tileBoundingVolume instanceof TileOrientedBoundingBox) {
|
|
79
|
-
// Assuming z-up, the last component stores the half-height of the box
|
|
80
|
-
const boxHeight = root._header.boundingVolume.box[11];
|
|
81
|
-
minimumHeight = centerLocal.z - boxHeight;
|
|
82
|
-
maximumHeight = centerLocal.z + boxHeight;
|
|
83
|
-
} else if (tileBoundingVolume instanceof TileBoundingSphere) {
|
|
84
|
-
const radius = boundingVolume.radius;
|
|
85
|
-
minimumHeight = centerLocal.z - radius;
|
|
86
|
-
maximumHeight = centerLocal.z + radius;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
48
|
+
/**
|
|
49
|
+
* Refreshes the root transform before calculating transform-dependent dynamic SSE density.
|
|
50
|
+
*
|
|
51
|
+
* Traversal normally updates transforms while visiting tile visibility, but density is calculated
|
|
52
|
+
* immediately before traversal. Performing the root update at that earlier boundary keeps local
|
|
53
|
+
* box and sphere height falloff synchronized with an animated tileset model matrix in the same
|
|
54
|
+
* frame. {@link Tile3D._updateTransform} also recalculates world-space geometric error from its raw
|
|
55
|
+
* source value, so repeated calls do not compound scale.
|
|
56
|
+
*
|
|
57
|
+
* @param root - Root tile whose computed transform feeds dynamic SSE height calculations.
|
|
58
|
+
* @param modelMatrix - Current tileset-to-world transform for this frame.
|
|
59
|
+
*/
|
|
60
|
+
export function updateRootTransformForDynamicScreenSpaceError(
|
|
61
|
+
root: Tile3D,
|
|
62
|
+
modelMatrix: Matrix4
|
|
63
|
+
): void {
|
|
64
|
+
root._updateTransform(modelMatrix);
|
|
65
|
+
}
|
|
90
66
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Calculates the effective dynamic screen-space error density for one viewport and frame.
|
|
69
|
+
*
|
|
70
|
+
* Dynamic SSE is a perspective-only optimization for street-level views. It reduces refinement
|
|
71
|
+
* for distant tiles near the horizon, where loading every geometric detail is expensive and has
|
|
72
|
+
* limited visual benefit. Density fades to zero as the camera rises above the tileset or points
|
|
73
|
+
* vertically. The returned value belongs to the supplied frame state; callers must not reuse it
|
|
74
|
+
* for another viewport because camera height and direction are view dependent.
|
|
75
|
+
*
|
|
76
|
+
* @param root - Root tile whose transform and source bounding volume define the tileset space.
|
|
77
|
+
* @param frameState - Current camera measurements in WGS84 and logical viewport space.
|
|
78
|
+
* @param options - Dynamic SSE density and height-falloff controls.
|
|
79
|
+
* @returns Effective fog density for this viewport, or zero when it cannot be calculated.
|
|
80
|
+
*/
|
|
81
|
+
export function calculateDynamicScreenSpaceErrorDensity(
|
|
82
|
+
root: Tile3D,
|
|
83
|
+
frameState: FrameState,
|
|
84
|
+
options: DynamicScreenSpaceErrorOptions
|
|
85
|
+
): number {
|
|
86
|
+
if (
|
|
87
|
+
!Number.isFinite(options.dynamicScreenSpaceErrorDensity) ||
|
|
88
|
+
options.dynamicScreenSpaceErrorDensity <= 0
|
|
89
|
+
) {
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
95
92
|
|
|
96
|
-
const
|
|
93
|
+
const boundingVolumeHeader = getContentBoundingVolumeHeader(root);
|
|
94
|
+
const heightRange = boundingVolumeHeader.region
|
|
95
|
+
? getRegionHeightRange(boundingVolumeHeader.region, frameState)
|
|
96
|
+
: getCartesianHeightRange(root, boundingVolumeHeader, frameState);
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
if (!heightRange) {
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
100
101
|
|
|
101
|
-
|
|
102
|
+
const heightFalloff = clamp(options.dynamicScreenSpaceErrorHeightFalloff, 0, 1);
|
|
103
|
+
const heightClose =
|
|
104
|
+
heightRange.minimumHeight +
|
|
105
|
+
(heightRange.maximumHeight - heightRange.minimumHeight) * heightFalloff;
|
|
106
|
+
const heightSpan = heightRange.maximumHeight - heightClose;
|
|
107
|
+
const heightPercentage =
|
|
108
|
+
heightSpan > 0
|
|
109
|
+
? clamp((heightRange.cameraHeight - heightClose) / heightSpan, 0, 1)
|
|
110
|
+
: heightRange.cameraHeight >= heightRange.maximumHeight
|
|
111
|
+
? 1
|
|
112
|
+
: 0;
|
|
102
113
|
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
|
|
114
|
+
// A horizontal view has a dot product near zero and receives the strongest optimization.
|
|
115
|
+
// A vertical view has a dot product near one and keeps the unmodified perspective SSE.
|
|
116
|
+
const verticalAlignment = clamp(
|
|
117
|
+
Math.abs(heightRange.cameraDirection.dot(heightRange.upDirection)),
|
|
118
|
+
0,
|
|
119
|
+
1
|
|
120
|
+
);
|
|
121
|
+
const horizonFactor = (1 - verticalAlignment) * (1 - heightPercentage);
|
|
106
122
|
|
|
107
|
-
return dynamicScreenSpaceErrorDensity * horizonFactor;
|
|
123
|
+
return options.dynamicScreenSpaceErrorDensity * horizonFactor;
|
|
108
124
|
}
|
|
109
125
|
|
|
110
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Calculates exponential fog strength for a camera distance and density.
|
|
128
|
+
* @param distanceToCamera - Distance from the camera to the tile bounding volume in meters.
|
|
129
|
+
* @param density - Effective dynamic SSE density in inverse meters.
|
|
130
|
+
* @returns Unitless strength in the inclusive range from zero to one.
|
|
131
|
+
*/
|
|
132
|
+
export function getDynamicScreenSpaceErrorFog(distanceToCamera: number, density: number): number {
|
|
111
133
|
const scalar = distanceToCamera * density;
|
|
112
|
-
return 1
|
|
134
|
+
return 1 - Math.exp(-(scalar * scalar));
|
|
113
135
|
}
|
|
114
136
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Calculates the perspective SSE reduction for a tile.
|
|
139
|
+
* @param distanceToCamera - Distance from the camera to the tile bounding volume in meters.
|
|
140
|
+
* @param density - View-dependent fog density calculated for the current frame.
|
|
141
|
+
* @param factor - Maximum reduction in logical/CSS pixels.
|
|
142
|
+
* @returns Number of logical pixels to subtract from perspective SSE.
|
|
143
|
+
*/
|
|
144
|
+
export function getDynamicScreenSpaceError(
|
|
145
|
+
distanceToCamera: number,
|
|
146
|
+
density: number,
|
|
147
|
+
factor: number
|
|
148
|
+
): number {
|
|
149
|
+
if (density <= 0 || factor <= 0 || !Number.isFinite(density) || !Number.isFinite(factor)) {
|
|
150
|
+
return 0;
|
|
122
151
|
}
|
|
123
152
|
|
|
124
|
-
return
|
|
153
|
+
return getDynamicScreenSpaceErrorFog(distanceToCamera, density) * factor;
|
|
125
154
|
}
|
|
126
155
|
|
|
127
156
|
/**
|
|
128
157
|
* Calculates 3D Tiles screen-space error (SSE) for the current projection.
|
|
129
158
|
*
|
|
130
159
|
* Perspective SSE projects the tile's world-space geometric error through the existing viewport
|
|
131
|
-
* height and frustum denominator.
|
|
132
|
-
*
|
|
160
|
+
* height and frustum denominator. Dynamic SSE may then reduce distant horizon refinement using
|
|
161
|
+
* the density calculated specifically for this frame and viewport. Orthographic projection has
|
|
162
|
+
* no perspective distance falloff, so its error is divided directly by the viewport's world-space
|
|
163
|
+
* meters per logical pixel and is never adjusted by perspective dynamic SSE.
|
|
133
164
|
*
|
|
134
165
|
* @param tile - Tile containing the transform-scaled geometric error and camera distance.
|
|
135
166
|
* @param frameState - Current camera and viewport measurements.
|
|
136
167
|
* @param useParentLodMetric - Whether request prioritization should use the parent's error.
|
|
168
|
+
* @param viewportHeightFraction - Fraction of viewport height represented by the priority pass.
|
|
137
169
|
* @returns Estimated error in logical/CSS pixels.
|
|
138
170
|
*/
|
|
139
|
-
export function getTiles3DScreenSpaceError(
|
|
171
|
+
export function getTiles3DScreenSpaceError(
|
|
172
|
+
tile: Tile3D,
|
|
173
|
+
frameState: FrameState,
|
|
174
|
+
useParentLodMetric: boolean,
|
|
175
|
+
viewportHeightFraction = 1
|
|
176
|
+
): number {
|
|
140
177
|
const tileset = tile.tileset;
|
|
141
178
|
const parentLodMetricValue = (tile.parent && tile.parent.lodMetricValue) || tile.lodMetricValue;
|
|
142
179
|
const lodMetricValue = useParentLodMetric ? parentLodMetricValue : tile.lodMetricValue;
|
|
143
180
|
|
|
144
|
-
// Leaf tiles do not have any error so save the computation
|
|
145
|
-
if (lodMetricValue === 0
|
|
146
|
-
return 0
|
|
181
|
+
// Leaf tiles do not have any error so save the computation.
|
|
182
|
+
if (lodMetricValue === 0) {
|
|
183
|
+
return 0;
|
|
147
184
|
}
|
|
148
185
|
|
|
149
186
|
const {viewDistanceScale} = tileset.options;
|
|
150
|
-
const lodScale = viewDistanceScale || 1
|
|
151
|
-
const
|
|
187
|
+
const lodScale = viewDistanceScale || 1;
|
|
188
|
+
const heightFraction = Number.isFinite(viewportHeightFraction)
|
|
189
|
+
? Math.max(viewportHeightFraction, 0)
|
|
190
|
+
: 1;
|
|
191
|
+
const orthographicError = getOrthographicScreenSpaceError(
|
|
192
|
+
lodMetricValue,
|
|
193
|
+
frameState,
|
|
194
|
+
lodScale,
|
|
195
|
+
heightFraction
|
|
196
|
+
);
|
|
152
197
|
if (orthographicError !== null) {
|
|
153
198
|
return orthographicError;
|
|
154
199
|
}
|
|
155
200
|
|
|
156
|
-
// Avoid divide by zero when viewer is inside the tile
|
|
157
|
-
const
|
|
201
|
+
// Avoid divide by zero when viewer is inside the tile.
|
|
202
|
+
const distanceToCamera = Math.max(tile._distanceToCamera, 1e-7);
|
|
158
203
|
const {height, sseDenominator} = frameState;
|
|
159
|
-
let
|
|
204
|
+
let screenSpaceError =
|
|
205
|
+
(lodMetricValue * height * heightFraction * lodScale) / (distanceToCamera * sseDenominator);
|
|
160
206
|
|
|
161
|
-
|
|
207
|
+
if (tileset.options.dynamicScreenSpaceError && !frameState.viewport.orthographic) {
|
|
208
|
+
screenSpaceError -= getDynamicScreenSpaceError(
|
|
209
|
+
distanceToCamera,
|
|
210
|
+
frameState.dynamicScreenSpaceErrorDensity,
|
|
211
|
+
tileset.options.dynamicScreenSpaceErrorFactor
|
|
212
|
+
);
|
|
213
|
+
}
|
|
162
214
|
|
|
163
|
-
return
|
|
215
|
+
return screenSpaceError;
|
|
164
216
|
}
|
|
165
217
|
|
|
166
218
|
/**
|
|
@@ -174,18 +226,145 @@ export function getTiles3DScreenSpaceError(tile, frameState, useParentLodMetric)
|
|
|
174
226
|
* @param lodMetricValue - Transform-scaled geometric error in world-space meters.
|
|
175
227
|
* @param frameState - Current frame state containing the viewport.
|
|
176
228
|
* @param lodScale - Application refinement scale from `viewDistanceScale`.
|
|
229
|
+
* @param viewportHeightFraction - Fraction of logical viewport height represented by the pass.
|
|
177
230
|
* @returns SSE in logical pixels, or `null` when orthographic SSE cannot be calculated.
|
|
178
231
|
*/
|
|
179
|
-
function getOrthographicScreenSpaceError(
|
|
232
|
+
function getOrthographicScreenSpaceError(
|
|
233
|
+
lodMetricValue: number,
|
|
234
|
+
frameState: FrameState,
|
|
235
|
+
lodScale: number,
|
|
236
|
+
viewportHeightFraction: number
|
|
237
|
+
): number | null {
|
|
180
238
|
const viewport = frameState.viewport;
|
|
181
239
|
if (!viewport?.orthographic) {
|
|
182
240
|
return null;
|
|
183
241
|
}
|
|
184
242
|
|
|
185
243
|
const metersPerPixel = viewport.metersPerPixel;
|
|
186
|
-
if (!Number.isFinite(metersPerPixel) || metersPerPixel <= 0) {
|
|
244
|
+
if (!Number.isFinite(metersPerPixel) || !metersPerPixel || metersPerPixel <= 0) {
|
|
187
245
|
return null;
|
|
188
246
|
}
|
|
189
247
|
|
|
190
|
-
return (lodMetricValue * lodScale) / metersPerPixel;
|
|
248
|
+
return (lodMetricValue * lodScale * viewportHeightFraction) / metersPerPixel;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Returns the content bounding volume header, falling back to the traversal volume. */
|
|
252
|
+
function getContentBoundingVolumeHeader(root: Tile3D): TileBoundingVolumeHeader {
|
|
253
|
+
return root.header.content?.boundingVolume || root.header.boundingVolume;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Calculates camera and tileset heights for a geodetic region bounding volume. */
|
|
257
|
+
function getRegionHeightRange(region: number[], frameState: FrameState): TilesetHeightRange {
|
|
258
|
+
const upDirection = scratchPositionNormal.copy(frameState.camera.position).normalize();
|
|
259
|
+
const cameraDirection = scratchDirection.copy(frameState.camera.direction).normalize();
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
cameraHeight: frameState.camera.cartographicPosition[2],
|
|
263
|
+
minimumHeight: region[4],
|
|
264
|
+
maximumHeight: region[5],
|
|
265
|
+
cameraDirection,
|
|
266
|
+
upDirection
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Calculates camera and tileset heights for box and sphere volumes.
|
|
272
|
+
*
|
|
273
|
+
* The root transform is inverted so that both camera height and source volume dimensions use the
|
|
274
|
+
* same coordinate system. Small coordinates are treated as local z-up. Earth-scale coordinates
|
|
275
|
+
* are treated as WGS84 and use cartographic height, matching Cesium's conservative approximation.
|
|
276
|
+
*/
|
|
277
|
+
function getCartesianHeightRange(
|
|
278
|
+
root: Tile3D,
|
|
279
|
+
boundingVolumeHeader: TileBoundingVolumeHeader,
|
|
280
|
+
frameState: FrameState
|
|
281
|
+
): TilesetHeightRange | null {
|
|
282
|
+
const halfHeight = getBoundingVolumeCenterAndHalfHeight(boundingVolumeHeader, scratchCenter);
|
|
283
|
+
if (halfHeight === null) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const localTransform = new Matrix4(root.computedTransform).invert();
|
|
288
|
+
const ellipsoid = root.tileset.ellipsoid as Ellipsoid;
|
|
289
|
+
const centerMagnitude = Math.hypot(scratchCenter[0], scratchCenter[1], scratchCenter[2]);
|
|
290
|
+
|
|
291
|
+
if (centerMagnitude > ellipsoid.minimumRadius) {
|
|
292
|
+
const centerCartographic = ellipsoid.cartesianToCartographic(
|
|
293
|
+
scratchCenter,
|
|
294
|
+
scratchCartographic
|
|
295
|
+
);
|
|
296
|
+
const upDirection = scratchPositionNormal.copy(frameState.camera.position).normalize();
|
|
297
|
+
const cameraDirection = scratchDirection.copy(frameState.camera.direction).normalize();
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
cameraHeight: frameState.camera.cartographicPosition[2],
|
|
301
|
+
minimumHeight: 0,
|
|
302
|
+
maximumHeight: centerCartographic[2] * 2,
|
|
303
|
+
cameraDirection,
|
|
304
|
+
upDirection
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
localTransform.transformAsPoint(frameState.camera.position, scratchPosition);
|
|
309
|
+
localTransform.transformAsVector(frameState.camera.direction, scratchDirection);
|
|
310
|
+
scratchDirection.normalize();
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
cameraHeight: scratchPosition[2],
|
|
314
|
+
minimumHeight: scratchCenter[2] - halfHeight,
|
|
315
|
+
maximumHeight: scratchCenter[2] + halfHeight,
|
|
316
|
+
cameraDirection: scratchDirection,
|
|
317
|
+
upDirection: unitZDirection
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Copies the source volume center and returns its conservative z-up half-height.
|
|
323
|
+
* @param boundingVolumeHeader - Root content or traversal volume from tileset JSON.
|
|
324
|
+
* @param result - Scratch vector that receives the source-space center.
|
|
325
|
+
* @returns Half-height in source-space meters, or `null` for an unsupported volume.
|
|
326
|
+
*/
|
|
327
|
+
function getBoundingVolumeCenterAndHalfHeight(
|
|
328
|
+
boundingVolumeHeader: TileBoundingVolumeHeader,
|
|
329
|
+
result: Vector3
|
|
330
|
+
): number | null {
|
|
331
|
+
if (boundingVolumeHeader.box) {
|
|
332
|
+
const box = boundingVolumeHeader.box;
|
|
333
|
+
result.set(box[0], box[1], box[2]);
|
|
334
|
+
return getBoxHalfHeight(box);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (boundingVolumeHeader.sphere) {
|
|
338
|
+
const sphere = boundingVolumeHeader.sphere;
|
|
339
|
+
result.set(sphere[0], sphere[1], sphere[2]);
|
|
340
|
+
return sphere[3];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Returns the conservative source-z extent of an oriented box.
|
|
348
|
+
*
|
|
349
|
+
* A 12-component 3D Tiles box stores three half-axis vectors, so every vector can contribute to
|
|
350
|
+
* vertical height after rotation. The alternate 10-component representation stores half sizes and
|
|
351
|
+
* a quaternion; rotating its three scaled basis vectors produces the same sum of absolute z
|
|
352
|
+
* projections. Using only the nominal z axis would underestimate tilted volumes and fade dynamic
|
|
353
|
+
* SSE too early while the camera is still within the tileset's height range.
|
|
354
|
+
*
|
|
355
|
+
* @param box - Source-space oriented box in half-axis or half-size/quaternion form.
|
|
356
|
+
* @returns Conservative source-z half-height in the box coordinate system's distance units.
|
|
357
|
+
*/
|
|
358
|
+
function getBoxHalfHeight(box: number[]): number {
|
|
359
|
+
if (box.length === 10) {
|
|
360
|
+
scratchBoxQuaternion.fromArray(box, 6);
|
|
361
|
+
scratchBoxXAxis.set(box[3], 0, 0).transformByQuaternion(scratchBoxQuaternion);
|
|
362
|
+
scratchBoxYAxis.set(0, box[4], 0).transformByQuaternion(scratchBoxQuaternion);
|
|
363
|
+
scratchBoxZAxis.set(0, 0, box[5]).transformByQuaternion(scratchBoxQuaternion);
|
|
364
|
+
return (
|
|
365
|
+
Math.abs(scratchBoxXAxis[2]) + Math.abs(scratchBoxYAxis[2]) + Math.abs(scratchBoxZAxis[2])
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return Math.abs(box[5]) + Math.abs(box[8]) + Math.abs(box[11]);
|
|
191
370
|
}
|