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.
Files changed (83) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +41 -0
  3. package/build/t3d.3dtiles.js +5418 -0
  4. package/build/t3d.3dtiles.min.js +2 -0
  5. package/build/t3d.3dtiles.module.js +6183 -0
  6. package/examples/jsm/CesiumIon.js +30 -0
  7. package/examples/jsm/Tiles3DDebugger.js +219 -0
  8. package/examples/jsm/Tiles3DUtils.js +32 -0
  9. package/examples/jsm/helpers/LineSegmentHelper.js +74 -0
  10. package/examples/jsm/helpers/OBBHelper.js +48 -0
  11. package/examples/jsm/helpers/Tiles3DHelper.js +135 -0
  12. package/examples/jsm/math/Intersects.js +100 -0
  13. package/examples/jsm/math/LineSegment.js +234 -0
  14. package/package.json +57 -0
  15. package/src/Tiles3D.js +402 -0
  16. package/src/libs/ImageBitmapLoader.js +56 -0
  17. package/src/libs/glTF/Constants.js +85 -0
  18. package/src/libs/glTF/GLTFLoader.js +169 -0
  19. package/src/libs/glTF/GLTFResource.js +28 -0
  20. package/src/libs/glTF/GLTFUtils.js +131 -0
  21. package/src/libs/glTF/extensions/EXT_meshopt_compression.js +35 -0
  22. package/src/libs/glTF/extensions/KHR_draco_mesh_compression.js +54 -0
  23. package/src/libs/glTF/extensions/KHR_lights_punctual.js +53 -0
  24. package/src/libs/glTF/extensions/KHR_materials_clearcoat.js +42 -0
  25. package/src/libs/glTF/extensions/KHR_materials_pbrSpecularGlossiness.js +53 -0
  26. package/src/libs/glTF/extensions/KHR_materials_unlit.js +13 -0
  27. package/src/libs/glTF/extensions/KHR_texture_basisu.js +14 -0
  28. package/src/libs/glTF/extensions/KHR_texture_transform.js +31 -0
  29. package/src/libs/glTF/parsers/AccessorParser.js +99 -0
  30. package/src/libs/glTF/parsers/AnimationParser.js +118 -0
  31. package/src/libs/glTF/parsers/BufferParser.js +35 -0
  32. package/src/libs/glTF/parsers/BufferViewParser.js +27 -0
  33. package/src/libs/glTF/parsers/ImageParser.js +97 -0
  34. package/src/libs/glTF/parsers/IndexParser.js +22 -0
  35. package/src/libs/glTF/parsers/MaterialParser.js +146 -0
  36. package/src/libs/glTF/parsers/NodeParser.js +145 -0
  37. package/src/libs/glTF/parsers/PrimitiveParser.js +289 -0
  38. package/src/libs/glTF/parsers/ReferenceParser.js +67 -0
  39. package/src/libs/glTF/parsers/SceneParser.js +41 -0
  40. package/src/libs/glTF/parsers/SkinParser.js +53 -0
  41. package/src/libs/glTF/parsers/TextureParser.js +71 -0
  42. package/src/libs/glTF/parsers/Validator.js +16 -0
  43. package/src/loaders/B3DMLoader.js +49 -0
  44. package/src/loaders/CMPTLoader.js +48 -0
  45. package/src/loaders/I3DMLoader.js +49 -0
  46. package/src/loaders/PNTSLoader.js +20 -0
  47. package/src/loaders/TileGLTFLoader.js +17 -0
  48. package/src/loaders/parsers/HeaderParser.js +104 -0
  49. package/src/loaders/parsers/LoadParser.js +22 -0
  50. package/src/loaders/parsers/TableParser.js +66 -0
  51. package/src/loaders/parsers/b3dm/B3DMParser.js +18 -0
  52. package/src/loaders/parsers/b3dm/B3DMRootParser.js +22 -0
  53. package/src/loaders/parsers/b3dm/MaterialParser.js +156 -0
  54. package/src/loaders/parsers/cmpt/CMPTParser.js +37 -0
  55. package/src/loaders/parsers/cmpt/CMPTRootParser.js +44 -0
  56. package/src/loaders/parsers/gltf/IndexParser.js +24 -0
  57. package/src/loaders/parsers/i3dm/I3DMParser.js +28 -0
  58. package/src/loaders/parsers/i3dm/I3DMRootParser.js +123 -0
  59. package/src/loaders/parsers/i3dm/MaterialParser.js +152 -0
  60. package/src/loaders/parsers/i3dm/PrimitiveParser.js +291 -0
  61. package/src/loaders/parsers/pnts/PNTSRootParser.js +69 -0
  62. package/src/main.js +14 -0
  63. package/src/materials/InstancedBasicMaterial.js +32 -0
  64. package/src/materials/InstancedPBRMaterial.js +32 -0
  65. package/src/materials/InstancedShaderChunks.js +23 -0
  66. package/src/math/Ellipsoid.js +41 -0
  67. package/src/math/EllipsoidRegion.js +160 -0
  68. package/src/math/FastFrustum.js +49 -0
  69. package/src/math/GeoUtils.js +31 -0
  70. package/src/math/OBB.js +395 -0
  71. package/src/math/TileBoundingVolume.js +172 -0
  72. package/src/math/TileOBB.js +103 -0
  73. package/src/utils/BatchTable.js +14 -0
  74. package/src/utils/CameraList.js +131 -0
  75. package/src/utils/FeatureTable.js +107 -0
  76. package/src/utils/IntersectionUtils.js +136 -0
  77. package/src/utils/LRUCache.js +159 -0
  78. package/src/utils/ModelLoader.js +150 -0
  79. package/src/utils/PriorityQueue.js +102 -0
  80. package/src/utils/RequestState.js +17 -0
  81. package/src/utils/TilesLoader.js +386 -0
  82. package/src/utils/TilesScheduler.js +375 -0
  83. package/src/utils/Utils.js +43 -0
@@ -0,0 +1,131 @@
1
+ import { Vector2, Vector3, Matrix4 } from 't3d';
2
+ import { FastFrustum } from '../math/FastFrustum.js';
3
+
4
+ export class CameraList {
5
+
6
+ constructor() {
7
+ this._cameras = [];
8
+ this._resolution = new Vector2();
9
+ this._infos = [];
10
+ }
11
+
12
+ add(camera) {
13
+ const cameras = this._cameras;
14
+
15
+ if (cameras.indexOf(camera) === -1) {
16
+ cameras.push(camera);
17
+ return true;
18
+ }
19
+
20
+ return false;
21
+ }
22
+
23
+ remove(camera) {
24
+ const cameras = this._cameras;
25
+ const index = cameras.indexOf(camera);
26
+
27
+ if (index !== -1) {
28
+ cameras.splice(index, 1);
29
+ return true;
30
+ }
31
+
32
+ return false;
33
+ }
34
+
35
+ setResolution(width, height) {
36
+ this._resolution.set(width, height);
37
+ }
38
+
39
+ updateInfos(originMatrix) {
40
+ const cameras = this._cameras;
41
+ const cameraCount = cameras.length;
42
+ const infos = this._infos;
43
+ const resolution = this._resolution;
44
+
45
+ if (cameraCount === 0) {
46
+ console.warn('CameraList.updateInfos(): No camera added.');
47
+ return;
48
+ }
49
+
50
+ // automatically scale the array of infos to match the cameras
51
+
52
+ while (infos.length > cameras.length) {
53
+ infos.pop();
54
+ }
55
+
56
+ while (infos.length < cameras.length) {
57
+ infos.push({
58
+ frustum: new FastFrustum(), // in origin space
59
+ isOrthographic: false,
60
+ sseDenominator: -1, // used if isOrthographic is false
61
+ position: new Vector3(), // in origin space
62
+ invScale: -1,
63
+ pixelSize: 0 // used if isOrthographic is true
64
+ });
65
+ }
66
+
67
+ // get inverse scale of origin matrix
68
+
69
+ _mat4_1.copy(originMatrix).inverse();
70
+
71
+ const invScaleX = _vec3_1.setFromMatrixColumn(_mat4_1, 0).getLength();
72
+ const invScaleY = _vec3_1.setFromMatrixColumn(_mat4_1, 1).getLength();
73
+ const invScaleZ = _vec3_1.setFromMatrixColumn(_mat4_1, 2).getLength();
74
+
75
+ if (Math.abs(Math.max(invScaleX - invScaleY, invScaleX - invScaleZ)) > 1e-6) {
76
+ console.warn('CameraList.updateInfos(): Non uniform scale used for tile which may cause issues when calculating screen space error.');
77
+ }
78
+
79
+ const invScale = invScaleX;
80
+ const invOriginMatrix = _mat4_1;
81
+
82
+ // update the camera infos
83
+
84
+ for (let i = 0, l = infos.length; i < l; i++) {
85
+ const camera = cameras[i];
86
+ const info = infos[i];
87
+
88
+ const cameraResolutionX = resolution.x * (camera.rect.z - camera.rect.x);
89
+ const cameraResolutionY = resolution.y * (camera.rect.w - camera.rect.y);
90
+
91
+ if (cameraResolutionX === 0 || cameraResolutionY === 0) {
92
+ console.warn('CameraList.updateInfos(): Resolution for camera error calculation is not set.');
93
+ }
94
+
95
+ // Read the calculated projection matrix directly to support custom Camera implementations
96
+ const projection = camera.projectionMatrix.elements;
97
+
98
+ // The last element of the projection matrix is 1 for orthographic, 0 for perspective
99
+ info.isOrthographic = projection[15] === 1;
100
+
101
+ if (info.isOrthographic) {
102
+ // the view width and height are used to populate matrix elements 0 and 5.
103
+ const w = 2 / projection[0];
104
+ const h = 2 / projection[5];
105
+ info.pixelSize = Math.max(h / cameraResolutionY, w / cameraResolutionX);
106
+ } else {
107
+ // the vertical FOV is used to populate matrix element 5.
108
+ info.sseDenominator = (2 / projection[5]) / cameraResolutionY;
109
+ }
110
+
111
+ info.invScale = invScale;
112
+
113
+ // get frustum in origin space
114
+ _mat4_2.copy(originMatrix).premultiply(camera.projectionViewMatrix);
115
+ info.frustum.setFromMatrix(_mat4_2);
116
+ info.frustum.updateCache();
117
+
118
+ // get camera position in origin space
119
+ info.position.setFromMatrixPosition(camera.worldMatrix).applyMatrix4(invOriginMatrix);
120
+ }
121
+ }
122
+
123
+ getInfos() {
124
+ return this._infos;
125
+ }
126
+
127
+ }
128
+
129
+ const _mat4_1 = new Matrix4();
130
+ const _mat4_2 = new Matrix4();
131
+ const _vec3_1 = new Vector3();
@@ -0,0 +1,107 @@
1
+
2
+ import { GLTFUtils } from '../libs/glTF/GLTFUtils.js';
3
+
4
+ export class FeatureTable {
5
+
6
+ constructor(buffer, start, headerLength, binLength) {
7
+ this.buffer = buffer;
8
+ this.binOffset = start + headerLength;
9
+ this.binLength = binLength;
10
+
11
+ let header = null;
12
+ if (headerLength !== 0) {
13
+ const headerData = new Uint8Array(buffer, start, headerLength);
14
+ header = JSON.parse(GLTFUtils.decodeText(headerData));
15
+ } else {
16
+ header = {};
17
+ }
18
+ this.header = header;
19
+ }
20
+
21
+ getKeys() {
22
+ return Object.keys(this.header);
23
+ }
24
+
25
+ getData(key, count, defaultComponentType = null, defaultType = null) {
26
+ const header = this.header;
27
+
28
+ if (!(key in header)) {
29
+ return null;
30
+ }
31
+
32
+ const feature = header[key];
33
+ if (!(feature instanceof Object)) {
34
+ return feature;
35
+ } else if (Array.isArray(feature)) {
36
+ return feature;
37
+ } else {
38
+ const { buffer, binOffset, binLength } = this;
39
+ const byteOffset = feature.byteOffset || 0;
40
+ const featureType = feature.type || defaultType;
41
+ const featureComponentType = feature.componentType || defaultComponentType;
42
+
43
+ if ('type' in feature && defaultType && feature.type !== defaultType) {
44
+ throw new Error('FeatureTable: Specified type does not match expected type.');
45
+ }
46
+
47
+ let stride;
48
+ switch (featureType) {
49
+ case 'SCALAR':
50
+ stride = 1;
51
+ break;
52
+ case 'VEC2':
53
+ stride = 2;
54
+ break;
55
+ case 'VEC3':
56
+ stride = 3;
57
+ break;
58
+ case 'VEC4':
59
+ stride = 4;
60
+ break;
61
+ default:
62
+ throw new Error(`FeatureTable: Feature type not provided for "${key}".`);
63
+ }
64
+
65
+ let data;
66
+ const arrayStart = binOffset + byteOffset;
67
+ const arrayLength = count * stride;
68
+
69
+ switch (featureComponentType) {
70
+ case 'BYTE':
71
+ data = new Int8Array(buffer, arrayStart, arrayLength);
72
+ break;
73
+ case 'UNSIGNED_BYTE':
74
+ data = new Uint8Array(buffer, arrayStart, arrayLength);
75
+ break;
76
+ case 'SHORT':
77
+ data = new Int16Array(buffer, arrayStart, arrayLength);
78
+ break;
79
+ case 'UNSIGNED_SHORT':
80
+ data = new Uint16Array(buffer, arrayStart, arrayLength);
81
+ break;
82
+ case 'INT':
83
+ data = new Int32Array(buffer, arrayStart, arrayLength);
84
+ break;
85
+ case 'UNSIGNED_INT':
86
+ data = new Uint32Array(buffer, arrayStart, arrayLength);
87
+ break;
88
+ case 'FLOAT':
89
+ data = new Float32Array(buffer, arrayStart, arrayLength);
90
+ break;
91
+ case 'DOUBLE':
92
+ data = new Float64Array(buffer, arrayStart, arrayLength);
93
+ break;
94
+ default:
95
+ throw new Error(`FeatureTable: Feature component type not provided for "${key}".`);
96
+ }
97
+
98
+ const dataEnd = arrayStart + arrayLength * data.BYTES_PER_ELEMENT;
99
+ if (dataEnd > binOffset + binLength) {
100
+ throw new Error('FeatureTable: Feature data read outside binary body length.');
101
+ }
102
+
103
+ return data;
104
+ }
105
+ }
106
+
107
+ }
@@ -0,0 +1,136 @@
1
+ import { Matrix4, Ray, Vector3 } from 't3d';
2
+
3
+ export const raycastTraverse = (tile, tiles3D, ray, intersects, localRay = null) => {
4
+ const { activeTiles } = tiles3D;
5
+ const boundingVolume = tile.cached.boundingVolume;
6
+
7
+ // reuse the ray when traversing the tree
8
+ if (localRay === null) {
9
+ localRay = _ray_1;
10
+ _mat4_1.copy(tiles3D.worldMatrix).inverse();
11
+ localRay.copy(ray).applyMatrix4(_mat4_1);
12
+ }
13
+
14
+ if (!tile.__used || !boundingVolume.intersectsRay(localRay)) {
15
+ return;
16
+ }
17
+
18
+ if (activeTiles.has(tile)) {
19
+ _intersectTileScene(tile, ray, intersects);
20
+ }
21
+
22
+ const children = tile.children;
23
+ for (let i = 0, l = children.length; i < l; i++) {
24
+ raycastTraverse(children[i], tiles3D, ray, intersects, localRay);
25
+ }
26
+ };
27
+
28
+ // Returns the closest hit when traversing the tree
29
+ export const raycastTraverseFirstHit = (tile, tiles3D, ray, localRay = null) => {
30
+ const { activeTiles } = tiles3D;
31
+
32
+ // reuse the ray when traversing the tree
33
+ if (localRay === null) {
34
+ localRay = _ray_1;
35
+ _mat4_1.copy(tiles3D.worldMatrix).inverse();
36
+ localRay.copy(ray).applyMatrix4(_mat4_1);
37
+ }
38
+
39
+ // get a set of intersections so we intersect the nearest one first
40
+ const array = [];
41
+ const children = tile.children;
42
+ for (let i = 0, l = children.length; i < l; i++) {
43
+ const child = children[i];
44
+
45
+ if (!child.__used) {
46
+ continue;
47
+ }
48
+
49
+ const boundingVolume = child.cached.boundingVolume;
50
+
51
+ if (boundingVolume.intersectRay(localRay, _vec3_1)) {
52
+ _vec3_1.applyMatrix4(tiles3D.worldMatrix);
53
+ array.push({
54
+ distance: _vec3_1.distanceToSquared(ray.origin),
55
+ tile: child
56
+ });
57
+ }
58
+ }
59
+
60
+ // sort them by ascending distance
61
+ array.sort(distanceSort);
62
+
63
+ let bestHit = null;
64
+ let bestHitDistSq = Infinity;
65
+
66
+ // If the root is active make sure we've checked it
67
+ if (activeTiles.has(tile)) {
68
+ _intersectTileScene(tile, ray, _hitArray);
69
+
70
+ if (_hitArray.length > 0) {
71
+ if (_hitArray.length > 1) {
72
+ _hitArray.sort(distanceSort);
73
+ }
74
+
75
+ const hit = _hitArray[0];
76
+ _hitArray.length = 0;
77
+
78
+ bestHit = hit;
79
+ bestHitDistSq = hit.distance * hit.distance;
80
+ }
81
+ }
82
+
83
+ // traverse until we find the best hit and early out if a tile bounds
84
+ // couldn't possible include a best hit
85
+ for (let i = 0, l = array.length; i < l; i++) {
86
+ const data = array[i];
87
+ const distanceSquared = data.distance;
88
+ const tile = data.tile;
89
+
90
+ if (distanceSquared > bestHitDistSq) {
91
+ break;
92
+ }
93
+
94
+ const hit = raycastTraverseFirstHit(tile, tiles3D, ray, localRay);
95
+
96
+ if (hit) {
97
+ const hitDistSq = hit.distance * hit.distance;
98
+ if (hitDistSq < bestHitDistSq) {
99
+ bestHit = hit;
100
+ bestHitDistSq = hitDistSq;
101
+ }
102
+ }
103
+ }
104
+
105
+ return bestHit;
106
+ };
107
+
108
+ export const distanceSort = (a, b) => {
109
+ return a.distance - b.distance;
110
+ };
111
+
112
+ const _intersectTileScene = (tile, ray, intersects) => {
113
+ const scene = tile.cached.scene;
114
+
115
+ const lengthBefore = intersects.length;
116
+
117
+ scene.traverse(c => {
118
+ // We set the default raycast function to empty so t3d.js doesn't automatically cast against it
119
+ Object.getPrototypeOf(c).raycast.call(c, ray, intersects);
120
+ });
121
+
122
+ const lengthAfter = intersects.length;
123
+
124
+ // add the tile to intersects
125
+ if (lengthAfter > lengthBefore) {
126
+ for (let i = lengthBefore; i < lengthAfter; i++) {
127
+ intersects[i].tile = tile;
128
+ }
129
+ }
130
+ };
131
+
132
+ const _mat4_1 = new Matrix4();
133
+ const _ray_1 = new Ray();
134
+ const _vec3_1 = new Vector3();
135
+
136
+ const _hitArray = [];
@@ -0,0 +1,159 @@
1
+
2
+ export class LRUCache {
3
+
4
+ constructor({ maxSize = 800, minSize = 600, unloadPercent = 0.05, unloadPriorityCallback = defaultPriorityCallback }) {
5
+ // options
6
+ this.maxSize = maxSize;
7
+ this.minSize = minSize;
8
+ this.unloadPercent = unloadPercent;
9
+
10
+ // "itemSet" doubles as both the list of the full set of items currently
11
+ // stored in the cache (keys) as well as a map to the time the item was last
12
+ // used so it can be sorted appropriately.
13
+ this.itemSet = new Map();
14
+ this.itemList = [];
15
+ this.usedSet = new Set();
16
+ this.callbacks = new Map();
17
+
18
+ this.scheduled = false;
19
+
20
+ this.unloadPriorityCallback = unloadPriorityCallback;
21
+ }
22
+
23
+ isFull() {
24
+ return this.itemSet.size >= this.maxSize;
25
+ }
26
+
27
+ add(item, removeCb) {
28
+ const itemSet = this.itemSet;
29
+ if (itemSet.has(item)) {
30
+ return false;
31
+ }
32
+
33
+ if (this.isFull()) {
34
+ return false;
35
+ }
36
+
37
+ const usedSet = this.usedSet;
38
+ const itemList = this.itemList;
39
+ const callbacks = this.callbacks;
40
+ itemList.push(item);
41
+ usedSet.add(item);
42
+ itemSet.set(item, Date.now());
43
+ callbacks.set(item, removeCb);
44
+
45
+ return true;
46
+ }
47
+
48
+ remove(item) {
49
+ const usedSet = this.usedSet;
50
+ const itemSet = this.itemSet;
51
+ const itemList = this.itemList;
52
+ const callbacks = this.callbacks;
53
+
54
+ if (itemSet.has(item)) {
55
+ callbacks.get(item)(item);
56
+
57
+ const index = itemList.indexOf(item);
58
+ itemList.splice(index, 1);
59
+ usedSet.delete(item);
60
+ itemSet.delete(item);
61
+ callbacks.delete(item);
62
+
63
+ return true;
64
+ }
65
+
66
+ return false;
67
+ }
68
+
69
+ markUsed(item) {
70
+ const itemSet = this.itemSet;
71
+ const usedSet = this.usedSet;
72
+ if (!itemSet.has(item) || usedSet.has(item)) {
73
+ return false;
74
+ }
75
+
76
+ itemSet.set(item, Date.now());
77
+ usedSet.add(item);
78
+
79
+ return true;
80
+ }
81
+
82
+ markAllUnused() {
83
+ this.usedSet.clear();
84
+ }
85
+
86
+ unloadToMinSize() {
87
+ const unloadPercent = this.unloadPercent;
88
+ const targetSize = this.minSize;
89
+ const itemList = this.itemList;
90
+ const itemSet = this.itemSet;
91
+ const usedSet = this.usedSet;
92
+ const callbacks = this.callbacks;
93
+ const unused = itemList.length - usedSet.size;
94
+ const excess = itemList.length - targetSize;
95
+ const unloadPriorityCallback = this.unloadPriorityCallback;
96
+
97
+ if (excess <= 0 || unused <= 0) {
98
+ return false;
99
+ }
100
+
101
+ // used items should be at the end of the array
102
+ itemList.sort((a, b) => {
103
+ const usedA = usedSet.has(a);
104
+ const usedB = usedSet.has(b);
105
+ if (usedA && usedB) {
106
+ // If they're both used then don't bother moving them
107
+ return 0;
108
+ } else if (!usedA && !usedB) {
109
+ // Use the sort function otherwise
110
+ // higher priority should be further to the left
111
+ return unloadPriorityCallback(itemSet, b) - unloadPriorityCallback(itemSet, a);
112
+ } else {
113
+ // If one is used and the other is not move the used one towards the end of the array
114
+ return usedA ? 1 : -1;
115
+ }
116
+ });
117
+
118
+ // address corner cases where the minSize might be zero or smaller than maxSize - minSize,
119
+ // which would result in a very small or no items being unloaded.
120
+ const unusedExcess = Math.min(excess, unused);
121
+ const maxUnload = Math.max(targetSize * unloadPercent, unusedExcess * unloadPercent);
122
+ let nodesToUnload = Math.min(maxUnload, unused);
123
+ nodesToUnload = Math.ceil(nodesToUnload);
124
+
125
+ const removedItems = itemList.splice(0, nodesToUnload);
126
+ for (let i = 0, l = removedItems.length; i < l; i++) {
127
+ const item = removedItems[i];
128
+ callbacks.get(item)(item);
129
+ itemSet.delete(item);
130
+ callbacks.delete(item);
131
+ }
132
+
133
+ return true;
134
+ }
135
+
136
+ scheduleUnload(markAllUnused = true) {
137
+ if (this.scheduled) {
138
+ return false;
139
+ }
140
+
141
+ this.scheduled = true;
142
+ enqueueMicrotask(() => {
143
+ this.scheduled = false;
144
+ this.unloadToMinSize();
145
+ if (markAllUnused) {
146
+ this.markAllUnused();
147
+ }
148
+ });
149
+ }
150
+
151
+ }
152
+
153
+ const defaultPriorityCallback = (map, key) => {
154
+ return map.get(key);
155
+ };
156
+
157
+ const enqueueMicrotask = callback => {
158
+ Promise.resolve().then(callback);
159
+ };
@@ -0,0 +1,150 @@
1
+
2
+ import { Matrix4, Vector3 } from 't3d';
3
+ import { B3DMLoader } from '../loaders/B3DMLoader.js';
4
+ import { I3DMLoader } from '../loaders/I3DMLoader.js';
5
+ import { PNTSLoader } from '../loaders/PNTSLoader.js';
6
+ import { CMPTLoader } from '../loaders/CMPTLoader.js';
7
+ import { TileGLTFLoader } from '../loaders/TileGLTFLoader.js';
8
+
9
+ export class ModelLoader {
10
+
11
+ constructor(manager) {
12
+ const b3dmLoader = new B3DMLoader(manager);
13
+ const i3dmLoader = new I3DMLoader(manager);
14
+ const pntsLoader = new PNTSLoader(manager);
15
+ const cmptLoader = new CMPTLoader(manager);
16
+ const gltfLoader = new TileGLTFLoader(manager);
17
+
18
+ this._loaders = new Map([
19
+ ['b3dm', b3dmLoader],
20
+ ['i3dm', i3dmLoader],
21
+ ['pnts', pntsLoader],
22
+ ['cmpt', cmptLoader],
23
+ ['gltf', gltfLoader],
24
+ ['glb', gltfLoader]
25
+ ]);
26
+ }
27
+
28
+ setDRACOLoader(dracoLoader) {
29
+ this._loaders.get('b3dm').setDRACOLoader(dracoLoader);
30
+ this._loaders.get('i3dm').setDRACOLoader(dracoLoader);
31
+ this._loaders.get('cmpt').setDRACOLoader(dracoLoader);
32
+ this._loaders.get('gltf').setDRACOLoader(dracoLoader);
33
+ }
34
+
35
+ setKTX2Loader(ktx2Loader) {
36
+ this._loaders.get('b3dm').setKTX2Loader(ktx2Loader);
37
+ this._loaders.get('i3dm').setKTX2Loader(ktx2Loader);
38
+ this._loaders.get('cmpt').setKTX2Loader(ktx2Loader);
39
+ this._loaders.get('gltf').setKTX2Loader(ktx2Loader);
40
+ }
41
+
42
+ loadTileContent(buffer, tile, extension, tiles3D) {
43
+ tile._loadIndex = tile._loadIndex || 0;
44
+ tile._loadIndex++;
45
+
46
+ const uri = tile.content.uri;
47
+ const uriSplits = uri.split(/[\\\/]/g); // eslint-disable-line no-useless-escape
48
+ uriSplits.pop();
49
+ const workingPath = uriSplits.join('/');
50
+ const fetchOptions = tiles3D.fetchOptions;
51
+
52
+ const loadIndex = tile._loadIndex;
53
+ let promise = null;
54
+
55
+ const upAxis = tiles3D.rootTileSet.asset && tiles3D.rootTileSet.asset.gltfUpAxis || 'y';
56
+ const cached = tile.cached;
57
+ const cachedTransform = cached.transform;
58
+
59
+ switch (upAxis.toLowerCase()) {
60
+ case 'x':
61
+ mat4_1.makeRotationAxis(Y_AXIS, -Math.PI / 2);
62
+ break;
63
+ case 'y':
64
+ mat4_1.makeRotationAxis(X_AXIS, Math.PI / 2);
65
+ break;
66
+ case 'z':
67
+ mat4_1.identity();
68
+ break;
69
+ }
70
+
71
+ const loader = this._loaders.get(extension);
72
+
73
+ if (loader) {
74
+ const config = {
75
+ fetchOptions,
76
+ path: workingPath,
77
+ buffer
78
+ };
79
+
80
+ if (extension === 'b3dm' || extension === 'i3dm' || extension === 'cmpt') {
81
+ config.adjustmentTransform = mat4_1.clone();
82
+ }
83
+
84
+ promise = loader.load(uri, config);
85
+ } else {
86
+ console.warn(`TilesRenderer: Content type "${extension}" not supported.`);
87
+ promise = Promise.resolve(null);
88
+ }
89
+
90
+ return promise.then(resource => {
91
+ const scene = resource.root;
92
+
93
+ if (tile._loadIndex !== loadIndex || !scene) {
94
+ return;
95
+ }
96
+
97
+ // ensure the matrix is up to date in case the scene has a transform applied
98
+ scene.updateMatrix();
99
+
100
+ // apply the local up-axis correction rotation
101
+ // GLTFLoader seems to never set a transformation on the root scene object so
102
+ // any transformations applied to it can be assumed to be applied after load
103
+ // (such as applying RTC_CENTER) meaning they should happen _after_ the z-up
104
+ // rotation fix which is why "multiply" happens here.
105
+ if (extension === 'glb' || extension === 'gltf') {
106
+ scene.matrix.multiply(mat4_1);
107
+ }
108
+
109
+ scene.matrix.premultiply(cachedTransform);
110
+ scene.matrix.decompose(scene.position, scene.quaternion, scene.scale);
111
+
112
+ cached.scene = scene;
113
+ cached.featureTable = resource.featureTable;
114
+ cached.batchTable = resource.batchTable;
115
+
116
+ const materials = [];
117
+ const geometry = [];
118
+ const textures = [];
119
+ scene.traverse(c => {
120
+ if (c.geometry) {
121
+ geometry.push(c.geometry);
122
+ }
123
+
124
+ if (c.material) {
125
+ const material = c.material;
126
+ materials.push(c.material);
127
+
128
+ for (const key in material) {
129
+ const value = material[key];
130
+ if (value && value.isTexture) {
131
+ textures.push(value);
132
+ }
133
+ }
134
+ }
135
+ });
136
+
137
+ cached.materials = materials;
138
+ cached.geometry = geometry;
139
+ cached.textures = textures;
140
+
141
+ return scene;
142
+ });
143
+ }
144
+
145
+ }
146
+
147
+ const mat4_1 = new Matrix4();
148
+
149
+ const X_AXIS = new Vector3(1, 0, 0);
150
+ const Y_AXIS = new Vector3(0, 1, 0);