@eturnity/eturnity_3d 9.13.0-google3dTile.2 → 9.16.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/package.json +1 -2
- package/src/Overlay/OverlayFactory.js +0 -3
- package/src/Overlay/ThreeDModelOverlay.js +3 -19
- package/src/helper/cameraMixin.js +0 -17
- package/src/helper/render/edge.js +0 -2
- package/src/helper/render/obstacle.js +15 -3
- package/src/helper/render/projectionMaterial.js +48 -13
- package/src/helper/render/roof.js +17 -4
- package/src/helper/render/tile.js +2 -0
- package/dist/assets/images/panels/longiSolarLR4_60HPH_350M.png +0 -0
- package/dist/assets/images/panels/longiSolarLR4_60HPH_370M.png +0 -0
- package/dist/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw copy.png +0 -0
- package/dist/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
- package/dist/assets/images/panels/uv.png +0 -0
- package/dist/assets/panels/longiSolarLR4_60HPH_350M.png +0 -0
- package/dist/assets/panels/longiSolarLR4_60HPH_370M.png +0 -0
- package/dist/assets/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
- package/dist/assets/panels/uv.png +0 -0
- package/dist/assets/theme.js +0 -43
- package/dist/assets/vue.svg +0 -1
- package/dist/main.es.js +0 -43662
- package/dist/main.umd.js +0 -3542
- package/dist/style.css +0 -1
- package/dist/vite.svg +0 -1
- package/src/Overlay/Google3DTilesOverlay.js +0 -574
package/dist/style.css
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.canvas3DContainer{height:100%;width:100%}.canvas3DContainer>canvas{height:100%;width:100%}
|
package/dist/vite.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -1,574 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google 3D Tiles Overlay
|
|
3
|
-
*
|
|
4
|
-
* Loads 3D Tiles from Google's Photorealistic 3D Tiles API and displays them
|
|
5
|
-
* in the Three.js scene. The scene origin is at (centerLat, centerLon) at ground level,
|
|
6
|
-
* with an ENU coordinate system: X = East, Y = North, Z = Up, in meters.
|
|
7
|
-
*
|
|
8
|
-
* Integrates with the existing Overlay system so it can be rendered via renderOnThreeJS
|
|
9
|
-
* and updated every frame via userData.update on the mesh.
|
|
10
|
-
* Extends ThreeDModelOverlay to reuse getProjectedPlanesOnOverlay for roof projection.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import ThreeDModelOverlay from './ThreeDModelOverlay'
|
|
14
|
-
import * as THREE from 'three'
|
|
15
|
-
import { TilesRenderer } from '3d-tiles-renderer'
|
|
16
|
-
import {
|
|
17
|
-
TilesFadePlugin,
|
|
18
|
-
GoogleCloudAuthPlugin,
|
|
19
|
-
ReorientationPlugin,
|
|
20
|
-
TileCompressionPlugin,
|
|
21
|
-
} from '3d-tiles-renderer/plugins'
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Max screen-space error for tile refinement (3d-tiles-renderer).
|
|
25
|
-
* Lower = finer meshes for tiles inside {@link Google3DTilesOverlay#_tilesCamera}'s frustum.
|
|
26
|
-
* GoogleCloudAuthPlugin sets 20 for broad views; we override for this fixed ortho footprint.
|
|
27
|
-
*/
|
|
28
|
-
const TILES_FRUSTUM_ERROR_TARGET = 4
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Draw after merged base / roofs (renderOrder 10) and edges (15) so transparent
|
|
32
|
-
* tiles blend with geometry already in the color buffer instead of hiding it.
|
|
33
|
-
*/
|
|
34
|
-
const GOOGLE_TILES_RENDER_ORDER = 25
|
|
35
|
-
|
|
36
|
-
/** Extra meters padded on each side of roof AABB for tile loading frustum */
|
|
37
|
-
const ROOFS_BOUNDS_MARGIN_M = 5
|
|
38
|
-
|
|
39
|
-
/** Same rhythm as ThreeDModelOverlay.animatePlaceholder (sin² on time) */
|
|
40
|
-
function placeholderBounceScale(timeSeconds) {
|
|
41
|
-
const baseRadius = 0.65
|
|
42
|
-
const amplitude = 0.55
|
|
43
|
-
return baseRadius + amplitude * Math.sin(timeSeconds * 0.7 * Math.PI) ** 2
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export default class Google3DTilesOverlay extends ThreeDModelOverlay {
|
|
47
|
-
constructor(overlay, emit, origin) {
|
|
48
|
-
super(overlay, emit, origin || {}, null)
|
|
49
|
-
this.hasToBeSavedInBE = false
|
|
50
|
-
this.origin = origin || {}
|
|
51
|
-
this.tilesData = null
|
|
52
|
-
this._initPromise = null
|
|
53
|
-
// Center for ReorientationPlugin: use settings or origin (degrees → radians)
|
|
54
|
-
const lat = this.settings?.centerLat ?? this.origin?.lat
|
|
55
|
-
const lon = this.settings?.centerLon ?? this.origin?.lng
|
|
56
|
-
this._centerLatRad =
|
|
57
|
-
lat != null ? lat * (Math.PI / 180) : 35.6586 * (Math.PI / 180)
|
|
58
|
-
this._centerLonRad =
|
|
59
|
-
lon != null ? lon * (Math.PI / 180) : 139.7454 * (Math.PI / 180)
|
|
60
|
-
// Ground elevation in meters from Google Elevation API (used to offset tiles to ground level)
|
|
61
|
-
this._groundElevation = this.settings?.groundElevation ?? null
|
|
62
|
-
// Dedicated camera for tile loading and resolution so the user's camera does not affect which tiles load
|
|
63
|
-
// Orthographic camera looking down (Z up), covering -50 to +50 meters in X and Y
|
|
64
|
-
this._tilesCamera = new THREE.OrthographicCamera(
|
|
65
|
-
-10,
|
|
66
|
-
10,
|
|
67
|
-
10,
|
|
68
|
-
-10,
|
|
69
|
-
0.1,
|
|
70
|
-
10000
|
|
71
|
-
)
|
|
72
|
-
this._tilesCamera.position.set(0, 0, -100)
|
|
73
|
-
this._tilesCamera.lookAt(0, 0, 0)
|
|
74
|
-
this._tilesCamera.updateMatrixWorld(true)
|
|
75
|
-
/** @type {{ xMin: number, xMax: number, yMin: number, yMax: number, zMin?: number, zMax?: number } | null} mm — same shape as Vuex getRoofsBounds (three-d-module) */
|
|
76
|
-
this.roofsBound = null
|
|
77
|
-
/** Padded roof-bounds center (m), same as tile camera look-at XY — placeholder sits at (cx, cy, 0) */
|
|
78
|
-
this._placeholderCenterX = 0
|
|
79
|
-
this._placeholderCenterY = 0
|
|
80
|
-
this._rayDirDown = new THREE.Vector3(0, 0, 1)
|
|
81
|
-
this._defaultTilesCamZ = -100
|
|
82
|
-
this._defaultOrthoHalfExtentM = 10
|
|
83
|
-
this.sphereMesh = null
|
|
84
|
-
/** Transparent bouncing sphere at origin; removed once ground align settles */
|
|
85
|
-
this._groundAlignPlaceholderMesh = null
|
|
86
|
-
/** True when raycast tile bbox min.z is within ±10 after stick-to-ground */
|
|
87
|
-
this.tilesFullyLoaded = false
|
|
88
|
-
this.scene = null
|
|
89
|
-
}
|
|
90
|
-
getOverlayMeshForRaycast() {
|
|
91
|
-
return this.tilesData?.tiles.group
|
|
92
|
-
}
|
|
93
|
-
async initialiseModel() {
|
|
94
|
-
this.isReady = true
|
|
95
|
-
return true
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
_roofsBoundsAreEqual(a, b) {
|
|
99
|
-
if (a === b) return true
|
|
100
|
-
if (!a || !b) return false
|
|
101
|
-
return (
|
|
102
|
-
a.xMin === b.xMin &&
|
|
103
|
-
a.xMax === b.xMax &&
|
|
104
|
-
a.yMin === b.yMin &&
|
|
105
|
-
a.yMax === b.yMax
|
|
106
|
-
)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Store roof AABB (mm) and fit {@link #_tilesCamera} to it (ortho frustum in m).
|
|
111
|
-
* Bounds shape matches Vuex `getRoofsBounds` in `three-d-module.js`.
|
|
112
|
-
* Camera sits above the bounds center; left/right/top/bottom are set so the world XY
|
|
113
|
-
* footprint matches [xMin,xMax]×[yMin,yMax] in meters (same convention as ThreeCanvas orthographic).
|
|
114
|
-
*
|
|
115
|
-
* @param {{ xMin: number, xMax: number, yMin: number, yMax: number, zMin?: number, zMax?: number } | null | undefined} boundsMm
|
|
116
|
-
*/
|
|
117
|
-
updateRoofsBound(boundsMm) {
|
|
118
|
-
this._tilesGroundAligned = false
|
|
119
|
-
if (
|
|
120
|
-
!boundsMm ||
|
|
121
|
-
!Number.isFinite(boundsMm.xMin) ||
|
|
122
|
-
boundsMm.xMin === Infinity
|
|
123
|
-
) {
|
|
124
|
-
this.roofsBound = null
|
|
125
|
-
const h = this._defaultOrthoHalfExtentM
|
|
126
|
-
const cam = this._tilesCamera
|
|
127
|
-
const z = this._defaultTilesCamZ
|
|
128
|
-
cam.position.set(0, 0, z)
|
|
129
|
-
cam.left = -h
|
|
130
|
-
cam.right = h
|
|
131
|
-
cam.top = h
|
|
132
|
-
cam.bottom = -h
|
|
133
|
-
cam.lookAt(0, 0, 0)
|
|
134
|
-
cam.updateProjectionMatrix()
|
|
135
|
-
cam.updateMatrixWorld(true)
|
|
136
|
-
this._placeholderCenterX = 0
|
|
137
|
-
this._placeholderCenterY = 0
|
|
138
|
-
this._syncPlaceholderWorldXY()
|
|
139
|
-
return
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
this.roofsBound = {
|
|
143
|
-
xMin: boundsMm.xMin,
|
|
144
|
-
xMax: boundsMm.xMax,
|
|
145
|
-
yMin: boundsMm.yMin,
|
|
146
|
-
yMax: boundsMm.yMax,
|
|
147
|
-
zMin: boundsMm.zMin,
|
|
148
|
-
zMax: boundsMm.zMax,
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const m = ROOFS_BOUNDS_MARGIN_M
|
|
152
|
-
const xMinM = boundsMm.xMin / 1000 - m
|
|
153
|
-
const xMaxM = boundsMm.xMax / 1000 + m
|
|
154
|
-
const yMinM = boundsMm.yMin / 1000 - m
|
|
155
|
-
const yMaxM = boundsMm.yMax / 1000 + m
|
|
156
|
-
|
|
157
|
-
const cx = (xMinM + xMaxM) / 2
|
|
158
|
-
const cy = (yMinM + yMaxM) / 2
|
|
159
|
-
|
|
160
|
-
let halfW = (xMaxM - xMinM) / 2
|
|
161
|
-
let halfH = (yMaxM - yMinM) / 2
|
|
162
|
-
const minHalf = 100
|
|
163
|
-
if (halfW < minHalf) halfW = minHalf
|
|
164
|
-
if (halfH < minHalf) halfH = minHalf
|
|
165
|
-
|
|
166
|
-
const cam = this._tilesCamera
|
|
167
|
-
const z = this._defaultTilesCamZ
|
|
168
|
-
cam.position.set(cx, cy, z)
|
|
169
|
-
cam.left = xMinM - cx
|
|
170
|
-
cam.right = xMaxM - cx
|
|
171
|
-
cam.top = yMaxM - cy
|
|
172
|
-
cam.bottom = yMinM - cy
|
|
173
|
-
cam.lookAt(cx, cy, 0)
|
|
174
|
-
cam.updateProjectionMatrix()
|
|
175
|
-
cam.updateMatrixWorld(true)
|
|
176
|
-
|
|
177
|
-
this._placeholderCenterX = cx
|
|
178
|
-
this._placeholderCenterY = cy
|
|
179
|
-
this._syncPlaceholderWorldXY()
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
_syncPlaceholderWorldXY() {
|
|
183
|
-
const mesh = this._groundAlignPlaceholderMesh
|
|
184
|
-
if (!mesh) return
|
|
185
|
-
mesh.position.x = this._placeholderCenterX
|
|
186
|
-
mesh.position.y = this._placeholderCenterY
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
_getOrCreateTilesData() {
|
|
190
|
-
if (this.tilesData) return this.tilesData
|
|
191
|
-
const apiKey = process.env.VUE_APP_GOOGLE_MAP_API_KEY
|
|
192
|
-
const tiles = new TilesRenderer()
|
|
193
|
-
tiles.registerPlugin(
|
|
194
|
-
new GoogleCloudAuthPlugin({
|
|
195
|
-
apiToken: apiKey,
|
|
196
|
-
sessionOptions: null,
|
|
197
|
-
autoRefreshToken: true,
|
|
198
|
-
useRecommendedSettings: true,
|
|
199
|
-
})
|
|
200
|
-
)
|
|
201
|
-
tiles.registerPlugin(
|
|
202
|
-
new ReorientationPlugin({
|
|
203
|
-
lat: this._centerLatRad,
|
|
204
|
-
lon: this._centerLonRad,
|
|
205
|
-
})
|
|
206
|
-
)
|
|
207
|
-
tiles.registerPlugin(new TileCompressionPlugin())
|
|
208
|
-
tiles.registerPlugin(new TilesFadePlugin({ maximumFadeOutTiles: 50 }))
|
|
209
|
-
|
|
210
|
-
// After GoogleCloudAuthPlugin.init (errorTarget 20), tighten LOD for the ortho frustum only
|
|
211
|
-
tiles.errorTarget = TILES_FRUSTUM_ERROR_TARGET
|
|
212
|
-
// Prefer loading tiles that intersect _tilesCamera before prefetch / out-of-frustum work
|
|
213
|
-
tiles.optimizedLoadStrategy = true
|
|
214
|
-
|
|
215
|
-
tiles.lruCache.minSize = 400
|
|
216
|
-
tiles.lruCache.maxSize = 800
|
|
217
|
-
tiles.parseQueue.maxJobs = 4
|
|
218
|
-
|
|
219
|
-
const tilesWrapper = new THREE.Group()
|
|
220
|
-
tilesWrapper.name = 'Google3DTilesOverlay'
|
|
221
|
-
tilesWrapper.renderOrder = GOOGLE_TILES_RENDER_ORDER
|
|
222
|
-
tilesWrapper.rotation.x = Math.PI / 2
|
|
223
|
-
tilesWrapper.rotation.y = Math.PI
|
|
224
|
-
tilesWrapper.add(tiles.group)
|
|
225
|
-
tilesWrapper.position.z = 0
|
|
226
|
-
this.tilesData = { tiles, tilesWrapper }
|
|
227
|
-
|
|
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
|
-
}
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
return this.tilesData
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
_ensureGroundAlignPlaceholder(threeJSComponent) {
|
|
241
|
-
if (this._tilesGroundAligned || !threeJSComponent?.scene) return
|
|
242
|
-
const { scene } = threeJSComponent
|
|
243
|
-
if (this._groundAlignPlaceholderMesh) {
|
|
244
|
-
if (scene.getObjectById(this._groundAlignPlaceholderMesh.id)) return
|
|
245
|
-
this._groundAlignPlaceholderMesh.geometry?.dispose()
|
|
246
|
-
if (this._groundAlignPlaceholderMesh.material?.dispose) {
|
|
247
|
-
this._groundAlignPlaceholderMesh.material.dispose()
|
|
248
|
-
}
|
|
249
|
-
this._groundAlignPlaceholderMesh = null
|
|
250
|
-
}
|
|
251
|
-
const geometry = new THREE.SphereGeometry(10, 32, 32)
|
|
252
|
-
const material = new THREE.MeshBasicMaterial({
|
|
253
|
-
color: 0xffffff,
|
|
254
|
-
transparent: true,
|
|
255
|
-
opacity: 0.2,
|
|
256
|
-
depthWrite: false,
|
|
257
|
-
})
|
|
258
|
-
const mesh = new THREE.Mesh(geometry, material)
|
|
259
|
-
mesh.name = 'Google3DTilesGroundAlignPlaceholder'
|
|
260
|
-
mesh.userData.googleTilesGroundAlignPlaceholder = true
|
|
261
|
-
mesh.position.set(this._placeholderCenterX, this._placeholderCenterY, 0)
|
|
262
|
-
mesh.scale.setScalar(1)
|
|
263
|
-
scene.add(mesh)
|
|
264
|
-
this._groundAlignPlaceholderMesh = mesh
|
|
265
|
-
this._tickGroundAlignPlaceholderAnimation()
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
_tickGroundAlignPlaceholderAnimation() {
|
|
269
|
-
const mesh = this._groundAlignPlaceholderMesh
|
|
270
|
-
if (!mesh?.material) return
|
|
271
|
-
|
|
272
|
-
if (this.opacity === 0) {
|
|
273
|
-
mesh.visible = false
|
|
274
|
-
mesh.material.opacity = 0
|
|
275
|
-
return
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
mesh.visible = true
|
|
279
|
-
const t = performance.now() * 0.001
|
|
280
|
-
const scale = placeholderBounceScale(t)
|
|
281
|
-
mesh.scale.setScalar(scale)
|
|
282
|
-
mesh.position.x = this._placeholderCenterX
|
|
283
|
-
mesh.position.y = this._placeholderCenterY
|
|
284
|
-
// Light Z bob so it reads as a bounce (Z up)
|
|
285
|
-
mesh.position.z = 0.2 * Math.sin(t * 1.4 * Math.PI) ** 2
|
|
286
|
-
mesh.material.opacity = 0.06 + 0.22 * Math.sin(t * 0.85 * Math.PI) ** 2
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
_removeGroundAlignPlaceholder(threeJSComponent) {
|
|
290
|
-
const mesh = this._groundAlignPlaceholderMesh
|
|
291
|
-
if (!mesh) return
|
|
292
|
-
const scene = threeJSComponent?.scene
|
|
293
|
-
if (scene && scene.getObjectById(mesh.id)) {
|
|
294
|
-
scene.remove(mesh)
|
|
295
|
-
} else {
|
|
296
|
-
mesh.parent?.remove(mesh)
|
|
297
|
-
}
|
|
298
|
-
mesh.geometry?.dispose()
|
|
299
|
-
if (mesh.material?.dispose) mesh.material.dispose()
|
|
300
|
-
this._groundAlignPlaceholderMesh = null
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
_syncGroundAlignPlaceholder(threeJSComponent) {
|
|
304
|
-
if (!threeJSComponent?.scene) return
|
|
305
|
-
if (this.tilesFullyLoaded) {
|
|
306
|
-
this._removeGroundAlignPlaceholder(threeJSComponent)
|
|
307
|
-
} else {
|
|
308
|
-
this._ensureGroundAlignPlaceholder(threeJSComponent)
|
|
309
|
-
}
|
|
310
|
-
}
|
|
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) {
|
|
325
|
-
const { tiles, tilesWrapper } = this.tilesData || {}
|
|
326
|
-
if (!tiles || !tilesWrapper) {
|
|
327
|
-
this._tilesGroundAligned = false
|
|
328
|
-
return
|
|
329
|
-
}
|
|
330
|
-
|
|
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
|
|
352
|
-
) {
|
|
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)
|
|
364
|
-
}
|
|
365
|
-
|
|
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
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Apply global overlay opacity to all tile mesh materials (base Overlay.setOpacity only updates state + emit).
|
|
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
|
-
|
|
421
|
-
_applyGoogleTilesOpacity(wrapper) {
|
|
422
|
-
if (!wrapper) return
|
|
423
|
-
const opacity = this.opacity
|
|
424
|
-
const isTransparent = opacity < 1 - 1e-6
|
|
425
|
-
wrapper.renderOrder = GOOGLE_TILES_RENDER_ORDER
|
|
426
|
-
wrapper.visible = Boolean(this.isActive) && opacity > 0
|
|
427
|
-
wrapper.traverse((object) => {
|
|
428
|
-
if (!object.isMesh || !object.material) return
|
|
429
|
-
object.renderOrder = GOOGLE_TILES_RENDER_ORDER
|
|
430
|
-
const materials = Array.isArray(object.material)
|
|
431
|
-
? object.material
|
|
432
|
-
: [object.material]
|
|
433
|
-
for (const mat of materials) {
|
|
434
|
-
if (mat) {
|
|
435
|
-
mat.transparent = isTransparent
|
|
436
|
-
mat.opacity = opacity
|
|
437
|
-
// Avoid writing depth when semi-transparent so merged base (base.js) and
|
|
438
|
-
// other geometry drawn earlier remain visible through the tiles.
|
|
439
|
-
mat.depthWrite = !isTransparent
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
})
|
|
443
|
-
}
|
|
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
|
-
}
|
|
464
|
-
setOpacity(opacity) {
|
|
465
|
-
super.setOpacity(opacity)
|
|
466
|
-
const wrapper = this.overlayMesh || this.tilesData?.tilesWrapper
|
|
467
|
-
if (wrapper) {
|
|
468
|
-
this._applyGoogleTilesOpacity(wrapper)
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
setIsActive(isActive) {
|
|
473
|
-
this.isActive = Boolean(isActive)
|
|
474
|
-
const wrapper = this.overlayMesh || this.tilesData?.tilesWrapper
|
|
475
|
-
if (wrapper) {
|
|
476
|
-
this._applyGoogleTilesOpacity(wrapper)
|
|
477
|
-
}
|
|
478
|
-
this.emit('item-updated', this)
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
async renderOnThreeJS(threeJSComponent) {
|
|
482
|
-
const rb = threeJSComponent?.roofsBounds
|
|
483
|
-
if (rb && !this._roofsBoundsAreEqual(this.roofsBound, rb)) {
|
|
484
|
-
this.updateRoofsBound(rb)
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
if (!this.isActive) {
|
|
488
|
-
this._removeGroundAlignPlaceholder(threeJSComponent)
|
|
489
|
-
const tilesWrapper =
|
|
490
|
-
this.tilesData?.tilesWrapper ||
|
|
491
|
-
threeJSComponent.meshes.overlayMeshes[this.id]
|
|
492
|
-
if (tilesWrapper) {
|
|
493
|
-
tilesWrapper.visible = false
|
|
494
|
-
threeJSComponent.meshes.overlayMeshes[this.id] = tilesWrapper
|
|
495
|
-
this.overlayMesh = tilesWrapper
|
|
496
|
-
}
|
|
497
|
-
return tilesWrapper || null
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
const tilesData = this._getOrCreateTilesData()
|
|
501
|
-
if (!tilesData) return null
|
|
502
|
-
|
|
503
|
-
const { tiles, tilesWrapper } = tilesData
|
|
504
|
-
const { renderer, scene } = threeJSComponent
|
|
505
|
-
this.scene = scene
|
|
506
|
-
tiles.setCamera(this._tilesCamera)
|
|
507
|
-
tiles.setResolutionFromRenderer(this._tilesCamera, renderer)
|
|
508
|
-
|
|
509
|
-
tilesWrapper.userData.type = 'overlayMeshes'
|
|
510
|
-
tilesWrapper.userData.meshId = this.id
|
|
511
|
-
tilesWrapper.userData.version = this.version
|
|
512
|
-
|
|
513
|
-
this._syncGroundAlignPlaceholder(threeJSComponent)
|
|
514
|
-
if (!this.tilesFullyLoaded) {
|
|
515
|
-
this._tickGroundAlignPlaceholderAnimation()
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
tilesWrapper.userData.update = () => {
|
|
519
|
-
if (!this.isActive || !tiles || !renderer) return
|
|
520
|
-
tiles.errorTarget = TILES_FRUSTUM_ERROR_TARGET
|
|
521
|
-
tiles.setCamera(this._tilesCamera)
|
|
522
|
-
tiles.setResolutionFromRenderer(this._tilesCamera, renderer)
|
|
523
|
-
tiles.update()
|
|
524
|
-
this._syncGroundAlignPlaceholder(threeJSComponent)
|
|
525
|
-
if (!this.tilesFullyLoaded) {
|
|
526
|
-
this._tickGroundAlignPlaceholderAnimation()
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
if (tilesWrapper.parent !== scene) {
|
|
531
|
-
if (tilesWrapper.parent) tilesWrapper.parent.remove(tilesWrapper)
|
|
532
|
-
scene.add(tilesWrapper)
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
threeJSComponent.meshes.overlayMeshes[this.id] = tilesWrapper
|
|
536
|
-
this.overlayMesh = tilesWrapper
|
|
537
|
-
this._applyGoogleTilesOpacity(tilesWrapper)
|
|
538
|
-
return tilesWrapper
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
renderOnPaperJS() {
|
|
542
|
-
// No 2D representation for 3D Tiles overlay
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
serializeSettings() {
|
|
546
|
-
return {
|
|
547
|
-
...super.serializeSettings(),
|
|
548
|
-
centerLat: this.origin?.lat ?? this.settings?.centerLat,
|
|
549
|
-
centerLon: this.origin?.lng ?? this.settings?.centerLon,
|
|
550
|
-
groundElevation: this._groundElevation,
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
dispose() {
|
|
555
|
-
if (this._groundAlignPlaceholderMesh) {
|
|
556
|
-
this._groundAlignPlaceholderMesh.parent?.remove(
|
|
557
|
-
this._groundAlignPlaceholderMesh
|
|
558
|
-
)
|
|
559
|
-
this._groundAlignPlaceholderMesh.geometry?.dispose()
|
|
560
|
-
if (this._groundAlignPlaceholderMesh.material?.dispose) {
|
|
561
|
-
this._groundAlignPlaceholderMesh.material.dispose()
|
|
562
|
-
}
|
|
563
|
-
this._groundAlignPlaceholderMesh = null
|
|
564
|
-
}
|
|
565
|
-
if (this.tilesData?.tiles) {
|
|
566
|
-
this.tilesData.tiles.dispose()
|
|
567
|
-
}
|
|
568
|
-
this.tilesData = null
|
|
569
|
-
this.overlayMesh = null
|
|
570
|
-
this.roofsBound = null
|
|
571
|
-
this._initPromise = null
|
|
572
|
-
this._tilesGroundAligned = false
|
|
573
|
-
}
|
|
574
|
-
}
|