@eturnity/eturnity_3d 9.13.0-google3dTile.1 → 9.13.0-google3dTile.2
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/package.json +1 -1
- package/src/Overlay/Google3DTilesOverlay.js +138 -90
package/package.json
CHANGED
|
@@ -20,20 +20,6 @@ import {
|
|
|
20
20
|
TileCompressionPlugin,
|
|
21
21
|
} from '3d-tiles-renderer/plugins'
|
|
22
22
|
|
|
23
|
-
/** Set DoubleSide on every mesh material in a loaded 3D Tiles scene */
|
|
24
|
-
function applyDoubleSideToTileScene(scene) {
|
|
25
|
-
if (!scene) return
|
|
26
|
-
scene.traverse((object) => {
|
|
27
|
-
if (!object.isMesh || !object.material) return
|
|
28
|
-
const materials = Array.isArray(object.material)
|
|
29
|
-
? object.material
|
|
30
|
-
: [object.material]
|
|
31
|
-
for (const mat of materials) {
|
|
32
|
-
if (mat) mat.side = THREE.DoubleSide
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
23
|
/**
|
|
38
24
|
* Max screen-space error for tile refinement (3d-tiles-renderer).
|
|
39
25
|
* Lower = finer meshes for tiles inside {@link Google3DTilesOverlay#_tilesCamera}'s frustum.
|
|
@@ -48,7 +34,7 @@ const TILES_FRUSTUM_ERROR_TARGET = 4
|
|
|
48
34
|
const GOOGLE_TILES_RENDER_ORDER = 25
|
|
49
35
|
|
|
50
36
|
/** Extra meters padded on each side of roof AABB for tile loading frustum */
|
|
51
|
-
const ROOFS_BOUNDS_MARGIN_M =
|
|
37
|
+
const ROOFS_BOUNDS_MARGIN_M = 5
|
|
52
38
|
|
|
53
39
|
/** Same rhythm as ThreeDModelOverlay.animatePlaceholder (sin² on time) */
|
|
54
40
|
function placeholderBounceScale(timeSeconds) {
|
|
@@ -76,10 +62,10 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
76
62
|
// Dedicated camera for tile loading and resolution so the user's camera does not affect which tiles load
|
|
77
63
|
// Orthographic camera looking down (Z up), covering -50 to +50 meters in X and Y
|
|
78
64
|
this._tilesCamera = new THREE.OrthographicCamera(
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
65
|
+
-10,
|
|
66
|
+
10,
|
|
67
|
+
10,
|
|
68
|
+
-10,
|
|
83
69
|
0.1,
|
|
84
70
|
10000
|
|
85
71
|
)
|
|
@@ -93,18 +79,13 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
93
79
|
this._placeholderCenterY = 0
|
|
94
80
|
this._rayDirDown = new THREE.Vector3(0, 0, 1)
|
|
95
81
|
this._defaultTilesCamZ = -100
|
|
96
|
-
this._defaultOrthoHalfExtentM =
|
|
97
|
-
const raycaster = new THREE.Raycaster()
|
|
98
|
-
raycaster.far = 1000000
|
|
99
|
-
raycaster.near = 1
|
|
100
|
-
this._defaultRayOrigin = new THREE.Vector3(0, 0, this._defaultTilesCamZ)
|
|
101
|
-
raycaster.set(this._defaultRayOrigin, this._rayDirDown)
|
|
102
|
-
this._raycaster = raycaster
|
|
82
|
+
this._defaultOrthoHalfExtentM = 10
|
|
103
83
|
this.sphereMesh = null
|
|
104
84
|
/** Transparent bouncing sphere at origin; removed once ground align settles */
|
|
105
85
|
this._groundAlignPlaceholderMesh = null
|
|
106
86
|
/** True when raycast tile bbox min.z is within ±10 after stick-to-ground */
|
|
107
|
-
this.
|
|
87
|
+
this.tilesFullyLoaded = false
|
|
88
|
+
this.scene = null
|
|
108
89
|
}
|
|
109
90
|
getOverlayMeshForRaycast() {
|
|
110
91
|
return this.tilesData?.tiles.group
|
|
@@ -152,8 +133,6 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
152
133
|
cam.lookAt(0, 0, 0)
|
|
153
134
|
cam.updateProjectionMatrix()
|
|
154
135
|
cam.updateMatrixWorld(true)
|
|
155
|
-
this._defaultRayOrigin.set(0, 0, z)
|
|
156
|
-
this._raycaster.set(this._defaultRayOrigin, this._rayDirDown)
|
|
157
136
|
this._placeholderCenterX = 0
|
|
158
137
|
this._placeholderCenterY = 0
|
|
159
138
|
this._syncPlaceholderWorldXY()
|
|
@@ -195,8 +174,6 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
195
174
|
cam.updateProjectionMatrix()
|
|
196
175
|
cam.updateMatrixWorld(true)
|
|
197
176
|
|
|
198
|
-
this._raycaster.set(new THREE.Vector3(cx, cy, z), this._rayDirDown)
|
|
199
|
-
|
|
200
177
|
this._placeholderCenterX = cx
|
|
201
178
|
this._placeholderCenterY = cy
|
|
202
179
|
this._syncPlaceholderWorldXY()
|
|
@@ -209,26 +186,6 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
209
186
|
mesh.position.y = this._placeholderCenterY
|
|
210
187
|
}
|
|
211
188
|
|
|
212
|
-
/**
|
|
213
|
-
* Cast a vertical ray at the origin pointing down and return the intersection height.
|
|
214
|
-
* @returns {number|null} - The z coordinate of the first intersection, or null if none
|
|
215
|
-
*/
|
|
216
|
-
raycastAtRoofsBoundCenter() {
|
|
217
|
-
const { tilesWrapper } = this.tilesData || {}
|
|
218
|
-
if (!tilesWrapper) return null
|
|
219
|
-
|
|
220
|
-
tilesWrapper.updateMatrixWorld(true)
|
|
221
|
-
|
|
222
|
-
const intersects = this._raycaster.intersectObject(tilesWrapper, true)
|
|
223
|
-
if (intersects.length > 0) {
|
|
224
|
-
if (intersects[0].point.z < 30) {
|
|
225
|
-
this._tilesGroundAligned = true
|
|
226
|
-
}
|
|
227
|
-
return intersects[0]
|
|
228
|
-
}
|
|
229
|
-
return null
|
|
230
|
-
}
|
|
231
|
-
|
|
232
189
|
_getOrCreateTilesData() {
|
|
233
190
|
if (this.tilesData) return this.tilesData
|
|
234
191
|
const apiKey = process.env.VUE_APP_GOOGLE_MAP_API_KEY
|
|
@@ -265,12 +222,16 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
265
222
|
tilesWrapper.rotation.x = Math.PI / 2
|
|
266
223
|
tilesWrapper.rotation.y = Math.PI
|
|
267
224
|
tilesWrapper.add(tiles.group)
|
|
268
|
-
tilesWrapper.position.z =
|
|
225
|
+
tilesWrapper.position.z = 0
|
|
269
226
|
this.tilesData = { tiles, tilesWrapper }
|
|
270
227
|
|
|
271
|
-
tiles.addEventListener('load-model', ({ scene }) => {
|
|
272
|
-
|
|
273
|
-
this.
|
|
228
|
+
tiles.addEventListener('load-model', ({ scene, tile }) => {
|
|
229
|
+
console.log('tile size loading', tiles.loadingTiles.size)
|
|
230
|
+
this.tilesFullyLoaded = tiles.loadingTiles.size == 0
|
|
231
|
+
if (this.tilesFullyLoaded) {
|
|
232
|
+
this._applyGoogleTilesShadowProperty(tilesWrapper)
|
|
233
|
+
this.stickObjectToTheGround(scene)
|
|
234
|
+
}
|
|
274
235
|
})
|
|
275
236
|
|
|
276
237
|
return this.tilesData
|
|
@@ -297,11 +258,7 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
297
258
|
const mesh = new THREE.Mesh(geometry, material)
|
|
298
259
|
mesh.name = 'Google3DTilesGroundAlignPlaceholder'
|
|
299
260
|
mesh.userData.googleTilesGroundAlignPlaceholder = true
|
|
300
|
-
mesh.position.set(
|
|
301
|
-
this._placeholderCenterX,
|
|
302
|
-
this._placeholderCenterY,
|
|
303
|
-
0
|
|
304
|
-
)
|
|
261
|
+
mesh.position.set(this._placeholderCenterX, this._placeholderCenterY, 0)
|
|
305
262
|
mesh.scale.setScalar(1)
|
|
306
263
|
scene.add(mesh)
|
|
307
264
|
this._groundAlignPlaceholderMesh = mesh
|
|
@@ -345,49 +302,122 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
345
302
|
|
|
346
303
|
_syncGroundAlignPlaceholder(threeJSComponent) {
|
|
347
304
|
if (!threeJSComponent?.scene) return
|
|
348
|
-
if (this.
|
|
305
|
+
if (this.tilesFullyLoaded) {
|
|
349
306
|
this._removeGroundAlignPlaceholder(threeJSComponent)
|
|
350
307
|
} else {
|
|
351
308
|
this._ensureGroundAlignPlaceholder(threeJSComponent)
|
|
352
309
|
}
|
|
353
310
|
}
|
|
354
|
-
|
|
355
|
-
|
|
311
|
+
getBoundingBoxOfTiles(tileGroups) {
|
|
312
|
+
let mergedBoundingBox = new THREE.Box3()
|
|
313
|
+
tileGroups.forEach((tileGroup) => {
|
|
314
|
+
const tileMesh = tileGroup.children[0]
|
|
315
|
+
if (tileGroup.visible && tileMesh.geometry && tileMesh.visible) {
|
|
316
|
+
//create random color
|
|
317
|
+
const boundingBox = this.getBoundingBoxOfTile(tileMesh)
|
|
318
|
+
//compute bounding box in world coordinates
|
|
319
|
+
mergedBoundingBox.union(boundingBox)
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
return mergedBoundingBox
|
|
323
|
+
}
|
|
324
|
+
stickObjectToTheGround(scene) {
|
|
356
325
|
const { tiles, tilesWrapper } = this.tilesData || {}
|
|
357
326
|
if (!tiles || !tilesWrapper) {
|
|
358
327
|
this._tilesGroundAligned = false
|
|
359
328
|
return
|
|
360
329
|
}
|
|
361
330
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
331
|
+
//merge all bounding boxes of the tiles
|
|
332
|
+
const boundingBox = this.getBoundingBoxOfTiles(
|
|
333
|
+
tilesWrapper.children[0].children
|
|
334
|
+
)
|
|
335
|
+
tilesWrapper.position.z -= boundingBox.min.z
|
|
336
|
+
tilesWrapper.updateMatrixWorld(true)
|
|
337
|
+
this._tilesGroundAligned = true
|
|
338
|
+
}
|
|
339
|
+
getBoundingBoxOfTile(tileMesh) {
|
|
340
|
+
const extremePoints = []
|
|
341
|
+
let minX = Infinity,
|
|
342
|
+
maxX = -Infinity,
|
|
343
|
+
minY = Infinity,
|
|
344
|
+
maxY = -Infinity,
|
|
345
|
+
minZ = Infinity,
|
|
346
|
+
maxZ = -Infinity
|
|
347
|
+
//use for instead of forEach as the array doesn't contain points but indices
|
|
348
|
+
for (
|
|
349
|
+
let i = 300;
|
|
350
|
+
i < tileMesh.geometry.attributes.position.array.length;
|
|
351
|
+
i += 3
|
|
382
352
|
) {
|
|
383
|
-
|
|
353
|
+
const x = tileMesh.geometry.attributes.position.array[i]
|
|
354
|
+
const y = tileMesh.geometry.attributes.position.array[i + 1]
|
|
355
|
+
const z = tileMesh.geometry.attributes.position.array[i + 2]
|
|
356
|
+
let point = new THREE.Vector3(x, y, z)
|
|
357
|
+
point.applyMatrix4(tileMesh.matrixWorld)
|
|
358
|
+
minX = Math.min(minX, point.x)
|
|
359
|
+
maxX = Math.max(maxX, point.x)
|
|
360
|
+
minY = Math.min(minY, point.y)
|
|
361
|
+
maxY = Math.max(maxY, point.y)
|
|
362
|
+
minZ = Math.min(minZ, point.z)
|
|
363
|
+
maxZ = Math.max(maxZ, point.z)
|
|
384
364
|
}
|
|
385
365
|
|
|
386
|
-
|
|
366
|
+
extremePoints.push(new THREE.Vector3(maxX, maxY, maxZ))
|
|
367
|
+
extremePoints.push(new THREE.Vector3(minX, maxY, minZ))
|
|
368
|
+
extremePoints.push(new THREE.Vector3(maxX, minY, minZ))
|
|
369
|
+
extremePoints.push(new THREE.Vector3(minX, maxY, maxZ))
|
|
370
|
+
extremePoints.push(new THREE.Vector3(maxX, minY, maxZ))
|
|
371
|
+
extremePoints.push(new THREE.Vector3(minX, minY, maxZ))
|
|
372
|
+
extremePoints.push(new THREE.Vector3(maxX, maxY, minZ))
|
|
373
|
+
|
|
374
|
+
const boundingBox = new THREE.Box3(
|
|
375
|
+
new THREE.Vector3(minX, minY, minZ),
|
|
376
|
+
new THREE.Vector3(maxX, maxY, maxZ)
|
|
377
|
+
)
|
|
378
|
+
return boundingBox
|
|
387
379
|
}
|
|
380
|
+
|
|
388
381
|
/**
|
|
389
382
|
* Apply global overlay opacity to all tile mesh materials (base Overlay.setOpacity only updates state + emit).
|
|
390
383
|
*/
|
|
384
|
+
/**
|
|
385
|
+
* Replace MeshBasicMaterial with MeshPhongMaterial for lit/shadow rendering.
|
|
386
|
+
* Textures are reused by reference. Caller must re-run TilesFadePlugin material prep after batch swap.
|
|
387
|
+
*/
|
|
388
|
+
_convertGoogleTileBasicToPhong(basic) {
|
|
389
|
+
const phong = new THREE.MeshPhongMaterial()
|
|
390
|
+
//THREE.Material.prototype.copy.call(phong, basic)
|
|
391
|
+
phong.color = new THREE.Color(0xffffff)
|
|
392
|
+
phong.map = basic.map
|
|
393
|
+
phong.side = THREE.DoubleSide
|
|
394
|
+
phong.transparent = false
|
|
395
|
+
phong.opacity = 1
|
|
396
|
+
phong.shadowSide = THREE.DoubleSide
|
|
397
|
+
phong.flatShading = true
|
|
398
|
+
// phong.lightMap = basic.lightMap
|
|
399
|
+
// phong.lightMapIntensity = basic.lightMapIntensity
|
|
400
|
+
// phong.aoMap = basic.aoMap
|
|
401
|
+
// phong.aoMapIntensity = basic.aoMapIntensity
|
|
402
|
+
// phong.specularMap = basic.specularMap
|
|
403
|
+
// phong.alphaMap = basic.alphaMap
|
|
404
|
+
// phong.envMap = basic.envMap
|
|
405
|
+
// phong.envMapRotation.copy(basic.envMapRotation)
|
|
406
|
+
// phong.combine = basic.combine
|
|
407
|
+
basic.dispose()
|
|
408
|
+
return phong
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* New materials after Basic→Phong swap must be wrapped for TilesFadePlugin dither fade.
|
|
413
|
+
* Uses FADE_TILES_PLUGIN internals (prepareScene); coupled to 3d-tiles-renderer version.
|
|
414
|
+
*/
|
|
415
|
+
_reregisterGoogleTilesFadeMaterials(wrapper) {
|
|
416
|
+
const tiles = this.tilesData?.tiles
|
|
417
|
+
const fadePlugin = tiles?.getPluginByName?.('FADE_TILES_PLUGIN')
|
|
418
|
+
fadePlugin?._fadeMaterialManager?.prepareScene?.(wrapper)
|
|
419
|
+
}
|
|
420
|
+
|
|
391
421
|
_applyGoogleTilesOpacity(wrapper) {
|
|
392
422
|
if (!wrapper) return
|
|
393
423
|
const opacity = this.opacity
|
|
@@ -411,7 +441,26 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
411
441
|
}
|
|
412
442
|
})
|
|
413
443
|
}
|
|
414
|
-
|
|
444
|
+
_applyGoogleTilesShadowProperty(wrapper) {
|
|
445
|
+
if (!wrapper) return
|
|
446
|
+
wrapper.traverse((object) => {
|
|
447
|
+
if (!object.isMesh || !object.material) return
|
|
448
|
+
if (Array.isArray(object.material)) {
|
|
449
|
+
object.material = object.material.map((mat) =>
|
|
450
|
+
this._convertGoogleTileBasicToPhong(mat)
|
|
451
|
+
)
|
|
452
|
+
} else {
|
|
453
|
+
object.material = this._convertGoogleTileBasicToPhong(object.material)
|
|
454
|
+
}
|
|
455
|
+
})
|
|
456
|
+
// this._reregisterGoogleTilesFadeMaterials(wrapper)
|
|
457
|
+
wrapper.traverse((object) => {
|
|
458
|
+
if (!object.isMesh) return
|
|
459
|
+
object.castShadow = true
|
|
460
|
+
object.receiveShadow = true
|
|
461
|
+
object.needsUpdate = true
|
|
462
|
+
})
|
|
463
|
+
}
|
|
415
464
|
setOpacity(opacity) {
|
|
416
465
|
super.setOpacity(opacity)
|
|
417
466
|
const wrapper = this.overlayMesh || this.tilesData?.tilesWrapper
|
|
@@ -453,6 +502,7 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
453
502
|
|
|
454
503
|
const { tiles, tilesWrapper } = tilesData
|
|
455
504
|
const { renderer, scene } = threeJSComponent
|
|
505
|
+
this.scene = scene
|
|
456
506
|
tiles.setCamera(this._tilesCamera)
|
|
457
507
|
tiles.setResolutionFromRenderer(this._tilesCamera, renderer)
|
|
458
508
|
|
|
@@ -460,9 +510,8 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
460
510
|
tilesWrapper.userData.meshId = this.id
|
|
461
511
|
tilesWrapper.userData.version = this.version
|
|
462
512
|
|
|
463
|
-
this.stickObjectToTheGround()
|
|
464
513
|
this._syncGroundAlignPlaceholder(threeJSComponent)
|
|
465
|
-
if (this.
|
|
514
|
+
if (!this.tilesFullyLoaded) {
|
|
466
515
|
this._tickGroundAlignPlaceholderAnimation()
|
|
467
516
|
}
|
|
468
517
|
|
|
@@ -472,9 +521,8 @@ export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
|
472
521
|
tiles.setCamera(this._tilesCamera)
|
|
473
522
|
tiles.setResolutionFromRenderer(this._tilesCamera, renderer)
|
|
474
523
|
tiles.update()
|
|
475
|
-
this.stickObjectToTheGround()
|
|
476
524
|
this._syncGroundAlignPlaceholder(threeJSComponent)
|
|
477
|
-
if (this.
|
|
525
|
+
if (!this.tilesFullyLoaded) {
|
|
478
526
|
this._tickGroundAlignPlaceholderAnimation()
|
|
479
527
|
}
|
|
480
528
|
}
|