t3d-3dtiles 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +28 -0
- package/README.md +41 -0
- package/build/t3d.3dtiles.js +5418 -0
- package/build/t3d.3dtiles.min.js +2 -0
- package/build/t3d.3dtiles.module.js +6183 -0
- package/examples/jsm/CesiumIon.js +30 -0
- package/examples/jsm/Tiles3DDebugger.js +219 -0
- package/examples/jsm/Tiles3DUtils.js +32 -0
- package/examples/jsm/helpers/LineSegmentHelper.js +74 -0
- package/examples/jsm/helpers/OBBHelper.js +48 -0
- package/examples/jsm/helpers/Tiles3DHelper.js +135 -0
- package/examples/jsm/math/Intersects.js +100 -0
- package/examples/jsm/math/LineSegment.js +234 -0
- package/package.json +57 -0
- package/src/Tiles3D.js +402 -0
- package/src/libs/ImageBitmapLoader.js +56 -0
- package/src/libs/glTF/Constants.js +85 -0
- package/src/libs/glTF/GLTFLoader.js +169 -0
- package/src/libs/glTF/GLTFResource.js +28 -0
- package/src/libs/glTF/GLTFUtils.js +131 -0
- package/src/libs/glTF/extensions/EXT_meshopt_compression.js +35 -0
- package/src/libs/glTF/extensions/KHR_draco_mesh_compression.js +54 -0
- package/src/libs/glTF/extensions/KHR_lights_punctual.js +53 -0
- package/src/libs/glTF/extensions/KHR_materials_clearcoat.js +42 -0
- package/src/libs/glTF/extensions/KHR_materials_pbrSpecularGlossiness.js +53 -0
- package/src/libs/glTF/extensions/KHR_materials_unlit.js +13 -0
- package/src/libs/glTF/extensions/KHR_texture_basisu.js +14 -0
- package/src/libs/glTF/extensions/KHR_texture_transform.js +31 -0
- package/src/libs/glTF/parsers/AccessorParser.js +99 -0
- package/src/libs/glTF/parsers/AnimationParser.js +118 -0
- package/src/libs/glTF/parsers/BufferParser.js +35 -0
- package/src/libs/glTF/parsers/BufferViewParser.js +27 -0
- package/src/libs/glTF/parsers/ImageParser.js +97 -0
- package/src/libs/glTF/parsers/IndexParser.js +22 -0
- package/src/libs/glTF/parsers/MaterialParser.js +146 -0
- package/src/libs/glTF/parsers/NodeParser.js +145 -0
- package/src/libs/glTF/parsers/PrimitiveParser.js +289 -0
- package/src/libs/glTF/parsers/ReferenceParser.js +67 -0
- package/src/libs/glTF/parsers/SceneParser.js +41 -0
- package/src/libs/glTF/parsers/SkinParser.js +53 -0
- package/src/libs/glTF/parsers/TextureParser.js +71 -0
- package/src/libs/glTF/parsers/Validator.js +16 -0
- package/src/loaders/B3DMLoader.js +49 -0
- package/src/loaders/CMPTLoader.js +48 -0
- package/src/loaders/I3DMLoader.js +49 -0
- package/src/loaders/PNTSLoader.js +20 -0
- package/src/loaders/TileGLTFLoader.js +17 -0
- package/src/loaders/parsers/HeaderParser.js +104 -0
- package/src/loaders/parsers/LoadParser.js +22 -0
- package/src/loaders/parsers/TableParser.js +66 -0
- package/src/loaders/parsers/b3dm/B3DMParser.js +18 -0
- package/src/loaders/parsers/b3dm/B3DMRootParser.js +22 -0
- package/src/loaders/parsers/b3dm/MaterialParser.js +156 -0
- package/src/loaders/parsers/cmpt/CMPTParser.js +37 -0
- package/src/loaders/parsers/cmpt/CMPTRootParser.js +44 -0
- package/src/loaders/parsers/gltf/IndexParser.js +24 -0
- package/src/loaders/parsers/i3dm/I3DMParser.js +28 -0
- package/src/loaders/parsers/i3dm/I3DMRootParser.js +123 -0
- package/src/loaders/parsers/i3dm/MaterialParser.js +152 -0
- package/src/loaders/parsers/i3dm/PrimitiveParser.js +291 -0
- package/src/loaders/parsers/pnts/PNTSRootParser.js +69 -0
- package/src/main.js +14 -0
- package/src/materials/InstancedBasicMaterial.js +32 -0
- package/src/materials/InstancedPBRMaterial.js +32 -0
- package/src/materials/InstancedShaderChunks.js +23 -0
- package/src/math/Ellipsoid.js +41 -0
- package/src/math/EllipsoidRegion.js +160 -0
- package/src/math/FastFrustum.js +49 -0
- package/src/math/GeoUtils.js +31 -0
- package/src/math/OBB.js +395 -0
- package/src/math/TileBoundingVolume.js +172 -0
- package/src/math/TileOBB.js +103 -0
- package/src/utils/BatchTable.js +14 -0
- package/src/utils/CameraList.js +131 -0
- package/src/utils/FeatureTable.js +107 -0
- package/src/utils/IntersectionUtils.js +136 -0
- package/src/utils/LRUCache.js +159 -0
- package/src/utils/ModelLoader.js +150 -0
- package/src/utils/PriorityQueue.js +102 -0
- package/src/utils/RequestState.js +17 -0
- package/src/utils/TilesLoader.js +386 -0
- package/src/utils/TilesScheduler.js +375 -0
- package/src/utils/Utils.js +43 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
|
|
2
|
+
export class PriorityQueue {
|
|
3
|
+
|
|
4
|
+
constructor({ maxJobs = 6, autoUpdate = true, priorityCallback = defaultPriorityCallback }) {
|
|
5
|
+
// options
|
|
6
|
+
this.maxJobs = maxJobs;
|
|
7
|
+
this.autoUpdate = autoUpdate;
|
|
8
|
+
|
|
9
|
+
this.items = [];
|
|
10
|
+
this.callbacks = new Map();
|
|
11
|
+
this.currJobs = 0;
|
|
12
|
+
this.scheduled = false;
|
|
13
|
+
|
|
14
|
+
this.priorityCallback = priorityCallback;
|
|
15
|
+
|
|
16
|
+
this._runjobs = () => {
|
|
17
|
+
this.tryRunJobs();
|
|
18
|
+
this.scheduled = false;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Customizable scheduling callback. Default using requestAnimationFrame()
|
|
23
|
+
schedulingCallback(func) {
|
|
24
|
+
requestAnimationFrame(func);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
sort() {
|
|
28
|
+
const priorityCallback = this.priorityCallback;
|
|
29
|
+
const items = this.items;
|
|
30
|
+
items.sort(priorityCallback);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
add(item, callback) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const prCallback = (...args) => callback(...args).then(resolve).catch(reject);
|
|
36
|
+
const items = this.items;
|
|
37
|
+
const callbacks = this.callbacks;
|
|
38
|
+
|
|
39
|
+
items.push(item);
|
|
40
|
+
callbacks.set(item, prCallback);
|
|
41
|
+
|
|
42
|
+
if (this.autoUpdate) {
|
|
43
|
+
this.scheduleJobRun();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
remove(item) {
|
|
49
|
+
const items = this.items;
|
|
50
|
+
const callbacks = this.callbacks;
|
|
51
|
+
|
|
52
|
+
const index = items.indexOf(item);
|
|
53
|
+
if (index !== -1) {
|
|
54
|
+
items.splice(index, 1);
|
|
55
|
+
callbacks.delete(item);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
tryRunJobs() {
|
|
60
|
+
this.sort();
|
|
61
|
+
|
|
62
|
+
const items = this.items;
|
|
63
|
+
const callbacks = this.callbacks;
|
|
64
|
+
const maxJobs = this.maxJobs;
|
|
65
|
+
let currJobs = this.currJobs;
|
|
66
|
+
while (maxJobs > currJobs && items.length > 0) {
|
|
67
|
+
currJobs++;
|
|
68
|
+
const item = items.pop();
|
|
69
|
+
const callback = callbacks.get(item);
|
|
70
|
+
callbacks.delete(item);
|
|
71
|
+
callback(item)
|
|
72
|
+
.then(() => {
|
|
73
|
+
this.currJobs--;
|
|
74
|
+
|
|
75
|
+
if (this.autoUpdate) {
|
|
76
|
+
this.scheduleJobRun();
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
.catch(() => {
|
|
80
|
+
this.currJobs--;
|
|
81
|
+
|
|
82
|
+
if (this.autoUpdate) {
|
|
83
|
+
this.scheduleJobRun();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
this.currJobs = currJobs;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
scheduleJobRun() {
|
|
91
|
+
if (!this.scheduled) {
|
|
92
|
+
this.schedulingCallback(this._runjobs.bind(this));
|
|
93
|
+
|
|
94
|
+
this.scheduled = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const defaultPriorityCallback = () => {
|
|
101
|
+
throw new Error('PriorityQueue: PriorityCallback function not defined.');
|
|
102
|
+
};
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { Matrix4, Vector3 } from 't3d';
|
|
2
|
+
import { TileBoundingVolume } from '../math/TileBoundingVolume.js';
|
|
3
|
+
import RequestState from './RequestState.js';
|
|
4
|
+
import { LRUCache } from './LRUCache.js';
|
|
5
|
+
import { PriorityQueue } from './PriorityQueue.js';
|
|
6
|
+
import { traverseSet, getUrlExtension } from './Utils.js';
|
|
7
|
+
|
|
8
|
+
export class TilesLoader {
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.lruCache = new LRUCache({ unloadPriorityCallback: lruPriorityCallback });
|
|
12
|
+
this.downloadQueue = new PriorityQueue({ maxJobs: 4, priorityCallback });
|
|
13
|
+
this.parseQueue = new PriorityQueue({ maxJobs: 1, priorityCallback });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fetchTileSet(url, parent = null, fetchOptions = {}) {
|
|
17
|
+
return fetch(url, fetchOptions).then(res => {
|
|
18
|
+
if (res.ok) {
|
|
19
|
+
return res.json();
|
|
20
|
+
} else {
|
|
21
|
+
throw new Error(`TilesLoader: Failed to load tileset "${url}" with status ${res.status} : ${res.statusText}`);
|
|
22
|
+
}
|
|
23
|
+
}).then(json => {
|
|
24
|
+
const version = json.asset.version;
|
|
25
|
+
const [major, minor] = version.split('.').map(v => parseInt(v));
|
|
26
|
+
console.assert(
|
|
27
|
+
major <= 1,
|
|
28
|
+
'TilesLoader: asset.version is expected to be a 1.x or a compatible version.'
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
if (major === 1 && minor > 0) {
|
|
32
|
+
console.warn('TilesLoader: tiles versions at 1.1 or higher have limited support. Some new extensions and features may not be supported.');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// remove trailing slash and last path-segment from the URL
|
|
36
|
+
const basePath = url.replace(/\/[^/]*\/?$/, '');
|
|
37
|
+
|
|
38
|
+
traverseSet(
|
|
39
|
+
json.root,
|
|
40
|
+
(node, parent) => preprocessTile(node, parent, basePath),
|
|
41
|
+
null,
|
|
42
|
+
parent,
|
|
43
|
+
parent ? parent.__depth : 0
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return json;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
requestTileContents(tile, tiles3D) {
|
|
51
|
+
// If the tile is already being loaded then don't
|
|
52
|
+
// start it again.
|
|
53
|
+
if (tile.__loadingState !== RequestState.UNLOADED) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const stats = tiles3D.stats;
|
|
58
|
+
const lruCache = this.lruCache;
|
|
59
|
+
const downloadQueue = this.downloadQueue;
|
|
60
|
+
const parseQueue = this.parseQueue;
|
|
61
|
+
|
|
62
|
+
const isExternalTileSet = tile.__externalTileSet;
|
|
63
|
+
|
|
64
|
+
lruCache.add(tile, t => {
|
|
65
|
+
if (t.__loadingState === RequestState.LOADING) {
|
|
66
|
+
// Stop the load if it's started
|
|
67
|
+
t.__loadAbort.abort();
|
|
68
|
+
t.__loadAbort = null;
|
|
69
|
+
} else if (isExternalTileSet) {
|
|
70
|
+
t.children.length = 0;
|
|
71
|
+
} else {
|
|
72
|
+
tiles3D.$disposeTile(t);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Decrement stats
|
|
76
|
+
if (t.__loadingState === RequestState.LOADING) {
|
|
77
|
+
stats.downloading--;
|
|
78
|
+
} else if (t.__loadingState === RequestState.PARSING) {
|
|
79
|
+
stats.parsing--;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
t.__loadingState = RequestState.UNLOADED;
|
|
83
|
+
t.__loadIndex++;
|
|
84
|
+
|
|
85
|
+
downloadQueue.remove(t);
|
|
86
|
+
parseQueue.remove(t);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Track a new load index so we avoid the condition where this load is stopped and
|
|
90
|
+
// another begins soon after so we don't parse twice.
|
|
91
|
+
tile.__loadIndex++;
|
|
92
|
+
const loadIndex = tile.__loadIndex;
|
|
93
|
+
const controller = new AbortController();
|
|
94
|
+
const signal = controller.signal;
|
|
95
|
+
|
|
96
|
+
stats.downloading++;
|
|
97
|
+
tile.__loadAbort = controller;
|
|
98
|
+
tile.__loadingState = RequestState.LOADING;
|
|
99
|
+
|
|
100
|
+
const errorCallback = e => {
|
|
101
|
+
// if it has been unloaded then the tile has been disposed
|
|
102
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (e.name !== 'AbortError') {
|
|
107
|
+
downloadQueue.remove(tile);
|
|
108
|
+
parseQueue.remove(tile);
|
|
109
|
+
|
|
110
|
+
if (tile.__loadingState === RequestState.PARSING) {
|
|
111
|
+
stats.parsing--;
|
|
112
|
+
} else if (tile.__loadingState === RequestState.LOADING) {
|
|
113
|
+
stats.downloading--;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
stats.failed++;
|
|
117
|
+
tile.__loadingState = RequestState.FAILED;
|
|
118
|
+
|
|
119
|
+
// Handle fetch bug for switching examples in index.html.
|
|
120
|
+
// https://stackoverflow.com/questions/12009423/what-does-status-canceled-for-a-resource-mean-in-chrome-developer-tools
|
|
121
|
+
if (e.message !== 'Failed to fetch') {
|
|
122
|
+
console.error(`TilesLoader: Failed to load tile at url "${tile.content.uri}".`);
|
|
123
|
+
console.error(e);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
lruCache.remove(tile);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
if (isExternalTileSet) {
|
|
131
|
+
downloadQueue.add(tile, tileCb => {
|
|
132
|
+
// if it has been unloaded then the tile has been disposed
|
|
133
|
+
if (tileCb.__loadIndex !== loadIndex) {
|
|
134
|
+
return Promise.resolve();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const preprocessURL = tiles3D.preprocessURL;
|
|
138
|
+
const fetchOptions = tiles3D.fetchOptions;
|
|
139
|
+
const uri = preprocessURL ? preprocessURL(tileCb.content.uri) : tileCb.content.uri;
|
|
140
|
+
return this.fetchTileSet(uri, tileCb, Object.assign({ signal }, fetchOptions));
|
|
141
|
+
}).then(json => {
|
|
142
|
+
// if it has been unloaded then the tile has been disposed
|
|
143
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
stats.downloading--;
|
|
148
|
+
tile.__loadAbort = null;
|
|
149
|
+
tile.__loadingState = RequestState.LOADED;
|
|
150
|
+
|
|
151
|
+
tile.children.push(json.root);
|
|
152
|
+
}).catch(errorCallback);
|
|
153
|
+
} else {
|
|
154
|
+
downloadQueue.add(tile, downloadTile => {
|
|
155
|
+
if (downloadTile.__loadIndex !== loadIndex) {
|
|
156
|
+
return Promise.resolve();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const preprocessURL = tiles3D.preprocessURL;
|
|
160
|
+
const fetchOptions = tiles3D.fetchOptions;
|
|
161
|
+
const uri = preprocessURL ? preprocessURL(downloadTile.content.uri) : downloadTile.content.uri;
|
|
162
|
+
return fetch(uri, Object.assign({ signal }, fetchOptions));
|
|
163
|
+
}).then(res => {
|
|
164
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (res.ok) {
|
|
169
|
+
const extension = getUrlExtension(res.url);
|
|
170
|
+
if (extension === 'gltf') {
|
|
171
|
+
return res.json();
|
|
172
|
+
} else {
|
|
173
|
+
return res.arrayBuffer();
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
throw new Error(`Failed to load model with error code ${res.status}`);
|
|
177
|
+
}
|
|
178
|
+
}).then(buffer => {
|
|
179
|
+
// if it has been unloaded then the tile has been disposed
|
|
180
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
stats.downloading--;
|
|
185
|
+
stats.parsing++;
|
|
186
|
+
tile.__loadAbort = null;
|
|
187
|
+
tile.__loadingState = RequestState.PARSING;
|
|
188
|
+
|
|
189
|
+
return parseQueue.add(tile, parseTile => {
|
|
190
|
+
// if it has been unloaded then the tile has been disposed
|
|
191
|
+
if (parseTile.__loadIndex !== loadIndex) {
|
|
192
|
+
return Promise.resolve();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const uri = parseTile.content.uri;
|
|
196
|
+
const extension = getUrlExtension(uri);
|
|
197
|
+
|
|
198
|
+
return tiles3D.$parseTile(buffer, parseTile, extension);
|
|
199
|
+
});
|
|
200
|
+
}).then(() => {
|
|
201
|
+
// if it has been unloaded then the tile has been disposed
|
|
202
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
stats.parsing--;
|
|
207
|
+
tile.__loadingState = RequestState.LOADED;
|
|
208
|
+
|
|
209
|
+
if (tile.__wasSetVisible) {
|
|
210
|
+
tiles3D.$setTileVisible(tile, true);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (tile.__wasSetActive) {
|
|
214
|
+
tiles3D.$setTileActive(tile, true);
|
|
215
|
+
}
|
|
216
|
+
}).catch(errorCallback);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Function for sorting the evicted LRU items. We should evict the shallowest depth first.
|
|
224
|
+
* @param {Tile} tile
|
|
225
|
+
* @returns number
|
|
226
|
+
*/
|
|
227
|
+
const lruPriorityCallback = (map, tile) => 1 / (tile.__depthFromRenderedParent + 1);
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Function for provided to sort all tiles for prioritizing loading.
|
|
231
|
+
*
|
|
232
|
+
* @param {Tile} a
|
|
233
|
+
* @param {Tile} b
|
|
234
|
+
* @returns number
|
|
235
|
+
*/
|
|
236
|
+
const priorityCallback = (a, b) => {
|
|
237
|
+
if (a.__depth !== b.__depth) {
|
|
238
|
+
// load shallower tiles first
|
|
239
|
+
return a.__depth > b.__depth ? -1 : 1;
|
|
240
|
+
} else if (a.__inFrustum !== b.__inFrustum) {
|
|
241
|
+
// load tiles that are in the frustum at the current depth
|
|
242
|
+
return a.__inFrustum ? 1 : -1;
|
|
243
|
+
} else if (a.__used !== b.__used) {
|
|
244
|
+
// load tiles that have been used
|
|
245
|
+
return a.__used ? 1 : -1;
|
|
246
|
+
} else if (a.__error !== b.__error) {
|
|
247
|
+
// load the tile with the higher error
|
|
248
|
+
return a.__error > b.__error ? 1 : -1;
|
|
249
|
+
} else if (a.__distanceFromCamera !== b.__distanceFromCamera) {
|
|
250
|
+
// and finally visible tiles which have equal error (ex: if geometricError === 0)
|
|
251
|
+
// should prioritize based on distance.
|
|
252
|
+
return a.__distanceFromCamera > b.__distanceFromCamera ? -1 : 1;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return 0;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const preprocessTile = (tile, parentTile, tileSetDir) => {
|
|
259
|
+
if (tile.contents) {
|
|
260
|
+
// TODO: multiple contents (1.1) are not supported yet
|
|
261
|
+
tile.content = tile.contents[0];
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (tile.content) {
|
|
265
|
+
// Fix old file formats
|
|
266
|
+
if (!('uri' in tile.content) && 'url' in tile.content) {
|
|
267
|
+
tile.content.uri = tile.content.url;
|
|
268
|
+
delete tile.content.url;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (tile.content.uri) {
|
|
272
|
+
// tile content uri has to be interpreted relative to the tileset.json
|
|
273
|
+
// tile.content.uri = new URL( tile.content.uri, tileSetDir + '/' ).toString();
|
|
274
|
+
tile.content.uri = `${tileSetDir}/${tile.content.uri}`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// NOTE: fix for some cases where tile provide the bounding volume
|
|
278
|
+
// but volumes are not present.
|
|
279
|
+
if (
|
|
280
|
+
tile.content.boundingVolume &&
|
|
281
|
+
!(
|
|
282
|
+
'box' in tile.content.boundingVolume ||
|
|
283
|
+
'sphere' in tile.content.boundingVolume ||
|
|
284
|
+
'region' in tile.content.boundingVolume
|
|
285
|
+
)
|
|
286
|
+
) {
|
|
287
|
+
delete tile.content.boundingVolume;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
tile.parent = parentTile;
|
|
292
|
+
tile.children = tile.children || [];
|
|
293
|
+
|
|
294
|
+
const uri = tile.content && tile.content.uri;
|
|
295
|
+
if (uri) {
|
|
296
|
+
// "content" should only indicate loadable meshes, not external tile sets
|
|
297
|
+
const extension = getUrlExtension(tile.content.uri);
|
|
298
|
+
const isExternalTileSet = Boolean(extension && extension.toLowerCase() === 'json');
|
|
299
|
+
tile.__externalTileSet = isExternalTileSet;
|
|
300
|
+
tile.__contentEmpty = isExternalTileSet;
|
|
301
|
+
} else {
|
|
302
|
+
tile.__externalTileSet = false;
|
|
303
|
+
tile.__contentEmpty = true;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Expected to be set during calculateError()
|
|
307
|
+
tile.__distanceFromCamera = Infinity;
|
|
308
|
+
tile.__error = Infinity;
|
|
309
|
+
|
|
310
|
+
tile.__inFrustum = false;
|
|
311
|
+
tile.__isLeaf = false;
|
|
312
|
+
|
|
313
|
+
tile.__usedLastFrame = false;
|
|
314
|
+
tile.__used = false;
|
|
315
|
+
|
|
316
|
+
tile.__wasSetVisible = false;
|
|
317
|
+
tile.__visible = false;
|
|
318
|
+
tile.__childrenWereVisible = false;
|
|
319
|
+
tile.__allChildrenLoaded = false;
|
|
320
|
+
|
|
321
|
+
tile.__wasSetActive = false;
|
|
322
|
+
tile.__active = false;
|
|
323
|
+
|
|
324
|
+
tile.__loadingState = RequestState.UNLOADED;
|
|
325
|
+
tile.__loadIndex = 0;
|
|
326
|
+
|
|
327
|
+
tile.__loadAbort = null;
|
|
328
|
+
|
|
329
|
+
tile.__depthFromRenderedParent = -1;
|
|
330
|
+
if (parentTile === null) {
|
|
331
|
+
tile.__depth = 0;
|
|
332
|
+
tile.refine = tile.refine || 'REPLACE';
|
|
333
|
+
} else {
|
|
334
|
+
tile.__depth = parentTile.__depth + 1;
|
|
335
|
+
tile.refine = tile.refine || parentTile.refine;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
//
|
|
339
|
+
|
|
340
|
+
const transform = new Matrix4();
|
|
341
|
+
if (tile.transform) {
|
|
342
|
+
transform.fromArray(tile.transform);
|
|
343
|
+
}
|
|
344
|
+
if (parentTile) {
|
|
345
|
+
transform.premultiply(parentTile.cached.transform);
|
|
346
|
+
}
|
|
347
|
+
const transformInverse = (new Matrix4()).copy(transform).inverse();
|
|
348
|
+
|
|
349
|
+
const transformScale = _vec3_1.setFromMatrixScale(transform);
|
|
350
|
+
const uniformScale = Math.max(transformScale.x, transformScale.y, transformScale.z);
|
|
351
|
+
let geometricError = tile.geometricError * uniformScale;
|
|
352
|
+
|
|
353
|
+
const boundingVolume = new TileBoundingVolume();
|
|
354
|
+
if ('box' in tile.boundingVolume) {
|
|
355
|
+
boundingVolume.setOBBData(tile.boundingVolume.box, transform);
|
|
356
|
+
}
|
|
357
|
+
if ('sphere' in tile.boundingVolume) {
|
|
358
|
+
boundingVolume.setSphereData(tile.boundingVolume.sphere, transform);
|
|
359
|
+
}
|
|
360
|
+
if ('region' in tile.boundingVolume) {
|
|
361
|
+
boundingVolume.setRegionData(...tile.boundingVolume.region);
|
|
362
|
+
geometricError = tile.geometricError;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
tile.cached = {
|
|
366
|
+
loadIndex: 0,
|
|
367
|
+
transform,
|
|
368
|
+
transformInverse,
|
|
369
|
+
|
|
370
|
+
geometricError, // geometric error applied tile transform scale
|
|
371
|
+
|
|
372
|
+
boundingVolume,
|
|
373
|
+
|
|
374
|
+
active: false,
|
|
375
|
+
inFrustum: [],
|
|
376
|
+
|
|
377
|
+
scene: null,
|
|
378
|
+
geometry: null,
|
|
379
|
+
material: null,
|
|
380
|
+
|
|
381
|
+
featureTable: null,
|
|
382
|
+
batchTable: null
|
|
383
|
+
};
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const _vec3_1 = new Vector3();
|