@babylonjs/loaders 9.19.1 → 9.20.1

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 (52) hide show
  1. package/SPLAT/gaussianSplattingStream.d.ts +170 -1
  2. package/SPLAT/gaussianSplattingStream.js +516 -40
  3. package/SPLAT/gaussianSplattingStream.js.map +1 -1
  4. package/SPLAT/gaussianSplattingWorkBuffer.d.ts +163 -4
  5. package/SPLAT/gaussianSplattingWorkBuffer.js +683 -35
  6. package/SPLAT/gaussianSplattingWorkBuffer.js.map +1 -1
  7. package/SPLAT/gaussianSplattingWorkBufferShaders.d.ts +70 -2
  8. package/SPLAT/gaussianSplattingWorkBufferShaders.js +465 -4
  9. package/SPLAT/gaussianSplattingWorkBufferShaders.js.map +1 -1
  10. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +16 -1
  11. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +232 -25
  12. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
  13. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +52 -2
  14. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +108 -7
  15. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
  16. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.d.ts +37 -0
  17. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js +69 -0
  18. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js.map +1 -0
  19. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.d.ts +44 -0
  20. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.js +51 -0
  21. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.js.map +1 -0
  22. package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +1 -0
  23. package/glTF/2.0/Extensions/KHR_interactivity.pure.js +143 -12
  24. package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
  25. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +6 -0
  26. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -1
  27. package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +4 -0
  28. package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -1
  29. package/glTF/2.0/Extensions/KHR_node_visibility.pure.js +11 -0
  30. package/glTF/2.0/Extensions/KHR_node_visibility.pure.js.map +1 -1
  31. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.d.ts +126 -0
  32. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.js +251 -0
  33. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.js.map +1 -0
  34. package/glTF/2.0/Extensions/compositePathToObjectConverter.d.ts +51 -0
  35. package/glTF/2.0/Extensions/compositePathToObjectConverter.js +51 -0
  36. package/glTF/2.0/Extensions/compositePathToObjectConverter.js.map +1 -0
  37. package/glTF/2.0/Extensions/gltfPathToObjectConverter.js +69 -7
  38. package/glTF/2.0/Extensions/gltfPathToObjectConverter.js.map +1 -1
  39. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.d.ts +41 -0
  40. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.js +108 -0
  41. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.js.map +1 -0
  42. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.d.ts +28 -0
  43. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js +71 -0
  44. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js.map +1 -0
  45. package/glTF/2.0/Extensions/objectModelMapping.d.ts +118 -30
  46. package/glTF/2.0/Extensions/objectModelMapping.js +472 -70
  47. package/glTF/2.0/Extensions/objectModelMapping.js.map +1 -1
  48. package/glTF/2.0/Extensions/transmissionHelper.js +4 -0
  49. package/glTF/2.0/Extensions/transmissionHelper.js.map +1 -1
  50. package/glTF/2.0/glTFLoader.pure.js +2 -1
  51. package/glTF/2.0/glTFLoader.pure.js.map +1 -1
  52. package/package.json +3 -3
@@ -1,4 +1,5 @@
1
1
  import { GaussianSplattingMesh } from "@babylonjs/core/Meshes/GaussianSplatting/gaussianSplattingMesh.js";
2
+ import { type GaussianSplattingPartProxyMesh } from "@babylonjs/core/Meshes/GaussianSplatting/gaussianSplattingPartProxyMesh.js";
2
3
  import { type Scene } from "@babylonjs/core/scene.js";
3
4
  import { type Nullable } from "@babylonjs/core/types.js";
4
5
  import { Camera } from "@babylonjs/core/Cameras/camera.js";
@@ -116,7 +117,8 @@ export interface IGaussianSplattingStreamOptions {
116
117
  * GPU memory budget (in megabytes) for resident splats. When set (and smaller than the full dataset),
117
118
  * LOD files are streamed through a fixed-size work buffer and unreferenced files are evicted to stay
118
119
  * within budget, allowing datasets larger than a single full-dataset buffer. Converted to a splat count
119
- * at ~84 bytes/splat. Combined with {@link maxResidentSplats} by taking the smaller of the two.
120
+ * using the per-splat cost (core data plus any baked SH and rotation/scale textures). Combined with
121
+ * {@link maxResidentSplats} by taking the smaller of the two.
120
122
  */
121
123
  memoryBudgetMb?: number;
122
124
  /**
@@ -130,6 +132,30 @@ export interface IGaussianSplattingStreamOptions {
130
132
  * return to it avoids a re-download. Only used when a budget enables eviction. PlayCanvas default `100`.
131
133
  */
132
134
  evictionCooldownFrames?: number;
135
+ /**
136
+ * When set, the stream does not render itself; instead it reserves a region of this compound mesh and
137
+ * decodes/sorts into it, so its splats are depth-sorted and drawn in ONE pass together with the compound's
138
+ * other (static) parts. Used by {@link AddGaussianSplattingStreamPart}. The stream mesh becomes a hidden
139
+ * controller; the SOG up-axis orientation is applied to the reserved part's proxy transform.
140
+ * @internal
141
+ */
142
+ hostCompound?: GaussianSplattingMesh;
143
+ /**
144
+ * When true, higher-order spherical-harmonics carried by the SOG files (`shN`) are GPU-decoded into baked
145
+ * packed-u32 SH textures so the streamed splats render with view-dependent lighting (matching the non-stream
146
+ * `.spz`/`.sog` path) instead of flat DC-only color. The SH degree is the max `shN.bands` across the streamed
147
+ * files (lower-band files neutral-fill). No effect when the files carry no `shN`. Defaults to `true`, matching
148
+ * the non-stream path's always-decode-if-present behavior; set to `false` to force flat DC-only color even
149
+ * when the data carries `shN` (e.g. to save the decode cost/texture memory).
150
+ */
151
+ decodeSh?: boolean;
152
+ /**
153
+ * When true, each splat's rotation matrix + scale are GPU-decoded into half-float rotation/scale textures so the
154
+ * streamed splats participate in voxel-based IBL shadowing (matching the non-stream path). Standalone: the work
155
+ * buffer owns the rotation textures. Hosted: the compound's rotation textures become a shared render-target atlas
156
+ * the stream decodes into. Defaults to `false`.
157
+ */
158
+ needsRotationScale?: boolean;
133
159
  }
134
160
  /**
135
161
  * Streams a PlayCanvas-style SOG LOD scene (`lod-meta.json`) into a single Gaussian Splatting mesh.
@@ -164,6 +190,10 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
164
190
  private readonly _frustumPlanes;
165
191
  private readonly _cullViewProj;
166
192
  private _workBuffer;
193
+ private _decodeSh;
194
+ private _streamShDegree;
195
+ private _shTextureCount;
196
+ private _needsRotationScale;
167
197
  private _useGpuPositionReadback;
168
198
  private _readbackCandidate;
169
199
  private _readbackProbed;
@@ -177,6 +207,8 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
177
207
  private readonly _cancelledDecodes;
178
208
  private _evictionEnabled;
179
209
  private _residentBudget;
210
+ private _maxResidentSplats;
211
+ private _memoryBudgetMb;
180
212
  private _evictionCooldownFrames;
181
213
  private _decodeGate;
182
214
  private readonly _relayoutOldOffsets;
@@ -198,6 +230,19 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
198
230
  private _debugColorData;
199
231
  private _debugSignature;
200
232
  private _disposed;
233
+ private readonly _hostCompound;
234
+ private _host;
235
+ private _positionBase;
236
+ private _unsubBeforeRebuild;
237
+ private _unsubAfterRebuild;
238
+ private _hostUnsubRemove;
239
+ private _hostUnsubDispose;
240
+ private _partReleasedByHost;
241
+ private _positionSnapshot;
242
+ private _partReadyPromise;
243
+ private _partReadyResolve;
244
+ private _partReadyReject;
245
+ private _partReadySettled;
201
246
  /**
202
247
  * Returns true when the parsed JSON looks like a PlayCanvas-style `lod-meta.json` payload.
203
248
  * @param data parsed JSON
@@ -214,6 +259,35 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
214
259
  */
215
260
  constructor(name: string, metadata: ISOGLODMetadata, rootUrl: string, scene: Scene, options?: IGaussianSplattingStreamOptions);
216
261
  getClassName(): string;
262
+ /**
263
+ * When `_hostCompound` is set (i.e. this stream was created via {@link AddGaussianSplattingStreamPart}
264
+ * to drive a reserved region of another compound mesh, rather than rendering itself), this instance is
265
+ * disabled and never drawn — so it never runs its own depth-sort worker and the base class's readiness
266
+ * check (which waits for one) would never pass. Report ready unconditionally in that case; the host
267
+ * compound is the one actually rendering, and its own `isReady()` already covers real sort completion.
268
+ * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
269
+ * @returns true when ready
270
+ */
271
+ isReady(completeCheck?: boolean): boolean;
272
+ /**
273
+ * Hosted mode only: the compound part proxy this stream drives (world transform + visibility of the
274
+ * reserved region), or null before the part has been reserved (or when running standalone).
275
+ */
276
+ get streamingPartProxy(): Nullable<GaussianSplattingPartProxyMesh>;
277
+ /**
278
+ * Hosted mode only: resolves once the reserved part exists and its base layer has decoded (so the proxy's
279
+ * bounds are real and the part is ready to be placed/framed), or rejects if streaming fails/disposes first.
280
+ * Resolves immediately for a standalone stream. Used by {@link AddGaussianSplattingStreamPartAsync}.
281
+ * @returns a promise that settles when the hosted part is ready to use
282
+ */
283
+ whenPartReadyAsync(): Promise<void>;
284
+ /** Resolves the part-ready deferred (hosted mode); no-op if already settled or standalone. */
285
+ private _resolvePartReady;
286
+ /**
287
+ * Rejects the part-ready deferred (hosted mode); no-op if already settled or standalone.
288
+ * @param message failure reason surfaced to the awaiter
289
+ */
290
+ private _rejectPartReady;
217
291
  /**
218
292
  * Resolves once the scene is fully streamed and displayed for the current camera: a LOD re-evaluation has
219
293
  * run for the current point of view, every reachable LOD file has finished downloading and decoding (no
@@ -269,6 +343,23 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
269
343
  get debugLodSource(): GaussianSplattingStreamDebugLodSource;
270
344
  set debugLodSource(value: GaussianSplattingStreamDebugLodSource);
271
345
  dispose(doNotRecurse?: boolean): void;
346
+ /**
347
+ * Disposes this stream (which tombstones its region) and then compacts the host once to actually reclaim the
348
+ * reserved rows. Used on a definitive load failure / empty result — a discrete, one-off reclaim, versus a bare
349
+ * {@link dispose} that only tombstones so tearing down several parts doesn't rebuild the atlas repeatedly.
350
+ */
351
+ private _disposeAndReclaim;
352
+ /**
353
+ * The world matrix that actually places this stream's splats, used to map the camera into the space the
354
+ * node bounds live in (for LOD distance) and to build per-node world AABBs (for frustum culling). Standalone:
355
+ * this controller mesh carries the transform. Hosted: this controller is a hidden, unplaced node — the splats
356
+ * are placed by the reserved part's proxy (SOG up-axis basis composed with the host's placement), so LOD and
357
+ * culling MUST use the proxy's world matrix or they compute distances/frustum tests in the wrong space
358
+ * (producing wrong per-chunk LODs, i.e. holes, whenever the host applies a non-identity transform).
359
+ * @param force when true, forces a full world-matrix recompute (else uses the renderId/sync fast-path)
360
+ * @returns the effective world matrix for LOD/culling
361
+ */
362
+ private _getEffectiveWorldMatrix;
272
363
  /**
273
364
  * Re-evaluates the optimal LOD for every node based on the camera position. The result is stored in
274
365
  * each node's `optimalLod`. Rendering is unaffected; this currently drives only diagnostics and the
@@ -326,6 +417,22 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
326
417
  * base layer, then installs the per-frame loop that streams finer LODs on demand.
327
418
  */
328
419
  private _streamAllAsync;
420
+ /**
421
+ * Waits (up to a frame cap) until the work buffer's backup/restore copy shaders are compiled, so a later
422
+ * grow/compaction can preserve this hosted region (see {@link GaussianSplattingWorkBuffer.backupRegion}).
423
+ * Polls per rendered frame: shader readiness here depends on the render loop (and the shared atlas can be
424
+ * rebuilt concurrently), so this stays synchronized with the render-driven decode and always makes progress.
425
+ * On timeout it proceeds best-effort — a subsequent grow/compaction then warns rather than blocking decode.
426
+ * @param wb the hosted work buffer to wait on
427
+ */
428
+ private _waitForCanBackupAsync;
429
+ /**
430
+ * Resolves the resident-splat budget from the raw options, sizing a memory (MB) budget with the actual per-splat
431
+ * GPU+CPU cost — core data plus the baked SH textures and rotation/scale textures when enabled — so SH/rotation
432
+ * assets don't silently consume up to double the configured budget. Requires the SH degree (from the metadata
433
+ * pre-pass) to be known. The smaller of the splat-count and memory budgets wins.
434
+ */
435
+ private _resolveResidentBudget;
329
436
  /**
330
437
  * Collects the unique set of source file indices referenced by any LOD of any leaf, sorted ascending.
331
438
  * @returns sorted unique file indices
@@ -356,6 +463,21 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
356
463
  * @param count number of splats in the range
357
464
  */
358
465
  private _applyPositions;
466
+ /**
467
+ * Sets the active source ranges (local to the stream's buffer) on the render sink.
468
+ * @param localRanges active ranges in the stream's local index space
469
+ */
470
+ private _sinkSetActiveRanges;
471
+ /**
472
+ * Patches a decoded position range (local offset) into the render sink's sort worker.
473
+ * @param base first splat index of the range, local to the stream's buffer
474
+ * @param count number of splats in the range
475
+ */
476
+ private _sinkPostPositionsRange;
477
+ /** Re-posts the full position/part set to the render sink's worker (after a relayout moved the region). */
478
+ private _sinkNotifyDataChanged;
479
+ /** Whether the render sink's depth sort is settled. */
480
+ private get _sinkIsDepthSortSettled();
359
481
  /**
360
482
  * One-time validation of GPU position readback: reads a sample of the just-decoded range back from the work
361
483
  * buffer and compares it to the CPU-decoded positions. Enables {@link _useGpuPositionReadback} only on an
@@ -496,6 +618,13 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
496
618
  * @returns the splat count
497
619
  */
498
620
  private static _GetSplatCount;
621
+ /**
622
+ * Reads a SOG file's higher-order SH degree and coefficient count from its metadata, mirroring
623
+ * {@link ParseSogDatas}'s `coeffs`/`shDegree` derivation. Returns zeros when the file carries no `shN`.
624
+ * @param data parsed SOG root metadata
625
+ * @returns the SH degree and higher-order coefficient count (excludes the DC/SH0 term)
626
+ */
627
+ private static _GetShInfo;
499
628
  /**
500
629
  * Disposes all GPU source textures of a SOG pack (they are only needed for the one decode pass).
501
630
  * @param pack the SOG texture pack
@@ -526,4 +655,44 @@ export declare class GaussianSplattingStream extends GaussianSplattingMesh {
526
655
  */
527
656
  private _unzipAsync;
528
657
  }
658
+ /**
659
+ * Adds a PlayCanvas-style SOG LOD stream as a part of a compound Gaussian Splatting mesh, so the streamed
660
+ * splats are depth-sorted and rendered in ONE pass together with the compound's other (static) parts.
661
+ *
662
+ * The returned mesh is a hidden controller: it streams SOG LOD files, GPU-decodes them into a reserved region
663
+ * of the compound's shared atlas, and drives which of its splats are active (LOD) — the compound owns the sort
664
+ * and the single instanced draw. The SOG up-axis orientation is applied to the reserved part's proxy transform;
665
+ * move/hide the part via the proxy (`streamController` exposes it once streaming has started).
666
+ * @param compound the compound mesh to add the streamed part to
667
+ * @param name name for the streaming controller / part
668
+ * @param metadata parsed `lod-meta.json`
669
+ * @param rootUrl base URL the metadata's relative paths resolve against
670
+ * @param options streaming options
671
+ * @returns the streaming controller mesh (hidden; drives the reserved compound part)
672
+ * @experimental
673
+ */
674
+ export declare function AddGaussianSplattingStreamPart(compound: GaussianSplattingMesh, name: string, metadata: ISOGLODMetadata, rootUrl: string, options?: IGaussianSplattingStreamOptions): GaussianSplattingStream;
675
+ /**
676
+ * Adds a PlayCanvas-style SOG LOD stream as a part of a compound Gaussian Splatting mesh and resolves once the
677
+ * part is ready to use, returning its {@link GaussianSplattingPartProxyMesh} — the same handle
678
+ * `GaussianSplattingCompoundMesh.addPart` returns for a static part. This lets a host application treat a
679
+ * streamed splat exactly like any other compound part (place/frame/gizmo via the proxy, remove via
680
+ * `compound.removePart(proxy.partIndex)`); the streaming controller lives behind the proxy and is disposed
681
+ * automatically when the part is removed.
682
+ *
683
+ * Resolves after the reserved region exists and its base layer has decoded (so the proxy's bounds are real),
684
+ * and rejects if streaming fails before that (the partially-constructed stream is disposed on rejection).
685
+ *
686
+ * NOTE: the base-layer decode runs on the GPU inside the scene's render loop, so this promise only resolves once
687
+ * the scene is rendering. Do not `await` it before the render loop has started (it would never resolve) — start
688
+ * rendering (e.g. `engine.runRenderLoop`) first, or `await` it concurrently with the first frames.
689
+ * @param compound the compound mesh to add the streamed part to
690
+ * @param name name for the streaming controller / part
691
+ * @param metadata parsed `lod-meta.json`
692
+ * @param rootUrl base URL the metadata's relative paths resolve against
693
+ * @param options streaming options
694
+ * @returns the part proxy driving the streamed region, ready to place/frame
695
+ * @experimental
696
+ */
697
+ export declare function AddGaussianSplattingStreamPartAsync(compound: GaussianSplattingMesh, name: string, metadata: ISOGLODMetadata, rootUrl: string, options?: IGaussianSplattingStreamOptions): Promise<GaussianSplattingPartProxyMesh>;
529
698
  export {};