babylonjs-loaders 9.12.1 → 9.13.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.
@@ -7418,9 +7418,13 @@ declare namespace BABYLON {
7418
7418
  * @param dataOrFiles Either the SOGRootData or a Map of filenames to Uint8Array file data (including meta.json)
7419
7419
  * @param rootUrl Base URL to load webp files from (if dataOrFiles is SOGRootData)
7420
7420
  * @param scene The Babylon.js scene
7421
+ * @param computeCpuPositions When true (default), means_l/means_u are read back on the CPU and `pack.positions`
7422
+ * is decoded for the sort worker / bounding box. Pass false when the caller will instead read the decoded
7423
+ * centers back from the GPU work buffer — then every attribute (including means) uses the fast direct
7424
+ * ImageBitmap upload (no `getImageData` readback) and `pack.positions` is left empty.
7421
7425
  * @returns Parsed splat info with `sogTextures` populated.
7422
7426
  */
7423
- export function ParseSogMetaAsTextures(dataOrFiles: SOGRootData | Map<string, Uint8Array>, rootUrl: string, scene: Scene): Promise<IParsedSplat>;
7427
+ export function ParseSogMetaAsTextures(dataOrFiles: SOGRootData | Map<string, Uint8Array>, rootUrl: string, scene: Scene, computeCpuPositions?: boolean): Promise<IParsedSplat>;
7424
7428
 
7425
7429
 
7426
7430
 
@@ -7470,6 +7474,13 @@ declare namespace BABYLON {
7470
7474
  private readonly _material;
7471
7475
  private readonly _quad;
7472
7476
  private _disposed;
7477
+ private _readFbo;
7478
+ /**
7479
+ * True when the engine supports the non-blocking GPU readback used by {@link readCentersRangeAsync}:
7480
+ * WebGL2 (PBO + fence) or WebGPU (copyTextureToBuffer + mapAsync). When false (e.g. WebGL1), callers must
7481
+ * decode positions on the CPU instead.
7482
+ */
7483
+ get supportsAsyncCentersReadback(): boolean;
7473
7484
  /**
7474
7485
  * Square edge length (in pixels) of the work-buffer textures.
7475
7486
  */
@@ -7492,6 +7503,18 @@ declare namespace BABYLON {
7492
7503
  * @param offset first splat index (pixel offset) for this file in the work buffer
7493
7504
  */
7494
7505
  decodeAsync(pack: ISogTexturePack, offset: number): Promise<void>;
7506
+ /**
7507
+ * Asynchronously reads back the decoded splat centers (stride-4 xyzw, w=1) for a contiguous splat range
7508
+ * from the work buffer's centers texture, using a non-blocking GPU readback (WebGL2 PBO + fence, or WebGPU
7509
+ * copyTextureToBuffer + mapAsync) so it never stalls the frame the way a CPU image decode does. The centers
7510
+ * texture already holds the GPU-decoded positions (identical to the CPU decode), so this replaces decoding
7511
+ * positions on the CPU from the means images. Returns null when async readback is unsupported (caller should
7512
+ * fall back to CPU decoding).
7513
+ * @param splatOffset first splat index of the range
7514
+ * @param splatCount number of splats in the range
7515
+ * @returns a stride-4 Float32Array of length `splatCount * 4`, or null when unsupported/failed
7516
+ */
7517
+ readCentersRangeAsync(splatOffset: number, splatCount: number): Promise<Nullable<Float32Array>>;
7495
7518
  /**
7496
7519
  * Disposes the work buffer and its decode resources.
7497
7520
  */
@@ -7537,6 +7560,11 @@ declare namespace BABYLON {
7537
7560
  targetLevel?: number;
7538
7561
  /** Frames remaining before this node may switch LOD again (oscillation damping). */
7539
7562
  lodCooldown?: number;
7563
+ /** True when the node's bounding box currently intersects the camera frustum. Drives the LOD bias that
7564
+ * pushes off-screen nodes to the coarsest level (they stay rendered, not hidden). */
7565
+ inFrustum?: boolean;
7566
+ /** Cached local-space bounding info used for the per-node frustum test (created once per leaf). */
7567
+ cullBounds?: BoundingInfo;
7540
7568
  }
7541
7569
  /**
7542
7570
  * Parsed contents of a PlayCanvas-style `lod-meta.json` file.
@@ -7590,6 +7618,12 @@ declare namespace BABYLON {
7590
7618
  * `1` caps detail at the next-coarser level, and so on. Higher values force a coarser maximum detail.
7591
7619
  */
7592
7620
  maxDetailLod?: number;
7621
+ /**
7622
+ * When true (default), LOD nodes outside the camera frustum are biased to their coarsest LOD rather than
7623
+ * rendered at full detail. They stay in the sort/render set so they appear instantly (at low detail) when
7624
+ * the camera turns toward them, then refine. Set to `false` to render every node at its distance LOD.
7625
+ */
7626
+ frustumCulling?: boolean;
7593
7627
  }
7594
7628
  /**
7595
7629
  * Streams a PlayCanvas-style SOG LOD scene (`lod-meta.json`) into a single Gaussian Splatting mesh.
@@ -7620,7 +7654,13 @@ declare namespace BABYLON {
7620
7654
  private _lodUpdateInterval;
7621
7655
  private _lodUpdateDistance;
7622
7656
  private _maxDetailLod;
7657
+ private _frustumCulling;
7658
+ private readonly _frustumPlanes;
7659
+ private readonly _cullViewProj;
7623
7660
  private _workBuffer;
7661
+ private _useGpuPositionReadback;
7662
+ private _readbackCandidate;
7663
+ private _readbackProbed;
7624
7664
  private readonly _fileBaseSplat;
7625
7665
  private readonly _fileCounts;
7626
7666
  private readonly _fileMeta;
@@ -7671,6 +7711,14 @@ declare namespace BABYLON {
7671
7711
  * for {@link maxDetailLod}.
7672
7712
  */
7673
7713
  get maxLodLevel(): number;
7714
+ /**
7715
+ * When true (default), nodes whose bounding box is outside the camera frustum are biased to the coarsest
7716
+ * LOD instead of being hidden. They stay in the sort/render set (their off-screen splats are clipped), so
7717
+ * turning the camera toward them shows low detail immediately with no invisible frames, then refines.
7718
+ * Changes take effect in real time.
7719
+ */
7720
+ get frustumCulling(): boolean;
7721
+ set frustumCulling(value: boolean);
7674
7722
  /**
7675
7723
  * When true, renders a wireframe box per LOD node, colored by the LOD level selected by {@link debugLodSource}.
7676
7724
  */
@@ -7762,6 +7810,35 @@ declare namespace BABYLON {
7762
7810
  * and promote any waiting nodes once they complete.
7763
7811
  */
7764
7812
  private _pumpDecodeQueue;
7813
+ /**
7814
+ * Writes a decoded splat range's positions into the shared buffer, expands the bounds, and incrementally
7815
+ * patches the sort worker.
7816
+ * @param positions stride-4 positions for the range
7817
+ * @param base first splat index of the range in the work buffer
7818
+ * @param count number of splats in the range
7819
+ */
7820
+ private _applyPositions;
7821
+ /**
7822
+ * One-time validation of GPU position readback: reads a sample of the just-decoded range back from the work
7823
+ * buffer and compares it to the CPU-decoded positions. Enables {@link _useGpuPositionReadback} only on an
7824
+ * exact (within float tolerance) match, so an unsupported or incorrect readback (e.g. a backend without the
7825
+ * required texture usage, or an orientation mismatch) safely keeps the CPU decode path.
7826
+ * @param base first splat index of the validated range
7827
+ * @param count number of splats in the range
7828
+ * @param cpuPositions the CPU-decoded stride-4 positions for the range (ground truth)
7829
+ */
7830
+ private _probeReadbackAsync;
7831
+ /**
7832
+ * Resolves the decoded positions for a splat range and applies them. Once GPU readback has been validated,
7833
+ * positions are read back from the work buffer (non-blocking) and `pack.positions` is empty; otherwise the
7834
+ * CPU-decoded `pack.positions` are used, and — on the first such decode — the GPU readback is validated
7835
+ * against them so subsequent decodes can use the fast path.
7836
+ * @param pack the parsed SOG pack (its `positions` is populated only on the CPU path)
7837
+ * @param base first splat index of the range in the work buffer
7838
+ * @param count number of splats in the range
7839
+ * @returns whether positions were applied
7840
+ */
7841
+ private _applyDecodedPositionsAsync;
7765
7842
  /**
7766
7843
  * Decodes the always-on environment bundle into its work-buffer block and activates its range.
7767
7844
  */
@@ -7795,13 +7872,21 @@ declare namespace BABYLON {
7795
7872
  */
7796
7873
  private _applyDesiredLods;
7797
7874
  /**
7798
- * Per-frame LOD streaming loop. Ticks cooldowns and pumps the decode queue every frame, but throttles
7799
- * the expensive LOD re-evaluation (optimal-LOD computation, budget balancing, desired-LOD application
7800
- * and interval rebuild) to run at most every {@link _lodUpdateInterval} frames and only after the camera
7801
- * has moved far enough, so continuous camera motion no longer rebuilds the interval set every frame. A
7802
- * budget change forces a single immediate update regardless of the throttle.
7875
+ * Per-frame LOD streaming loop. Ticks cooldowns and pumps the decode queue every frame, and runs the
7876
+ * cheap per-node frustum test every frame so the off-screen LOD bias tracks camera rotation. The LOD
7877
+ * re-evaluation is throttled to at most every {@link _lodUpdateInterval} frames once the camera has
7878
+ * translated far enough, but also runs immediately whenever a node enters/leaves the frustum (so its
7879
+ * detail upgrades/downgrades promptly) or a cap change forces it. Active ranges rebuild on any LOD change.
7803
7880
  */
7804
7881
  private _onLodFrame;
7882
+ /**
7883
+ * Updates each leaf node's {@link ISOGLODNode.inFrustum} flag from a per-node frustum test against the
7884
+ * active camera. When {@link frustumCulling} is disabled (or there is no camera) every node is marked
7885
+ * in-frustum. Bounds are static (from the LOD tree), so flags are valid for all nodes regardless of
7886
+ * decode state. Returns true when any node's in-frustum state changed (so the LOD bias must be re-applied).
7887
+ * @returns whether any node's in-frustum state changed
7888
+ */
7889
+ private _updateNodeFrustum;
7805
7890
  /**
7806
7891
  * Reads the splat count from SOG metadata.
7807
7892
  * @param data SOG metadata