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,234 @@
|
|
|
1
|
+
import { Vector3, Matrix4, Triangle, Ray } from 't3d';
|
|
2
|
+
|
|
3
|
+
export class LineSegment {
|
|
4
|
+
|
|
5
|
+
constructor(startPoint = new Vector3(), endPoint = new Vector3()) {
|
|
6
|
+
this.startPoint = startPoint;
|
|
7
|
+
this.endPoint = endPoint;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
setPoints(startPoint, endPoint) {
|
|
11
|
+
this.startPoint.copy(startPoint);
|
|
12
|
+
this.endPoint.copy(endPoint);
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
copy(lineSegment) {
|
|
17
|
+
this.startPoint.copy(lineSegment.startPoint);
|
|
18
|
+
this.endPoint.copy(lineSegment.endPoint);
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
applyMatrix4(m) {
|
|
23
|
+
this.startPoint.applyMatrix4(m);
|
|
24
|
+
this.endPoint.applyMatrix4(m);
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getLength() {
|
|
29
|
+
return this.startPoint.distanceTo(this.endPoint);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getLengthSquared() {
|
|
33
|
+
return this.startPoint.distanceToSquared(this.endPoint);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getCenter(target) {
|
|
37
|
+
return target.addVectors(this.startPoint, this.endPoint).multiplyScalar(0.5);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getOBB(radius, target) {
|
|
41
|
+
const center = this.getCenter(_vec3_1);
|
|
42
|
+
const halfSize = _vec3_2.set(radius, radius, this.getLength() * 0.5 + radius); // expand box size by radius
|
|
43
|
+
|
|
44
|
+
const rotationMatrix4 = _mat4_1.identity().lookAtRH(this.startPoint, this.endPoint, _up);
|
|
45
|
+
|
|
46
|
+
target.box.min.subVectors(center, halfSize);
|
|
47
|
+
target.box.max.addVectors(center, halfSize);
|
|
48
|
+
target.rotation.setFromMatrix4(rotationMatrix4);
|
|
49
|
+
|
|
50
|
+
return target;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
closestLineToLineSegment(lineSegment, target) {
|
|
54
|
+
const lineVec = _lineVec1.subVectors(this.endPoint, this.startPoint);
|
|
55
|
+
const lineVec2 = _lineVec2.subVectors(lineSegment.endPoint, lineSegment.startPoint);
|
|
56
|
+
const r = _lineVec3.subVectors(this.startPoint, lineSegment.startPoint);
|
|
57
|
+
const a = lineVec.getLengthSquared();
|
|
58
|
+
const invA = 1.0 / a;
|
|
59
|
+
const e = lineVec2.getLengthSquared();
|
|
60
|
+
const f = lineVec2.dot(r);
|
|
61
|
+
const EPSILON = 1E-5;
|
|
62
|
+
let s, t;
|
|
63
|
+
|
|
64
|
+
if (a <= EPSILON && e <= EPSILON) {
|
|
65
|
+
// Both segments degenerate into points
|
|
66
|
+
target.startPoint.copy(this.startPoint);
|
|
67
|
+
target.endPoint.copy(lineSegment.startPoint);
|
|
68
|
+
return target;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (a <= EPSILON) {
|
|
72
|
+
// First segment degenerates into a point
|
|
73
|
+
s = 0.0;
|
|
74
|
+
t = f / e;
|
|
75
|
+
t = Math.min(Math.max(t, 0.0), 1.0);
|
|
76
|
+
} else {
|
|
77
|
+
const c = lineVec.dot(r);
|
|
78
|
+
if (e <= EPSILON) {
|
|
79
|
+
// Second segment degenerates into a point
|
|
80
|
+
t = 0.0;
|
|
81
|
+
s = Math.min(Math.max(-c * invA, 0.0), 1.0);
|
|
82
|
+
} else {
|
|
83
|
+
// The general nondegenerate case starts here
|
|
84
|
+
const b = lineVec.dot(lineVec2);
|
|
85
|
+
const denom = a * e - b * b;
|
|
86
|
+
// If segments not parallel, compute closest point on L1 to L2 and clamp to segment S1. Else pick arbitrary s (here 0)
|
|
87
|
+
if (denom !== 0.0) { s = Math.min(Math.max((b * f - c * e) / denom, 0.0), 1.0) } else { s = 0.0 }
|
|
88
|
+
// Compute point on L2 closest to S1(s) using
|
|
89
|
+
// t = Dot((P1 + D1 * s) - P2, D2) / Dot(D2, D2) = (b * s + f) / e
|
|
90
|
+
t = (b * s + f) / e;
|
|
91
|
+
// If t in [0,1] done. Else clamp t, recompute s for the new value of t using s = Dot((P2 + D2 * t) - P1, D1) / Dot(D1, D1) = (t * b - c) / a and clamp s to [0, 1]
|
|
92
|
+
if (t < 0.0) {
|
|
93
|
+
t = 0.0;
|
|
94
|
+
s = Math.min(Math.max(-c * invA, 0.0), 1.0);
|
|
95
|
+
} else if (t > 1.0) {
|
|
96
|
+
t = 1.0;
|
|
97
|
+
s = Math.min(Math.max((b - c) * invA, 0.0), 1.0);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
target.startPoint.addVectors(this.startPoint, lineVec.multiplyScalar(s));
|
|
103
|
+
target.endPoint.addVectors(lineSegment.startPoint, lineVec2.multiplyScalar(t));
|
|
104
|
+
return target;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
intersectTriangle(triangle, target) {
|
|
108
|
+
const lineVec = _lineVec0.subVectors(this.endPoint, this.startPoint).normalize();
|
|
109
|
+
const ray = _ray.set(this.startPoint, lineVec);
|
|
110
|
+
const backfaceCulling = false;
|
|
111
|
+
|
|
112
|
+
const intersect = ray.intersectTriangle(triangle.a, triangle.b, triangle.c, backfaceCulling, target);
|
|
113
|
+
if (intersect === null) return null;
|
|
114
|
+
|
|
115
|
+
const distance = this.startPoint.distanceTo(target);
|
|
116
|
+
const t = distance / this.getLength();
|
|
117
|
+
if (t >= 0.0 && t <= 1.0) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
closestLineToTriangle(triangle, target) {
|
|
124
|
+
let min = Infinity, d;
|
|
125
|
+
|
|
126
|
+
const intersectWithTriangle = this.intersectTriangle(triangle, _vec3_1);
|
|
127
|
+
if (intersectWithTriangle) {
|
|
128
|
+
target.startPoint.copy(_vec3_1);
|
|
129
|
+
target.endPoint.copy(_vec3_1);
|
|
130
|
+
return target;
|
|
131
|
+
} else {
|
|
132
|
+
const isPointAintri = Triangle.containsPoint(this.startPoint, triangle.a, triangle.b, triangle.c);
|
|
133
|
+
const isPointBintri = Triangle.containsPoint(this.endPoint, triangle.a, triangle.b, triangle.c);
|
|
134
|
+
|
|
135
|
+
// segment endpoint A and plane of triangle (when A projects inside V0V1V2)
|
|
136
|
+
let computed = false;
|
|
137
|
+
let a = NaN, b = NaN, c = NaN, nd = NaN;
|
|
138
|
+
if (isPointAintri) {
|
|
139
|
+
const lineVec1 = _lineVec1.subVectors(triangle.b, triangle.a);
|
|
140
|
+
const lineVec2 = _lineVec2.subVectors(triangle.c, triangle.a);
|
|
141
|
+
a = lineVec1.y * lineVec2.z - lineVec1.z * lineVec2.y;
|
|
142
|
+
b = lineVec1.z * lineVec2.x - lineVec1.x * lineVec2.z;
|
|
143
|
+
c = lineVec1.x * lineVec2.y - lineVec1.y * lineVec2.x;
|
|
144
|
+
const lineVec3 = _lineVec3.set(a, b, c);
|
|
145
|
+
computed = true;
|
|
146
|
+
nd = -lineVec3.normalize().dot(triangle.a);
|
|
147
|
+
|
|
148
|
+
d = lineVec3.dot(this.startPoint) + nd;
|
|
149
|
+
const l = d;
|
|
150
|
+
d *= d;
|
|
151
|
+
if (d < min) {
|
|
152
|
+
min = d;
|
|
153
|
+
target.startPoint.copy(this.startPoint);
|
|
154
|
+
target.endPoint.subVectors(this.startPoint, lineVec3.multiplyScalar(l));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// segment endpoint B and plane of triangle (when B projects inside V0V1V2)
|
|
159
|
+
if (isPointBintri) {
|
|
160
|
+
const lineVec3 = _lineVec3;
|
|
161
|
+
if (!computed) {
|
|
162
|
+
const lineVec1 = _lineVec1.subVectors(triangle.b, triangle.a);
|
|
163
|
+
const lineVec2 = _lineVec2.subVectors(triangle.c, triangle.a);
|
|
164
|
+
a = lineVec1.y * lineVec2.z - lineVec1.z * lineVec2.y;
|
|
165
|
+
b = lineVec1.z * lineVec2.x - lineVec1.x * lineVec2.z;
|
|
166
|
+
c = lineVec1.x * lineVec2.y - lineVec1.y * lineVec2.x;
|
|
167
|
+
lineVec3.set(a, b, c);
|
|
168
|
+
computed = true;
|
|
169
|
+
nd = -lineVec3.normalize().dot(triangle.a);
|
|
170
|
+
}
|
|
171
|
+
d = lineVec3.dot(this.endPoint) + nd;
|
|
172
|
+
const l = d;
|
|
173
|
+
d *= d;
|
|
174
|
+
if (d < min) {
|
|
175
|
+
min = d;
|
|
176
|
+
target.startPoint.copy(this.endPoint);
|
|
177
|
+
target.endPoint.subVectors(this.endPoint, lineVec3.multiplyScalar(l));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (isPointBintri && isPointAintri) {
|
|
182
|
+
return target;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// AB -> V0V1
|
|
186
|
+
_lineSegmentEdge.setPoints(triangle.a, triangle.b);
|
|
187
|
+
this.closestLineToLineSegment(_lineSegmentEdge, _tampTarget);
|
|
188
|
+
min = _tampTarget.getLength();
|
|
189
|
+
target.startPoint.copy(_tampTarget.startPoint);
|
|
190
|
+
target.endPoint.copy(_tampTarget.endPoint);
|
|
191
|
+
|
|
192
|
+
// AB -> V1V2
|
|
193
|
+
_lineSegmentEdge.setPoints(triangle.b, triangle.c);
|
|
194
|
+
this.closestLineToLineSegment(_lineSegmentEdge, _tampTarget);
|
|
195
|
+
d = _tampTarget.getLength();
|
|
196
|
+
if (d < min) {
|
|
197
|
+
min = d;
|
|
198
|
+
target.startPoint.copy(_tampTarget.startPoint);
|
|
199
|
+
target.endPoint.copy(_tampTarget.endPoint);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// AB -> V2V0
|
|
203
|
+
_lineSegmentEdge.setPoints(triangle.c, triangle.a);
|
|
204
|
+
this.closestLineToLineSegment(_lineSegmentEdge, _tampTarget);
|
|
205
|
+
d = _tampTarget.getLength();
|
|
206
|
+
if (d < min) {
|
|
207
|
+
min = d;
|
|
208
|
+
target.startPoint.copy(_tampTarget.startPoint);
|
|
209
|
+
target.endPoint.copy(_tampTarget.endPoint);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return target;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const _vec3_1 = new Vector3();
|
|
219
|
+
const _vec3_2 = new Vector3();
|
|
220
|
+
const _mat4_1 = new Matrix4();
|
|
221
|
+
|
|
222
|
+
const _up = new Vector3(0, 1, 0);
|
|
223
|
+
|
|
224
|
+
const _ray = new Ray();
|
|
225
|
+
|
|
226
|
+
const _lineVec0 = new Vector3();
|
|
227
|
+
|
|
228
|
+
const _lineVec1 = new Vector3();
|
|
229
|
+
const _lineVec2 = new Vector3();
|
|
230
|
+
const _lineVec3 = new Vector3();
|
|
231
|
+
|
|
232
|
+
const _lineSegmentEdge = new LineSegment();
|
|
233
|
+
|
|
234
|
+
const _tampTarget = new LineSegment();
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "t3d-3dtiles",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "An extension for 3D Tiles based on t3d.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./build/t3d.3dtiles.js",
|
|
7
|
+
"module": "./build/t3d.3dtiles.module.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./build/t3d.3dtiles.module.js",
|
|
10
|
+
"./src/*": "./src/*",
|
|
11
|
+
"./addons/*": "./examples/jsm/*"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/uinosoft/t3d-3dtiles"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"build",
|
|
19
|
+
"examples/jsm",
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"package.json",
|
|
22
|
+
"README.md",
|
|
23
|
+
"src"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"3dtiles",
|
|
27
|
+
"t3d",
|
|
28
|
+
"javascript",
|
|
29
|
+
"3d",
|
|
30
|
+
"webgl",
|
|
31
|
+
"webgl2",
|
|
32
|
+
"canvas",
|
|
33
|
+
"html5"
|
|
34
|
+
],
|
|
35
|
+
"author": "uino",
|
|
36
|
+
"license": "BSD-3-Clause",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@babel/core": "^7.18.10",
|
|
39
|
+
"@babel/preset-env": "^7.18.10",
|
|
40
|
+
"@rollup/plugin-babel": "^6.0.3",
|
|
41
|
+
"@rollup/plugin-terser": "^0.4.0",
|
|
42
|
+
"eslint": "^8.57.0",
|
|
43
|
+
"eslint-plugin-html": "^8.1.1",
|
|
44
|
+
"eslint-plugin-import": "^2.29.0",
|
|
45
|
+
"rollup": "^4.18.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"t3d": "^0.2.7"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"dev": "rollup -w -c",
|
|
52
|
+
"build": "rollup -c",
|
|
53
|
+
"lint": "eslint src",
|
|
54
|
+
"lint-fix": "eslint src --fix",
|
|
55
|
+
"lint-examples": "eslint examples --ext .html"
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/Tiles3D.js
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import { EventDispatcher, LoadingManager, Matrix4, Object3D } from 't3d';
|
|
2
|
+
import { traverseSet } from './utils/Utils.js';
|
|
3
|
+
import { raycastTraverse, raycastTraverseFirstHit, distanceSort } from './utils/IntersectionUtils.js';
|
|
4
|
+
import RequestState from './utils/RequestState.js';
|
|
5
|
+
import { CameraList } from './utils/CameraList.js';
|
|
6
|
+
import { TilesLoader } from './utils/TilesLoader.js';
|
|
7
|
+
import { ModelLoader } from './utils/ModelLoader.js';
|
|
8
|
+
import { schedulingTiles } from './utils/TilesScheduler.js';
|
|
9
|
+
|
|
10
|
+
export class Tiles3D extends Object3D {
|
|
11
|
+
|
|
12
|
+
constructor(url, manager = new LoadingManager()) {
|
|
13
|
+
super();
|
|
14
|
+
|
|
15
|
+
// options
|
|
16
|
+
|
|
17
|
+
this.fetchOptions = {};
|
|
18
|
+
this.errorTarget = 6.0;
|
|
19
|
+
this.errorThreshold = Infinity;
|
|
20
|
+
this.loadSiblings = true;
|
|
21
|
+
this.displayActiveTiles = false;
|
|
22
|
+
this.maxDepth = Infinity;
|
|
23
|
+
this.stopAtEmptyTiles = true;
|
|
24
|
+
|
|
25
|
+
this.preprocessURL = null;
|
|
26
|
+
manager.setURLModifier(url => {
|
|
27
|
+
if (this.preprocessURL) {
|
|
28
|
+
return this.preprocessURL(url);
|
|
29
|
+
} else {
|
|
30
|
+
return url;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
this.manager = manager;
|
|
34
|
+
|
|
35
|
+
// stats
|
|
36
|
+
|
|
37
|
+
this.stats = {
|
|
38
|
+
parsing: 0,
|
|
39
|
+
downloading: 0,
|
|
40
|
+
failed: 0,
|
|
41
|
+
inFrustum: 0,
|
|
42
|
+
used: 0,
|
|
43
|
+
active: 0,
|
|
44
|
+
visible: 0
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
this.frameCount = 0;
|
|
48
|
+
|
|
49
|
+
this.activeTiles = new Set();
|
|
50
|
+
this.visibleTiles = new Set();
|
|
51
|
+
|
|
52
|
+
// internals
|
|
53
|
+
|
|
54
|
+
this._rootURL = url;
|
|
55
|
+
this._rootTileSet = null;
|
|
56
|
+
|
|
57
|
+
this._autoDisableRendererCulling = true;
|
|
58
|
+
|
|
59
|
+
this.$cameras = new CameraList();
|
|
60
|
+
this.$tilesLoader = new TilesLoader();
|
|
61
|
+
this.$modelLoader = new ModelLoader(manager);
|
|
62
|
+
this.$events = new EventDispatcher();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get rootURL() {
|
|
66
|
+
return this._rootURL;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get rootTileSet() {
|
|
70
|
+
const rootTileSet = this._rootTileSet;
|
|
71
|
+
|
|
72
|
+
if (!rootTileSet) {
|
|
73
|
+
const url = this._rootURL;
|
|
74
|
+
this._rootTileSet = this.$tilesLoader.fetchTileSet(this.preprocessURL ? this.preprocessURL(url) : url, null, this.fetchOptions)
|
|
75
|
+
.then(json => {
|
|
76
|
+
this._rootTileSet = json;
|
|
77
|
+
})
|
|
78
|
+
.then(json => {
|
|
79
|
+
// Push this onto the end of the event stack to ensure this runs
|
|
80
|
+
// after the base renderer has placed the provided json where it
|
|
81
|
+
// needs to be placed and is ready for an update.
|
|
82
|
+
Promise.resolve().then(() => {
|
|
83
|
+
// TODO dispatch event only if this is the root tileset for now, we can
|
|
84
|
+
// dispatch this event for all tilesets in the future
|
|
85
|
+
_TileSetLoadedEvent.json = json;
|
|
86
|
+
_TileSetLoadedEvent.url = url;
|
|
87
|
+
this.$events.dispatchEvent(_TileSetLoadedEvent);
|
|
88
|
+
});
|
|
89
|
+
})
|
|
90
|
+
.catch(err => {
|
|
91
|
+
console.error(err);
|
|
92
|
+
this._rootTileSet = err;
|
|
93
|
+
});
|
|
94
|
+
return null;
|
|
95
|
+
} else if (rootTileSet instanceof Promise || rootTileSet instanceof Error) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return rootTileSet;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
get root() {
|
|
103
|
+
const rootTileSet = this.rootTileSet;
|
|
104
|
+
return rootTileSet ? rootTileSet.root : null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get autoDisableRendererCulling() {
|
|
108
|
+
return this._autoDisableRendererCulling;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
set autoDisableRendererCulling(value) {
|
|
112
|
+
if (this._autoDisableRendererCulling !== value) {
|
|
113
|
+
super._autoDisableRendererCulling = value;
|
|
114
|
+
this.traverse(tile => {
|
|
115
|
+
const scene = tile.cached.scene;
|
|
116
|
+
if (scene) {
|
|
117
|
+
scene.traverse(c => {
|
|
118
|
+
c.frustumCulled = c[INITIAL_FRUSTUM_CULLED] && !value;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
setDRACOLoader(dracoLoader) {
|
|
126
|
+
this.$modelLoader.setDRACOLoader(dracoLoader);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
setKTX2Loader(ktx2Loader) {
|
|
130
|
+
this.$modelLoader.setKTX2Loader(ktx2Loader);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
addEventListener(type, listener, thisObject) {
|
|
134
|
+
this.$events.addEventListener(type, listener, thisObject);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
removeEventListener(type, listener, thisObject) {
|
|
138
|
+
this.$events.removeEventListener(type, listener, thisObject);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
update() {
|
|
142
|
+
const rootTile = this.root;
|
|
143
|
+
if (!rootTile) return;
|
|
144
|
+
|
|
145
|
+
const { stats } = this;
|
|
146
|
+
stats.inFrustum = 0;
|
|
147
|
+
stats.used = 0;
|
|
148
|
+
stats.active = 0;
|
|
149
|
+
stats.visible = 0;
|
|
150
|
+
|
|
151
|
+
this.frameCount++;
|
|
152
|
+
|
|
153
|
+
this.$cameras.updateInfos(this.worldMatrix);
|
|
154
|
+
|
|
155
|
+
schedulingTiles(rootTile, this);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
addCamera(camera) {
|
|
159
|
+
return this.$cameras.add(camera);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
removeCamera(camera) {
|
|
163
|
+
return this.$cameras.remove(camera);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
resize(width, height) {
|
|
167
|
+
this.$cameras.setResolution(width, height);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
raycast(ray, intersects) {
|
|
171
|
+
if (!this.root) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
raycastTraverse(this.root, this, ray, intersects);
|
|
176
|
+
|
|
177
|
+
intersects.sort(distanceSort);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
raycastFirst(ray) {
|
|
181
|
+
if (!this.root) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return raycastTraverseFirstHit(this.root, this, ray);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
getBoundingBox(box) {
|
|
189
|
+
if (!this.root) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const boundingVolume = this.root.cached.boundingVolume;
|
|
194
|
+
|
|
195
|
+
if (boundingVolume) {
|
|
196
|
+
boundingVolume.getBoundingBox(box);
|
|
197
|
+
return true;
|
|
198
|
+
} else {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
getOrientedBoundingBox(targetBox, targetMatrix) {
|
|
204
|
+
if (!this.root) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const boundingVolume = this.root.cached.boundingVolume;
|
|
209
|
+
|
|
210
|
+
if (boundingVolume) {
|
|
211
|
+
boundingVolume.getOrientedBoundingBox(targetBox, targetMatrix);
|
|
212
|
+
return true;
|
|
213
|
+
} else {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
getBoundingSphere(sphere) {
|
|
219
|
+
if (!this.root) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const boundingVolume = this.root.cached.boundingVolume;
|
|
224
|
+
|
|
225
|
+
if (boundingVolume) {
|
|
226
|
+
boundingVolume.getBoundingSphere(sphere);
|
|
227
|
+
return true;
|
|
228
|
+
} else {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
traverse(beforecb, aftercb) {
|
|
234
|
+
const rootTile = this.root;
|
|
235
|
+
if (!rootTile) return;
|
|
236
|
+
traverseSet(rootTile, beforecb, aftercb);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
resetFailedTiles() {
|
|
240
|
+
const stats = this.stats;
|
|
241
|
+
if (stats.failed === 0) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.traverse(tile => {
|
|
246
|
+
if (tile.__loadingState === RequestState.FAILED) {
|
|
247
|
+
tile.__loadingState = RequestState.UNLOADED;
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
stats.failed = 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
dispose() {
|
|
255
|
+
const lruCache = this.$tilesLoader.lruCache;
|
|
256
|
+
this.traverse(tile => {
|
|
257
|
+
lruCache.remove(tile);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
this.stats = {
|
|
261
|
+
parsing: 0,
|
|
262
|
+
downloading: 0,
|
|
263
|
+
failed: 0,
|
|
264
|
+
inFrustum: 0,
|
|
265
|
+
used: 0,
|
|
266
|
+
active: 0,
|
|
267
|
+
visible: 0
|
|
268
|
+
};
|
|
269
|
+
this.frameCount = 0;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// override Object3D methods
|
|
273
|
+
updateMatrix(force) {
|
|
274
|
+
if (this.matrixAutoUpdate || this.matrixNeedsUpdate) {
|
|
275
|
+
this.matrix.transform(this.position, this.scale, this.quaternion);
|
|
276
|
+
|
|
277
|
+
this.matrixNeedsUpdate = false;
|
|
278
|
+
this.worldMatrixNeedsUpdate = true;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (this.worldMatrixNeedsUpdate || force) {
|
|
282
|
+
if (this.parent === null) {
|
|
283
|
+
tempMat.copy(this.matrix);
|
|
284
|
+
} else {
|
|
285
|
+
tempMat.multiplyMatrices(this.parent.worldMatrix, this.matrix);
|
|
286
|
+
}
|
|
287
|
+
this.worldMatrixNeedsUpdate = false;
|
|
288
|
+
|
|
289
|
+
if (!matrixEquals(tempMat, this.worldMatrix)) {
|
|
290
|
+
this.worldMatrix.copy(tempMat);
|
|
291
|
+
|
|
292
|
+
// update children
|
|
293
|
+
// the children will not have to change unless the parent group has updated
|
|
294
|
+
const children = this.children;
|
|
295
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
296
|
+
children[i].updateMatrix();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
$parseTile(buffer, tile, extension) {
|
|
303
|
+
return this.$modelLoader.loadTileContent(buffer, tile, extension, this)
|
|
304
|
+
.then(scene => {
|
|
305
|
+
scene.traverse(c => {
|
|
306
|
+
c[INITIAL_FRUSTUM_CULLED] = c.frustumCulled; // store initial value
|
|
307
|
+
c.frustumCulled = c.frustumCulled && !this._autoDisableRendererCulling;
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
_TileLoadedEvent.scene = scene;
|
|
311
|
+
_TileLoadedEvent.tile = tile;
|
|
312
|
+
this.$events.dispatchEvent(_TileLoadedEvent);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
$setTileVisible(tile, visible) {
|
|
317
|
+
const scene = tile.cached.scene;
|
|
318
|
+
if (!scene) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const visibleTiles = this.visibleTiles;
|
|
322
|
+
if (visible) {
|
|
323
|
+
this.add(scene);
|
|
324
|
+
visibleTiles.add(tile);
|
|
325
|
+
scene.updateMatrix(true); // TODO: remove this?
|
|
326
|
+
} else {
|
|
327
|
+
this.remove(scene);
|
|
328
|
+
visibleTiles.delete(tile);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
_TileVisibilityChangedEvent.scene = scene;
|
|
332
|
+
_TileVisibilityChangedEvent.tile = tile;
|
|
333
|
+
_TileVisibilityChangedEvent.visible = visible;
|
|
334
|
+
this.$events.dispatchEvent(_TileVisibilityChangedEvent);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
$setTileActive(tile, active) {
|
|
338
|
+
const activeTiles = this.activeTiles;
|
|
339
|
+
if (active) {
|
|
340
|
+
activeTiles.add(tile);
|
|
341
|
+
} else {
|
|
342
|
+
activeTiles.delete(tile);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
$disposeTile(tile) {
|
|
347
|
+
// This could get called before the tile has finished downloading
|
|
348
|
+
const cached = tile.cached;
|
|
349
|
+
if (cached.scene) {
|
|
350
|
+
const materials = cached.materials;
|
|
351
|
+
const geometry = cached.geometry;
|
|
352
|
+
const textures = cached.textures;
|
|
353
|
+
|
|
354
|
+
for (let i = 0, l = geometry.length; i < l; i++) {
|
|
355
|
+
geometry[i].dispose();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
for (let i = 0, l = materials.length; i < l; i++) {
|
|
359
|
+
materials[i].dispose();
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
for (let i = 0, l = textures.length; i < l; i++) {
|
|
363
|
+
const texture = textures[i];
|
|
364
|
+
texture.dispose();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
_TileDisposedEvent.scene = cached.scene;
|
|
368
|
+
_TileDisposedEvent.tile = tile;
|
|
369
|
+
this.$events.dispatchEvent(_TileDisposedEvent);
|
|
370
|
+
|
|
371
|
+
cached.scene = null;
|
|
372
|
+
cached.materials = null;
|
|
373
|
+
cached.textures = null;
|
|
374
|
+
cached.geometry = null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
tile._loadIndex++;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const INITIAL_FRUSTUM_CULLED = Symbol('INITIAL_FRUSTUM_CULLED');
|
|
383
|
+
|
|
384
|
+
const _TileSetLoadedEvent = { type: 'TileSetLoaded', json: null, url: null };
|
|
385
|
+
const _TileLoadedEvent = { type: 'TileLoaded', scene: null, tile: null };
|
|
386
|
+
const _TileDisposedEvent = { type: 'TileDisposed', scene: null, tile: null };
|
|
387
|
+
const _TileVisibilityChangedEvent = { type: 'TileVisibilityChanged', scene: null, tile: null, visible: false };
|
|
388
|
+
|
|
389
|
+
const tempMat = new Matrix4();
|
|
390
|
+
|
|
391
|
+
const matrixEquals = (matrixA, matrixB, epsilon = Number.EPSILON) => {
|
|
392
|
+
const te = matrixA.elements;
|
|
393
|
+
const me = matrixB.elements;
|
|
394
|
+
|
|
395
|
+
for (let i = 0; i < 16; i++) {
|
|
396
|
+
if (Math.abs(te[i] - me[i]) > epsilon) {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return true;
|
|
402
|
+
};
|