@threepipe/plugin-3d-tiles-renderer 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/B3DMLoadPlugin.d.ts +22 -0
  2. package/dist/B3DMLoadPlugin.d.ts.map +1 -0
  3. package/dist/CMPTLoadPlugin.d.ts +22 -0
  4. package/dist/CMPTLoadPlugin.d.ts.map +1 -0
  5. package/dist/DeepZoomImageLoadPlugin.d.ts +25 -0
  6. package/dist/DeepZoomImageLoadPlugin.d.ts.map +1 -0
  7. package/dist/EnvironmentControlsPlugin.d.ts +29 -0
  8. package/dist/EnvironmentControlsPlugin.d.ts.map +1 -0
  9. package/dist/GlobeControlsPlugin.d.ts +33 -0
  10. package/dist/GlobeControlsPlugin.d.ts.map +1 -0
  11. package/dist/I3DMLoadPlugin.d.ts +21 -0
  12. package/dist/I3DMLoadPlugin.d.ts.map +1 -0
  13. package/dist/PNTSLoadPlugin.d.ts +22 -0
  14. package/dist/PNTSLoadPlugin.d.ts.map +1 -0
  15. package/dist/SlippyMapTilesLoadPlugin.d.ts +29 -0
  16. package/dist/SlippyMapTilesLoadPlugin.d.ts.map +1 -0
  17. package/dist/TilesRendererPlugin.d.ts +67 -0
  18. package/dist/TilesRendererPlugin.d.ts.map +1 -0
  19. package/dist/dependencies.txt +212 -0
  20. package/dist/gltf.d.ts +18 -0
  21. package/dist/gltf.d.ts.map +1 -0
  22. package/dist/index.d.ts +11 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +10873 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/index.mjs +10856 -0
  27. package/dist/index.mjs.map +1 -0
  28. package/package.json +51 -0
  29. package/src/B3DMLoadPlugin.ts +64 -0
  30. package/src/CMPTLoadPlugin.ts +144 -0
  31. package/src/DeepZoomImageLoadPlugin.ts +49 -0
  32. package/src/EnvironmentControlsPlugin.ts +52 -0
  33. package/src/GlobeControlsPlugin.ts +75 -0
  34. package/src/I3DMLoadPlugin.ts +65 -0
  35. package/src/PNTSLoadPlugin.ts +137 -0
  36. package/src/SlippyMapTilesLoadPlugin.ts +50 -0
  37. package/src/TilesRendererPlugin.ts +354 -0
  38. package/src/global.d.ts +40 -0
  39. package/src/gltf.ts +40 -0
  40. package/src/index.ts +16 -0
@@ -0,0 +1,354 @@
1
+ import {
2
+ AViewerPluginEventMap,
3
+ AViewerPluginSync,
4
+ Box3B,
5
+ EventListener2,
6
+ generateUUID,
7
+ IAssetImporter,
8
+ ILoader,
9
+ Importer,
10
+ IObject3D,
11
+ iObjectCommons,
12
+ IRenderManager,
13
+ IRenderManagerEventMap,
14
+ IScene,
15
+ ISceneEventMap,
16
+ Loader,
17
+ ImportAddOptions,
18
+ LoadingManager,
19
+ ThreeViewer, Sphere, uiButton,
20
+ } from 'threepipe'
21
+ import {TilesGroup, TilesRenderer} from '3d-tiles-renderer'
22
+ import {gltfCesiumRTCExtension, gltfMeshFeaturesExtension, gltfStructuralMetadataExtension} from './gltf'
23
+ // @ts-expect-error moduleResolution issue
24
+ import {ImplicitTilingPlugin, TilesFadePlugin, UpdateOnChangePlugin, CesiumIonAuthPlugin} from '3d-tiles-renderer/plugins'
25
+
26
+ export type TilesRendererGroup = TilesGroup & IObject3D
27
+
28
+ export interface TilesRendererPluginEventMap extends AViewerPluginEventMap {
29
+ addTile: {group: TilesRendererGroup}
30
+ removeTile: {group: TilesRendererGroup}
31
+ }
32
+
33
+ /**
34
+ * TilesRendererPlugin is a plugin for loading and rendering OGC 3D Tiles using [3d-tiles-renderer](https://github.com/NASA-AMMOS/3DTilesRendererJS) package.
35
+ *
36
+ * Specification - https://www.ogc.org/standards/3dtiles/
37
+ */
38
+ export class TilesRendererPlugin extends AViewerPluginSync<TilesRendererPluginEventMap> {
39
+ public static readonly PluginType: string = 'TilesRendererPlugin'
40
+ enabled = true
41
+ dependencies = []
42
+
43
+ static readonly DUMMY_EXT = 'tileset'
44
+
45
+ objects: TilesRendererGroup[] = []
46
+
47
+ protected _importer = new Importer(TilesRendererLoader, [TilesRendererPlugin.DUMMY_EXT, TilesRendererPlugin.DUMMY_EXT + '.json'], [], false)
48
+
49
+ constructor() {
50
+ super()
51
+ }
52
+
53
+ async load(url: string, options?: ImportAddOptions) {
54
+ if (!this._viewer) {
55
+ console.warn('TilesRendererPlugin: viewer not set')
56
+ return
57
+ }
58
+ const temp = generateUUID() + '.' + TilesRendererPlugin.DUMMY_EXT
59
+ const importer = this._viewer.assetManager.importer.registerFile(temp) as TilesRendererLoader
60
+ if (!importer.isTilesRendererLoader) {
61
+ console.warn('TilesRendererPlugin: TilesRendererLoader not registered')
62
+ return
63
+ }
64
+ return await this._viewer.load<TilesRendererGroup>(url, {
65
+ ...options,
66
+ fileExtension: TilesRendererPlugin.DUMMY_EXT,
67
+ fileHandler: importer,
68
+ })
69
+ }
70
+
71
+ async loadCesiumIon(info: TilesImportOptions['CesiumIonAuthPlugin'], options?: ImportAddOptions) {
72
+ const file = generateUUID() + '.' + TilesRendererPlugin.DUMMY_EXT
73
+ return this.load(file, {
74
+ ...options,
75
+ tiles: {
76
+ CesiumIonAuthPlugin: info,
77
+ ...options?.tiles,
78
+ },
79
+ })
80
+ }
81
+
82
+ onAdded(viewer: ThreeViewer) {
83
+ super.onAdded(viewer)
84
+ this._importer.onCtor = (l, ai) => {
85
+ if (l) l.ai = ai
86
+ return l
87
+ }
88
+ viewer.assetManager.registerGltfExtension(gltfCesiumRTCExtension)
89
+ viewer.assetManager.registerGltfExtension(gltfStructuralMetadataExtension)
90
+ viewer.assetManager.registerGltfExtension(gltfMeshFeaturesExtension)
91
+ viewer.assetManager.importer.addImporter(this._importer)
92
+ viewer.scene.addEventListener('addSceneObject', this._addSceneObject)
93
+ // viewer.scene.addEventListener('mainCameraChange', this._mainCameraChange)
94
+ // viewer.scene.addEventListener('mainCameraUpdate', this._mainCameraUpdate)
95
+ viewer.renderManager.addEventListener('preRender', this._preRender) // note - adding to renderManager preRender, not viewer. So its fired for each camera render
96
+ viewer.renderManager.addEventListener('resize', this._resize)
97
+ }
98
+
99
+ onRemove(viewer: ThreeViewer) {
100
+ viewer.assetManager.importer.removeImporter(this._importer)
101
+ viewer.assetManager.unregisterGltfExtension(gltfCesiumRTCExtension.name)
102
+ viewer.assetManager.unregisterGltfExtension(gltfStructuralMetadataExtension.name)
103
+ viewer.assetManager.unregisterGltfExtension(gltfMeshFeaturesExtension.name)
104
+ viewer.scene.removeEventListener('addSceneObject', this._addSceneObject)
105
+ // viewer.scene.removeEventListener('mainCameraChange', this._mainCameraChange)
106
+ // viewer.scene.removeEventListener('mainCameraUpdate', this._mainCameraUpdate)
107
+ viewer.renderManager.removeEventListener('preRender', this._preRender)
108
+ viewer.renderManager.removeEventListener('resize', this._resize)
109
+ // todo dispose all tiles renderers?
110
+ super.onRemove(viewer)
111
+ }
112
+
113
+ private _preRender/* : EventListener2<'preRender', ThreeViewerEventMap, ThreeViewer>*/ = () => {
114
+ const camera = this._viewer?.scene.renderCamera
115
+ if (!this._viewer || !camera) return
116
+ if (this._viewer.renderManager.frameCount > 0) return // from ProgressivePlugin
117
+ camera.updateProjectionMatrix()
118
+ camera.updateMatrixWorld()
119
+ for (const group of this.objects) {
120
+ // todo do we need to do this every frame for every camera?
121
+ group.tilesRenderer.setCamera(camera)
122
+ group.tilesRenderer.setResolutionFromRenderer(camera, this._viewer.renderManager.webglRenderer)
123
+ // group.tilesRenderer.frameCount = 0
124
+ // console.log('update tiles renderer')
125
+ group.tilesRenderer.update()
126
+ }
127
+ }
128
+
129
+ // private _mainCameraUpdate: EventListener2<'mainCameraUpdate', ISceneEventMap, IScene> = (e) => {
130
+ // const camera = e.camera ?? this._viewer?.scene.mainCamera
131
+ // if (!this._viewer || !camera) return
132
+ // camera.updateProjectionMatrix()
133
+ // camera.updateMatrixWorld()
134
+ // for (const group of this.objects) {
135
+ // group.tilesRenderer.update()
136
+ // }
137
+ // }
138
+ //
139
+ // private _mainCameraChange: EventListener2<'mainCameraChange', ISceneEventMap, IScene> = (e) => {
140
+ // const camera = e.camera
141
+ // if (!this._viewer) return
142
+ // for (const group of this.objects) {
143
+ // // todo deleteCamera?
144
+ // group.tilesRenderer.setCamera(camera)
145
+ // group.tilesRenderer.setResolutionFromRenderer(camera, this._viewer.renderManager.webglRenderer)
146
+ // }
147
+ // }
148
+
149
+ private _resize: EventListener2<'resize', IRenderManagerEventMap, IRenderManager> = () => {
150
+ if (!this._viewer) return
151
+ for (const group of this.objects) {
152
+ group.tilesRenderer.setResolutionFromRenderer(this._viewer.scene.mainCamera, this._viewer.renderManager.webglRenderer)
153
+ }
154
+ }
155
+
156
+ private _cachedRefs?: Pick<TilesRenderer, 'lruCache' | 'downloadQueue' | 'parseQueue'/* | 'processNodeQueue'*/>
157
+
158
+ private _addSceneObject: EventListener2<'addSceneObject', ISceneEventMap, IScene> = (e)=>{
159
+ const object = e.object
160
+ const group = object as TilesRendererGroup
161
+ // console.log(e)
162
+ if (!group || !group.tilesRenderer || !this._viewer) return
163
+
164
+ // set the second renderer to share the cache and queues from the first
165
+ if (!this._cachedRefs) {
166
+ this._cachedRefs = {
167
+ lruCache: group.tilesRenderer.lruCache,
168
+ downloadQueue: group.tilesRenderer.downloadQueue,
169
+ parseQueue: group.tilesRenderer.parseQueue,
170
+ // @ts-expect-error not in ts
171
+ processNodeQueue: group.tilesRenderer.processNodeQueue,
172
+ }
173
+ } else {
174
+ group.tilesRenderer.lruCache = this._cachedRefs.lruCache
175
+ group.tilesRenderer.downloadQueue = this._cachedRefs.downloadQueue
176
+ group.tilesRenderer.parseQueue = this._cachedRefs.parseQueue
177
+ // @ts-expect-error not in ts
178
+ group.tilesRenderer.processNodeQueue = this._cachedRefs.processNodeQueue
179
+ }
180
+
181
+ this.objects.push(group)
182
+
183
+ group.tilesRenderer.registerPlugin({
184
+ dispose: () => {
185
+ const index = this.objects.indexOf(group)
186
+ if (index !== -1) this.objects.splice(index, 1)
187
+ this.dispatchEvent({type: 'removeTile', group})
188
+ },
189
+ })
190
+ group.tilesRenderer.setCamera(this._viewer.scene.mainCamera)
191
+ group.tilesRenderer.setResolutionFromRenderer(this._viewer.scene.mainCamera, this._viewer.renderManager.webglRenderer)
192
+ group.tilesRenderer.update()
193
+ group.addEventListener('dispose', ()=>{
194
+ group.tilesRenderer.dispose()
195
+ })
196
+
197
+ this.dispatchEvent({type: 'addTile', group})
198
+ }
199
+
200
+ @uiButton()
201
+ async promptForURL() {
202
+ const url = await this._viewer?.dialog.prompt('TilesRendererPlugin: Enter URL for the root tileset', '', true)
203
+ if (!url) return
204
+ return this.load(url)
205
+ }
206
+ }
207
+
208
+ export class TilesRendererLoader extends Loader implements ILoader<TilesRendererGroup> {
209
+ isTilesRendererLoader = true
210
+ ai?: IAssetImporter
211
+ importOptions?: ImportAddOptions
212
+
213
+ plugins: ((o: TilesImportOptions, group: TilesRendererGroup)=>object|undefined)[] = [
214
+ ()=>new UpdateOnChangePlugin(),
215
+ (opts)=>opts?.ImplicitTilingPlugin !== false ? new ImplicitTilingPlugin() : undefined,
216
+ (opts)=>opts?.TilesFadePlugin !== false ? new TilesFadePlugin(typeof opts?.TilesFadePlugin === 'object' ? opts.TilesFadePlugin : undefined) : undefined,
217
+ (opts)=>opts?.CesiumIonAuthPlugin ? new CesiumIonAuthPlugin(typeof opts?.CesiumIonAuthPlugin === 'object' ? opts.CesiumIonAuthPlugin : undefined) : undefined,
218
+ ]
219
+
220
+ constructor(manager: LoadingManager) {
221
+ super(manager)
222
+ }
223
+
224
+ protected _createTilesRenderer(url: string) {
225
+
226
+ const tiles = new TilesRenderer(url)
227
+ tiles.manager = this.manager
228
+ tiles.fetchOptions.headers = new Headers(this.requestHeader)
229
+ tiles.fetchOptions.credentials = this.withCredentials ? 'include' : 'same-origin'
230
+ tiles.fetchOptions.mode = 'cors'
231
+
232
+ return tiles
233
+ }
234
+
235
+ load(url: string, onLoad: (data: unknown) => void, _onProgress?: (event: ProgressEvent) => void, _onError?: (err: unknown) => void) {
236
+ // todo
237
+ // let resourcePath = this.resourcePath || this.path || LoaderUtils.extractUrlBase(url)
238
+
239
+ const tiles = this._createTilesRenderer(url)
240
+ const group = iObjectCommons.upgradeObject3D.call(tiles.group) as TilesRendererGroup
241
+ group.autoUpgradeChildren = false
242
+
243
+ const opts = this.importOptions?.tiles ?? {}
244
+ tiles.errorTarget = opts.errorTarget ?? 1
245
+ const plugins = [...this.plugins, ...opts.plugins ?? []]
246
+ for (const plugin of plugins) {
247
+ const p = plugin(opts, group)
248
+ if (p) tiles.registerPlugin(p)
249
+ }
250
+
251
+ // bounds, similar to InstancedMesh
252
+ group.boundingBox = null
253
+ group.boundingSphere = null
254
+ group.computeBoundingBox = ()=>{
255
+ if (!group.boundingBox) group.boundingBox = new Box3B()
256
+ tiles.getBoundingBox(group.boundingBox)
257
+ }
258
+ group.computeBoundingSphere = ()=>{
259
+ if (!group.boundingSphere) group.boundingSphere = new Sphere()
260
+ tiles.getBoundingSphere(group.boundingSphere)
261
+ }
262
+ tiles.addEventListener('load-tile-set', (_e) => {
263
+ group.computeBoundingBox!()
264
+ group.computeBoundingSphere!()
265
+ })
266
+
267
+ // const sup = group.updateWorldMatrix
268
+ // todo remove in next version
269
+ group.updateWorldMatrix = (updateParents) => {
270
+ if (group.parent && updateParents) {
271
+ group.parent.updateWorldMatrix(updateParents, false)
272
+ }
273
+ // run the normal update function to ensure children and inverse matrices are in sync
274
+ group.updateMatrixWorld(true)
275
+ }
276
+
277
+ // Save promise to tell the viewer/scene when the load is finished, it can then autoScale, autoCenter etc
278
+ let resolve: any
279
+ // let reject: any
280
+ group._loadingPromise = new Promise<void>((res, _rej) => {
281
+ resolve = res
282
+ // reject = _rej
283
+ })
284
+ tiles.addEventListener('load-tile-set', (e) => {
285
+ const isRoot = e.tileSet === tiles.rootTileSet
286
+ if (isRoot && resolve) resolve()
287
+ })
288
+
289
+ const ai = this.ai
290
+ if (ai) {
291
+ const tmpFile = generateUUID()
292
+ ai.registerFile(tmpFile + '.gltf') // to set the gltf loader in manager
293
+ ai.registerFile(tmpFile + '.drc') // to set the draco loader in manager
294
+
295
+ const preprocessUrl = (url1: string) => {
296
+ if (tiles.preprocessURL) return tiles.preprocessURL(url1)
297
+ return url1
298
+ }
299
+ ai.addURLModifier(preprocessUrl)
300
+ tiles.registerPlugin({
301
+ dispose: () => {
302
+ if (ai) {
303
+ ai.unregisterFile(tmpFile + '.gltf')
304
+ ai.unregisterFile(tmpFile + '.drc')
305
+ ai.removeURLModifier(preprocessUrl)
306
+ }
307
+ },
308
+ })
309
+
310
+ }
311
+
312
+ tiles.addEventListener('tile-visibility-change', (_e) => {
313
+ // console.log(e)
314
+ })
315
+
316
+ const setDirty = (_e: any)=>{
317
+ // console.log(e)
318
+ group.setDirty({frameFade: false})
319
+ }
320
+ tiles.addEventListener('load-content', setDirty)
321
+ tiles.addEventListener('load-tile-set', setDirty)
322
+ tiles.addEventListener('needs-update', setDirty)
323
+
324
+ tiles.update()
325
+ onLoad(group)
326
+
327
+ }
328
+
329
+ }
330
+
331
+ export interface TilesImportOptions{
332
+ /**
333
+ * @default 1
334
+ */
335
+ errorTarget?: number
336
+ ImplicitTilingPlugin?: boolean
337
+ TilesFadePlugin?: boolean | {
338
+ maximumFadeOutTiles?: number,
339
+ fadeRootTiles?: boolean,
340
+ fadeDuration?: number,
341
+ }
342
+ CesiumIonAuthPlugin?: boolean | {
343
+ apiToken: string,
344
+ assetId?: string | null,
345
+ autoRefreshToken?: boolean
346
+ }
347
+ plugins?: ((opts: TilesImportOptions, group: TilesRendererGroup)=>object|undefined)[]
348
+ }
349
+
350
+ declare module 'threepipe'{
351
+ interface ImportAddOptions {
352
+ tiles?: TilesImportOptions
353
+ }
354
+ }
@@ -0,0 +1,40 @@
1
+ declare module '*.txt' {
2
+ const content: string
3
+ export default content
4
+ }
5
+ declare module '*.glsl' {
6
+ const content: string
7
+ export default content
8
+ }
9
+ declare module '*.vert' {
10
+ const content: string
11
+ export default content
12
+ }
13
+ declare module '*.frag' {
14
+ const content: string
15
+ export default content
16
+ }
17
+ declare module '*.module.scss' {
18
+ const content: any
19
+ export default content
20
+ export const stylesheet: string
21
+ }
22
+ declare module '*.module.css' {
23
+ const content: any
24
+ export default content
25
+ export const stylesheet: string
26
+ }
27
+ declare module '*.css' {
28
+ const content: string
29
+ export default content
30
+ }
31
+ declare module '*.css?inline' { // for vite
32
+ const content: string
33
+ export default content
34
+ }
35
+
36
+ // export {}
37
+
38
+ // hack for typedoc
39
+ // eslint-disable-next-line @typescript-eslint/naming-convention
40
+ // declare type OffscreenCanvas = HTMLCanvasElement
package/src/gltf.ts ADDED
@@ -0,0 +1,40 @@
1
+ import {
2
+ GLTFCesiumRTCExtension,
3
+ GLTFMeshFeaturesExtension,
4
+ GLTFStructuralMetadataExtension,
5
+ // @ts-expect-error moduleResolution issue
6
+ } from '3d-tiles-renderer/plugins'
7
+ import {AssetManager} from 'threepipe'
8
+
9
+ export const gltfCesiumRTCExtension = {
10
+ name: 'CESIUM_RTC' satisfies GLTFCesiumRTCExtension['name'],
11
+ import: (_p)=>new GLTFCesiumRTCExtension(),
12
+ export: (_w)=>({
13
+ // todo - save center in userData and access to write back as extension value
14
+ }),
15
+ textures: undefined,
16
+ } satisfies AssetManager['gltfExtensions'][number]
17
+
18
+ export const gltfStructuralMetadataExtension = {
19
+ name: 'EXT_structural_metadata' satisfies GLTFStructuralMetadataExtension['name'],
20
+ import: (_p)=>new GLTFStructuralMetadataExtension(),
21
+ export: (_w)=>({
22
+ // todo
23
+ // beforeParse: ()=>{
24
+ // throw new Error('not implemented')
25
+ // },
26
+ }),
27
+ textures: undefined,
28
+ } satisfies AssetManager['gltfExtensions'][number]
29
+
30
+ export const gltfMeshFeaturesExtension = {
31
+ name: 'EXT_mesh_features' satisfies GLTFMeshFeaturesExtension['name'],
32
+ import: (_p)=>new GLTFMeshFeaturesExtension(),
33
+ export: (_w)=>({
34
+ // todo
35
+ // beforeParse: ()=>{
36
+ // throw new Error('not implemented')
37
+ // },
38
+ }),
39
+ // textures: undefined, // todo
40
+ } satisfies AssetManager['gltfExtensions'][number]
package/src/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ export {TilesRendererPlugin, TilesRendererLoader, type TilesRendererGroup, type TilesImportOptions} from './TilesRendererPlugin'
2
+ export {B3DMLoadPlugin} from './B3DMLoadPlugin'
3
+ export {I3DMLoadPlugin} from './I3DMLoadPlugin'
4
+ export {PNTSLoadPlugin} from './PNTSLoadPlugin'
5
+ export {CMPTLoadPlugin} from './CMPTLoadPlugin'
6
+ export {DeepZoomImageLoadPlugin} from './DeepZoomImageLoadPlugin'
7
+ export {SlippyMapTilesLoadPlugin} from './SlippyMapTilesLoadPlugin'
8
+ export {EnvironmentControlsPlugin, EnvironmentControls2} from './EnvironmentControlsPlugin'
9
+ export {GlobeControlsPlugin, GlobeControls2} from './GlobeControlsPlugin'
10
+ export {
11
+ CesiumIonAuthPlugin,
12
+ ReorientationPlugin,
13
+ DebugTilesPlugin, GoogleCloudAuthPlugin,
14
+ LoadRegionPlugin, UnloadTilesPlugin, TileCompressionPlugin,
15
+ // @ts-expect-error moduleResolution issue
16
+ } from '3d-tiles-renderer/plugins'