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,30 @@
|
|
|
1
|
+
const CesiumIon = {};
|
|
2
|
+
|
|
3
|
+
CesiumIon.fetchAssetJson = async function(assetId, accessToken) {
|
|
4
|
+
const url = new URL(`https://api.cesium.com/v1/assets/${assetId}/endpoint`);
|
|
5
|
+
url.searchParams.append('access_token', accessToken);
|
|
6
|
+
|
|
7
|
+
const res = await fetch(url, { mode: 'cors' });
|
|
8
|
+
|
|
9
|
+
if (!res.ok) throw `${res.status} : ${res.statusText}`;
|
|
10
|
+
|
|
11
|
+
return await res.json();
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
CesiumIon.initTiles3D = function(tiles3D, assetJson) {
|
|
15
|
+
const assetVersion = new URL(assetJson.url).searchParams.get('v');
|
|
16
|
+
|
|
17
|
+
tiles3D.fetchOptions.mode = 'cors';
|
|
18
|
+
tiles3D.fetchOptions.headers = {};
|
|
19
|
+
tiles3D.fetchOptions.headers.Authorization = `Bearer ${assetJson.accessToken}`;
|
|
20
|
+
|
|
21
|
+
tiles3D.preprocessURL = uri => {
|
|
22
|
+
uri = new URL(uri);
|
|
23
|
+
if (/^http/.test(uri.protocol)) {
|
|
24
|
+
uri.searchParams.append('v', assetVersion);
|
|
25
|
+
}
|
|
26
|
+
return uri.toString();
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default CesiumIon;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { PBRMaterial, PointsMaterial, SHADING_TYPE, DRAW_MODE, Sphere } from 't3d';
|
|
2
|
+
import { InstancedPBRMaterial, InstancedBasicMaterial } from 't3d-3dtiles';
|
|
3
|
+
import { Tiles3DHelper } from './helpers/Tiles3DHelper.js';
|
|
4
|
+
|
|
5
|
+
export class Tiles3DDebugger {
|
|
6
|
+
|
|
7
|
+
constructor(tiles3D) {
|
|
8
|
+
this.helper = new Tiles3DHelper(tiles3D);
|
|
9
|
+
tiles3D.add(this.helper);
|
|
10
|
+
|
|
11
|
+
this.colorMode = NONE;
|
|
12
|
+
|
|
13
|
+
this.maxDebugDepth = -1;
|
|
14
|
+
this.maxDebugDistance = -1;
|
|
15
|
+
this.maxDebugError = -1;
|
|
16
|
+
|
|
17
|
+
this.customColorCallback = null;
|
|
18
|
+
|
|
19
|
+
this.getDebugColor = (value, target) => {
|
|
20
|
+
target.setRGB(value, value, value);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let extremeDebugDepth = -1;
|
|
24
|
+
let extremeDebugError = -1;
|
|
25
|
+
|
|
26
|
+
tiles3D.addEventListener('TileSetLoaded', ({ json, url }) => {
|
|
27
|
+
// only update for the root tileset
|
|
28
|
+
|
|
29
|
+
if (url !== tiles3D.rootURL) return;
|
|
30
|
+
|
|
31
|
+
// initialize the extreme values of the hierarchy
|
|
32
|
+
|
|
33
|
+
let maxDepth = -1;
|
|
34
|
+
tiles3D.traverse(tile => {
|
|
35
|
+
maxDepth = Math.max(maxDepth, tile.__depth);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
let maxError = -1;
|
|
39
|
+
tiles3D.traverse(tile => {
|
|
40
|
+
maxError = Math.max(maxError, tile.cached.geometricError);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
extremeDebugDepth = maxDepth;
|
|
44
|
+
extremeDebugError = maxError;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
this.update = () => {
|
|
48
|
+
if (!tiles3D.root) return;
|
|
49
|
+
|
|
50
|
+
// get max values to use for materials
|
|
51
|
+
let maxDepth = -1;
|
|
52
|
+
if (this.maxDebugDepth === -1) {
|
|
53
|
+
maxDepth = extremeDebugDepth;
|
|
54
|
+
} else {
|
|
55
|
+
maxDepth = this.maxDebugDepth;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let maxError = -1;
|
|
59
|
+
if (this.maxDebugError === -1) {
|
|
60
|
+
maxError = extremeDebugError;
|
|
61
|
+
} else {
|
|
62
|
+
maxError = this.maxDebugError;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let maxDistance = -1;
|
|
66
|
+
if (this.maxDebugDistance === -1) {
|
|
67
|
+
const boundingVolume = tiles3D.root.cached.boundingVolume;
|
|
68
|
+
const rootSphere = boundingVolume.getBoundingSphere(_sphere_1);
|
|
69
|
+
maxDistance = rootSphere.radius;
|
|
70
|
+
} else {
|
|
71
|
+
maxDistance = this.maxDebugDistance;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const errorTarget = tiles3D.errorTarget;
|
|
75
|
+
const colorMode = this.colorMode;
|
|
76
|
+
const visibleTiles = tiles3D.visibleTiles;
|
|
77
|
+
|
|
78
|
+
visibleTiles.forEach(tile => {
|
|
79
|
+
const scene = tile.cached.scene;
|
|
80
|
+
|
|
81
|
+
// create a random color per-tile
|
|
82
|
+
let h, s, l;
|
|
83
|
+
if (colorMode === RANDOM_COLOR) {
|
|
84
|
+
h = Math.random();
|
|
85
|
+
s = 0.5 + Math.random() * 0.5;
|
|
86
|
+
l = 0.375 + Math.random() * 0.25;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
scene.traverse(c => {
|
|
90
|
+
if (!c[ORIGINAL_MATERIAL]) {
|
|
91
|
+
c[ORIGINAL_MATERIAL] = c.material;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (colorMode === RANDOM_NODE_COLOR) {
|
|
95
|
+
h = Math.random();
|
|
96
|
+
s = 0.5 + Math.random() * 0.5;
|
|
97
|
+
l = 0.375 + Math.random() * 0.25;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (c.material) {
|
|
101
|
+
const originalMaterial = c[ORIGINAL_MATERIAL];
|
|
102
|
+
|
|
103
|
+
if (colorMode === NONE && c.material !== originalMaterial) {
|
|
104
|
+
c.material.dispose();
|
|
105
|
+
c.material = c[ORIGINAL_MATERIAL];
|
|
106
|
+
} else if (colorMode !== NONE && c.material === originalMaterial) {
|
|
107
|
+
if (c.material.drawMode === DRAW_MODE.POINTS) {
|
|
108
|
+
const pointsMaterial = new PointsMaterial();
|
|
109
|
+
pointsMaterial.size = originalMaterial.size;
|
|
110
|
+
pointsMaterial.sizeAttenuation = originalMaterial.sizeAttenuation;
|
|
111
|
+
c.material = pointsMaterial;
|
|
112
|
+
} else {
|
|
113
|
+
if (c.material.isInstancedPBRMaterial) {
|
|
114
|
+
c.material = new InstancedPBRMaterial();
|
|
115
|
+
} else if (c.material.isInstancedBasicMaterial) {
|
|
116
|
+
c.material = new InstancedBasicMaterial();
|
|
117
|
+
} else {
|
|
118
|
+
c.material = new PBRMaterial();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
c.material.shading = SHADING_TYPE.FLAT_SHADING;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (colorMode !== RANDOM_COLOR) {
|
|
126
|
+
delete c.material[HAS_RANDOM_COLOR];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (colorMode !== RANDOM_NODE_COLOR) {
|
|
130
|
+
delete c.material[HAS_RANDOM_NODE_COLOR];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
switch (colorMode) {
|
|
134
|
+
case DEPTH: {
|
|
135
|
+
const val = tile.__depth / maxDepth;
|
|
136
|
+
this.getDebugColor(val, c.material.diffuse);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case RELATIVE_DEPTH: {
|
|
140
|
+
const val = tile.__depthFromRenderedParent / maxDepth;
|
|
141
|
+
this.getDebugColor(val, c.material.diffuse);
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
case SCREEN_ERROR: {
|
|
145
|
+
const val = tile.__error / errorTarget;
|
|
146
|
+
if (val > 1.0) {
|
|
147
|
+
c.material.diffuse.setRGB(1.0, 0.0, 0.0);
|
|
148
|
+
} else {
|
|
149
|
+
this.getDebugColor(val, c.material.diffuse);
|
|
150
|
+
}
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case GEOMETRIC_ERROR: {
|
|
154
|
+
const val = Math.min(tile.cached.geometricError / maxError, 1);
|
|
155
|
+
this.getDebugColor(val, c.material.diffuse);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case DISTANCE: {
|
|
159
|
+
// We don't update the distance if the geometric error is 0.0 so
|
|
160
|
+
// it will always be black.
|
|
161
|
+
const val = Math.min(tile.__distanceFromCamera / maxDistance, 1);
|
|
162
|
+
this.getDebugColor(val, c.material.diffuse);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case IS_LEAF: {
|
|
166
|
+
if (!tile.children || tile.children.length === 0) {
|
|
167
|
+
this.getDebugColor(1.0, c.material.diffuse);
|
|
168
|
+
} else {
|
|
169
|
+
this.getDebugColor(0.0, c.material.diffuse);
|
|
170
|
+
}
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
case RANDOM_NODE_COLOR: {
|
|
174
|
+
if (!c.material[HAS_RANDOM_NODE_COLOR]) {
|
|
175
|
+
c.material.diffuse.setHSL(h, s, l);
|
|
176
|
+
c.material[HAS_RANDOM_NODE_COLOR] = true;
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case RANDOM_COLOR: {
|
|
181
|
+
if (!c.material[HAS_RANDOM_COLOR]) {
|
|
182
|
+
c.material.diffuse.setHSL(h, s, l);
|
|
183
|
+
c.material[HAS_RANDOM_COLOR] = true;
|
|
184
|
+
}
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case CUSTOM_COLOR: {
|
|
188
|
+
if (this.customColorCallback) {
|
|
189
|
+
this.customColorCallback(tile, c);
|
|
190
|
+
} else {
|
|
191
|
+
console.warn('Tiles3DDebugger: customColorCallback not defined');
|
|
192
|
+
}
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const _sphere_1 = new Sphere();
|
|
205
|
+
|
|
206
|
+
const ORIGINAL_MATERIAL = Symbol('ORIGINAL_MATERIAL');
|
|
207
|
+
const HAS_RANDOM_COLOR = Symbol('HAS_RANDOM_COLOR');
|
|
208
|
+
const HAS_RANDOM_NODE_COLOR = Symbol('HAS_RANDOM_NODE_COLOR');
|
|
209
|
+
|
|
210
|
+
export const NONE = 0;
|
|
211
|
+
export const SCREEN_ERROR = 1;
|
|
212
|
+
export const GEOMETRIC_ERROR = 2;
|
|
213
|
+
export const DISTANCE = 3;
|
|
214
|
+
export const DEPTH = 4;
|
|
215
|
+
export const RELATIVE_DEPTH = 5;
|
|
216
|
+
export const IS_LEAF = 6;
|
|
217
|
+
export const RANDOM_COLOR = 7;
|
|
218
|
+
export const RANDOM_NODE_COLOR = 8;
|
|
219
|
+
export const CUSTOM_COLOR = 9;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as t3d from 't3d';
|
|
2
|
+
|
|
3
|
+
export function setTiles3DToOrigin(tiles3D, parent) {
|
|
4
|
+
const sphere = new t3d.Sphere();
|
|
5
|
+
tiles3D.getBoundingSphere(sphere);
|
|
6
|
+
|
|
7
|
+
const position = sphere.center;
|
|
8
|
+
|
|
9
|
+
const surfaceDirection = position.clone().normalize();
|
|
10
|
+
const up = new t3d.Vector3(0, 1, 0);
|
|
11
|
+
const rotationToNorthPole = rotationBetweenDirections(surfaceDirection, up);
|
|
12
|
+
|
|
13
|
+
parent.quaternion.x = rotationToNorthPole.x;
|
|
14
|
+
parent.quaternion.y = rotationToNorthPole.y;
|
|
15
|
+
parent.quaternion.z = rotationToNorthPole.z;
|
|
16
|
+
parent.quaternion.w = rotationToNorthPole.w;
|
|
17
|
+
|
|
18
|
+
tiles3D.position.sub(position);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function rotationBetweenDirections(dir1, dir2) {
|
|
22
|
+
const rotation = new t3d.Quaternion();
|
|
23
|
+
const a = new t3d.Vector3();
|
|
24
|
+
a.crossVectors(dir1, dir2);
|
|
25
|
+
rotation.x = a.x;
|
|
26
|
+
rotation.y = a.y;
|
|
27
|
+
rotation.z = a.z;
|
|
28
|
+
rotation.w = 1 + dir1.clone().dot(dir2);
|
|
29
|
+
rotation.normalize();
|
|
30
|
+
|
|
31
|
+
return rotation;
|
|
32
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Object3D, SphereGeometry, BasicMaterial, Mesh, Geometry, Buffer, Attribute, DRAW_MODE, Vector3 } from 't3d';
|
|
2
|
+
|
|
3
|
+
export class LineSegmentHelper extends Object3D {
|
|
4
|
+
|
|
5
|
+
constructor(lineSegment, pointRadius = 1, pointColor = 0x00ffff, lineColor = 0x00ffff) {
|
|
6
|
+
super();
|
|
7
|
+
|
|
8
|
+
// create start and end points
|
|
9
|
+
|
|
10
|
+
const pointGeometry = new SphereGeometry(1);
|
|
11
|
+
const pointMaterial = new BasicMaterial();
|
|
12
|
+
|
|
13
|
+
this.start = new Mesh(pointGeometry, pointMaterial);
|
|
14
|
+
this.start.scale.setScalar(pointRadius);
|
|
15
|
+
this.add(this.start);
|
|
16
|
+
|
|
17
|
+
this.end = new Mesh(pointGeometry, pointMaterial);
|
|
18
|
+
this.end.scale.setScalar(pointRadius);
|
|
19
|
+
this.add(this.end);
|
|
20
|
+
|
|
21
|
+
// create line
|
|
22
|
+
|
|
23
|
+
const lineArray = new Float32Array([0, 0, -0.5, 0, 0, 0.5]);
|
|
24
|
+
const lineGeometry = new Geometry();
|
|
25
|
+
lineGeometry.addAttribute('a_Position', new Attribute(new Buffer(lineArray, 3)));
|
|
26
|
+
lineGeometry.computeBoundingBox();
|
|
27
|
+
lineGeometry.computeBoundingSphere();
|
|
28
|
+
|
|
29
|
+
const lineMaterial = new BasicMaterial();
|
|
30
|
+
lineMaterial.drawMode = DRAW_MODE.LINES;
|
|
31
|
+
|
|
32
|
+
this.line = new Mesh(lineGeometry, lineMaterial);
|
|
33
|
+
this.line.raycast = () => {}; // disable raycasting
|
|
34
|
+
this.add(this.line);
|
|
35
|
+
|
|
36
|
+
//
|
|
37
|
+
|
|
38
|
+
this.lineSegment = lineSegment;
|
|
39
|
+
|
|
40
|
+
this.setPointColor(pointColor);
|
|
41
|
+
this.setLineColor(lineColor);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setPointColor(color) {
|
|
45
|
+
// both points share the same material
|
|
46
|
+
// so we only need to update one of them
|
|
47
|
+
this.start.material.diffuse.setHex(color);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setLineColor(color) {
|
|
51
|
+
this.line.material.diffuse.setHex(color);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
updateMatrix(force) {
|
|
55
|
+
const { lineSegment } = this;
|
|
56
|
+
const { startPoint, endPoint } = lineSegment;
|
|
57
|
+
|
|
58
|
+
// TODO set center to group position
|
|
59
|
+
|
|
60
|
+
this.start.position.copy(startPoint);
|
|
61
|
+
this.end.position.copy(endPoint);
|
|
62
|
+
|
|
63
|
+
lineSegment.getCenter(this.line.position);
|
|
64
|
+
this.line.scale.z = lineSegment.getLength();
|
|
65
|
+
_vec3_1.subVectors(endPoint, startPoint).normalize();
|
|
66
|
+
this.line.quaternion.setFromUnitVectors(_zAxis, _vec3_1);
|
|
67
|
+
|
|
68
|
+
super.updateMatrix(force);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const _vec3_1 = new Vector3();
|
|
74
|
+
const _zAxis = new Vector3(0, 0, 1);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BasicMaterial, Mesh, Geometry, Buffer, Attribute, DRAW_MODE } from 't3d';
|
|
2
|
+
|
|
3
|
+
export class OBBHelper extends Mesh {
|
|
4
|
+
|
|
5
|
+
constructor(obb, color = 0xffff00) {
|
|
6
|
+
const lineBoxVertices = new Float32Array([
|
|
7
|
+
-0.5, -0.5, -0.5, 0.5, -0.5, -0.5,
|
|
8
|
+
0.5, -0.5, -0.5, 0.5, 0.5, -0.5,
|
|
9
|
+
0.5, 0.5, -0.5, -0.5, 0.5, -0.5,
|
|
10
|
+
-0.5, 0.5, -0.5, -0.5, -0.5, -0.5,
|
|
11
|
+
-0.5, -0.5, 0.5, 0.5, -0.5, 0.5,
|
|
12
|
+
0.5, -0.5, 0.5, 0.5, 0.5, 0.5,
|
|
13
|
+
0.5, 0.5, 0.5, -0.5, 0.5, 0.5,
|
|
14
|
+
-0.5, 0.5, 0.5, -0.5, -0.5, 0.5,
|
|
15
|
+
-0.5, -0.5, -0.5, -0.5, -0.5, 0.5,
|
|
16
|
+
0.5, -0.5, -0.5, 0.5, -0.5, 0.5,
|
|
17
|
+
0.5, 0.5, -0.5, 0.5, 0.5, 0.5,
|
|
18
|
+
-0.5, 0.5, -0.5, -0.5, 0.5, 0.5
|
|
19
|
+
]);
|
|
20
|
+
const lineBoxGeometry = new Geometry();
|
|
21
|
+
lineBoxGeometry.addAttribute('a_Position', new Attribute(new Buffer(lineBoxVertices, 3)));
|
|
22
|
+
lineBoxGeometry.computeBoundingBox();
|
|
23
|
+
lineBoxGeometry.computeBoundingSphere();
|
|
24
|
+
|
|
25
|
+
const lineMaterial = new BasicMaterial();
|
|
26
|
+
lineMaterial.drawMode = DRAW_MODE.LINES;
|
|
27
|
+
|
|
28
|
+
super(lineBoxGeometry, lineMaterial);
|
|
29
|
+
|
|
30
|
+
this.obb = obb;
|
|
31
|
+
|
|
32
|
+
this.setColor(color);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setColor(color) {
|
|
36
|
+
this.material.diffuse.setHex(color);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
updateMatrix(force) {
|
|
40
|
+
const { box, rotation } = this.obb;
|
|
41
|
+
box.getCenter(this.position);
|
|
42
|
+
box.getSize(this.scale);
|
|
43
|
+
this.quaternion.setFromRotationMatrix(this.matrix.setFromMatrix3(rotation));
|
|
44
|
+
|
|
45
|
+
super.updateMatrix(force);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Color3, Object3D } from 't3d';
|
|
2
|
+
import { Box3Helper } from 't3d/addons/objects/Box3Helper.js';
|
|
3
|
+
import { SphereHelper } from 't3d/addons/objects/SphereHelper.js';
|
|
4
|
+
|
|
5
|
+
export class Tiles3DHelper extends Object3D {
|
|
6
|
+
|
|
7
|
+
constructor(tiles3D) {
|
|
8
|
+
super();
|
|
9
|
+
|
|
10
|
+
const boxGroup = new Object3D();
|
|
11
|
+
boxGroup.name = 'Tiles3DHelper.boxGroup';
|
|
12
|
+
this.add(boxGroup);
|
|
13
|
+
|
|
14
|
+
const sphereGroup = new Object3D();
|
|
15
|
+
sphereGroup.name = 'Tiles3DHelper.sphereGroup';
|
|
16
|
+
this.add(sphereGroup);
|
|
17
|
+
|
|
18
|
+
const helperMap = new Map();
|
|
19
|
+
|
|
20
|
+
function getHelperCache(tile) {
|
|
21
|
+
let helperCache = helperMap.get(tile);
|
|
22
|
+
if (!helperCache) {
|
|
23
|
+
helperCache = {
|
|
24
|
+
box: null,
|
|
25
|
+
sphere: null
|
|
26
|
+
};
|
|
27
|
+
helperMap.set(tile, helperCache);
|
|
28
|
+
}
|
|
29
|
+
return helperCache;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
tiles3D.addEventListener('TileVisibilityChanged', ({ scene, tile, visible }) => {
|
|
33
|
+
const helperCache = getHelperCache(tile);
|
|
34
|
+
|
|
35
|
+
if (visible) {
|
|
36
|
+
if (helperCache.box !== null) {
|
|
37
|
+
boxGroup.add(helperCache.box);
|
|
38
|
+
helperCache.box.updateMatrix(true);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (helperCache.sphere !== null) {
|
|
42
|
+
sphereGroup.add(helperCache.sphere);
|
|
43
|
+
helperCache.sphere.updateMatrix(true);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
if (helperCache.box !== null) {
|
|
47
|
+
boxGroup.remove(helperCache.box);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (helperCache.sphere !== null) {
|
|
51
|
+
sphereGroup.remove(helperCache.sphere);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
tiles3D.addEventListener('TileLoaded', ({ scene, tile }) => {
|
|
57
|
+
const helperCache = getHelperCache(tile);
|
|
58
|
+
const boundingVolume = tile.cached.boundingVolume;
|
|
59
|
+
|
|
60
|
+
if (boundingVolume.obb) {
|
|
61
|
+
// Create debug bounding box
|
|
62
|
+
// In some cases the bounding box may have a scale of 0 in one dimension resulting
|
|
63
|
+
// in the NaNs in an extracted rotation so we disable matrix updates instead.
|
|
64
|
+
const boxWrapper = new Object3D();
|
|
65
|
+
boxWrapper.name = 'Tiles3DHelper.boxWrapper';
|
|
66
|
+
boxWrapper.matrix.copy(boundingVolume.obb._originBoxTransform);
|
|
67
|
+
boxWrapper.matrixAutoUpdate = false;
|
|
68
|
+
boxWrapper.matrixNeedsUpdate = false;
|
|
69
|
+
|
|
70
|
+
const boxHelper = new Box3Helper(boundingVolume.obb._originBox, getIndexedRandomColor(tile.__depth));
|
|
71
|
+
boxHelper.name = 'Box3Helper';
|
|
72
|
+
boxHelper.raycast = emptyRaycast;
|
|
73
|
+
boxWrapper.add(boxHelper);
|
|
74
|
+
|
|
75
|
+
helperCache.box = boxWrapper;
|
|
76
|
+
|
|
77
|
+
if (tiles3D.visibleTiles.has(tile)) {
|
|
78
|
+
boxGroup.add(boxWrapper);
|
|
79
|
+
boxWrapper.updateMatrix(true);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (boundingVolume.sphere) {
|
|
84
|
+
const sphereHelper = new SphereHelper(boundingVolume.sphere, getIndexedRandomColor(tile.__depth));
|
|
85
|
+
sphereHelper.name = 'SphereHelper';
|
|
86
|
+
sphereHelper.raycast = emptyRaycast;
|
|
87
|
+
|
|
88
|
+
helperCache.sphere = sphereHelper;
|
|
89
|
+
|
|
90
|
+
if (tiles3D.visibleTiles.has(tile)) {
|
|
91
|
+
sphereGroup.add(sphereHelper);
|
|
92
|
+
sphereHelper.updateMatrix(true);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
tiles3D.addEventListener('TileDisposed', ({ scene, tile }) => {
|
|
98
|
+
const helperCache = getHelperCache(tile);
|
|
99
|
+
|
|
100
|
+
if (helperCache.box !== null) {
|
|
101
|
+
helperCache.box.children[0].geometry.dispose();
|
|
102
|
+
helperCache.box.children[0].material.dispose();
|
|
103
|
+
delete helperCache.box;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (helperCache.sphere !== null) {
|
|
107
|
+
helperCache.sphere.geometry.dispose();
|
|
108
|
+
helperCache.sphere.material.dispose();
|
|
109
|
+
delete helperCache.sphere;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
this.boxGroup = boxGroup;
|
|
114
|
+
this.sphereGroup = sphereGroup;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function emptyRaycast() {}
|
|
120
|
+
|
|
121
|
+
const _color3_1 = new Color3();
|
|
122
|
+
|
|
123
|
+
const _colors = {};
|
|
124
|
+
|
|
125
|
+
// Return a consistant random color for an index
|
|
126
|
+
const getIndexedRandomColor = index => {
|
|
127
|
+
if (!_colors[index]) {
|
|
128
|
+
const h = Math.random();
|
|
129
|
+
const s = 0.5 + Math.random() * 0.5;
|
|
130
|
+
const l = 0.375 + Math.random() * 0.25;
|
|
131
|
+
|
|
132
|
+
_colors[index] = _color3_1.setHSL(h, s, l).getHex();
|
|
133
|
+
}
|
|
134
|
+
return _colors[index];
|
|
135
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Triangle, Matrix4, Sphere } from 't3d';
|
|
2
|
+
import { OBB } from 't3d-3dtiles';
|
|
3
|
+
import { LineSegment } from './LineSegment.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get the closest intersection point between a path and the 3D Tiles.
|
|
7
|
+
* The path is defined by a line segment with a distance threshold,
|
|
8
|
+
* so the actual area is a capsule.
|
|
9
|
+
* @param {Object} tiles3D - The 3D Tiles Object.
|
|
10
|
+
* @param {LineSegment} lineSegment - The line segment.
|
|
11
|
+
* @param {Number} minDistance - The distance threshold.
|
|
12
|
+
* @return {Object|null} - The intersection object or null.
|
|
13
|
+
*/
|
|
14
|
+
export function getIntersectWithPath(tiles3D, lineSegment, minDistance) {
|
|
15
|
+
// Get obb in tiles root space
|
|
16
|
+
const obb = _lineSegment_1.copy(lineSegment)
|
|
17
|
+
.applyMatrix4(_mat4_1.getInverse(tiles3D.worldMatrix))
|
|
18
|
+
.getOBB(minDistance, _obb_1);
|
|
19
|
+
// TODO: obb.applyMatrix4 has bug, so don't use this until it's fixed
|
|
20
|
+
// const obb = lineSegment.getOBB(minDistance, _obb_1);
|
|
21
|
+
// obb.applyMatrix4(_mat4_1.getInverse(tiles3D.worldMatrix));
|
|
22
|
+
|
|
23
|
+
let intersectWithTile = null;
|
|
24
|
+
|
|
25
|
+
tiles3D.activeTiles.forEach(tile => {
|
|
26
|
+
if (!intersectsOBB(tile.cached.boundingVolume, obb)) return;
|
|
27
|
+
|
|
28
|
+
// TODO: traverse scene
|
|
29
|
+
const positions = tile.cached.geometry[0].attributes.a_Position.buffer.array;
|
|
30
|
+
const indexes = tile.cached.geometry[0].index.buffer.array;
|
|
31
|
+
|
|
32
|
+
// TODO: use mesh worldMatrix
|
|
33
|
+
const toWorldMatrix = tile.cached.scene.children[0].worldMatrix;
|
|
34
|
+
const toTileRootMatrix = _mat4_2.copy(toWorldMatrix).premultiply(_mat4_1);
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < indexes.length; i = i + 3) {
|
|
37
|
+
// TODO: more complex buffer structure, like non-indexed buffer
|
|
38
|
+
|
|
39
|
+
const { a, b, c } = _triangle_1;
|
|
40
|
+
|
|
41
|
+
const indexA = indexes[i], indexB = indexes[i + 1], indexC = indexes[i + 2];
|
|
42
|
+
a.fromArray(positions, 3 * indexA);
|
|
43
|
+
b.fromArray(positions, 3 * indexB);
|
|
44
|
+
c.fromArray(positions, 3 * indexC);
|
|
45
|
+
|
|
46
|
+
// Early out if obb doesn't intersect with the triangle's bounding sphere
|
|
47
|
+
// Should compute triangle circumcenter to get a more accurate sphere?
|
|
48
|
+
_sphere_1.setFromPoints(_triangle_1_array).applyMatrix4(toTileRootMatrix);
|
|
49
|
+
if (!obb.intersectsSphere(_sphere_1)) continue;
|
|
50
|
+
|
|
51
|
+
a.applyMatrix4(toWorldMatrix);
|
|
52
|
+
b.applyMatrix4(toWorldMatrix);
|
|
53
|
+
c.applyMatrix4(toWorldMatrix);
|
|
54
|
+
|
|
55
|
+
_lineSegment_1.startPoint.set(0, 0, 0);
|
|
56
|
+
_lineSegment_1.endPoint.set(0, 0, 0);
|
|
57
|
+
lineSegment.closestLineToTriangle(_triangle_1, _lineSegment_1);
|
|
58
|
+
|
|
59
|
+
// TODO: use distance squared
|
|
60
|
+
const closestDis = _lineSegment_1.getLength();
|
|
61
|
+
if (closestDis < minDistance) {
|
|
62
|
+
if (!intersectWithTile || closestDis < intersectWithTile.distance) {
|
|
63
|
+
intersectWithTile = {
|
|
64
|
+
tile,
|
|
65
|
+
distance: closestDis,
|
|
66
|
+
startPoint: _lineSegment_1.startPoint.toArray(),
|
|
67
|
+
endPoint: _lineSegment_1.endPoint.toArray()
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return intersectWithTile;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const _obb_1 = new OBB();
|
|
78
|
+
const _mat4_1 = new Matrix4();
|
|
79
|
+
const _mat4_2 = new Matrix4();
|
|
80
|
+
const _lineSegment_1 = new LineSegment();
|
|
81
|
+
const _triangle_1 = new Triangle();
|
|
82
|
+
const _triangle_1_array = [_triangle_1.a, _triangle_1.b, _triangle_1.c];
|
|
83
|
+
const _sphere_1 = new Sphere();
|
|
84
|
+
|
|
85
|
+
function intersectsOBB(boundingVolume, obb) {
|
|
86
|
+
const _sphere = boundingVolume.sphere;
|
|
87
|
+
const _obb = boundingVolume.obb;
|
|
88
|
+
|
|
89
|
+
// Early out if we don't hit this tile sphere
|
|
90
|
+
if (_sphere && !obb.intersectsSphere(_sphere)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Early out if we don't this this tile box
|
|
95
|
+
if (_obb && !_obb.intersectsOBB(obb)) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return true;
|
|
100
|
+
}
|