gaussian-splat-lite 1.5.0 → 1.5.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.
package/CHANGELOG.md CHANGED
@@ -7,28 +7,34 @@ and this project follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.5.1] - 2026-10-27
11
+
12
+ ### Changed
13
+
14
+ - `gsl-build-lod` SH codebooks now match the original view-dependent color of large models more closely. Conversion takes slightly longer.
15
+
10
16
  ## [1.5.0] - 2026-10-27
11
17
 
12
18
  ### Added
13
19
 
14
- - Added `sources` to `RadStreamScheduler` and `SogStreamScheduler` to stream several inputs with one detail selection. The inputs share the splat budget and loading concurrency; RAD inputs also share both memory budgets, and each uses as much memory per Splat as the highest SH degree among them, limited by `maxSh`. See [RAD streaming](docs/RadStreamScheduler.md#multiple-inputs) and [SOG streaming](docs/SogStreamScheduler.md#multiple-inputs).
20
+ - Added `sources` to `RadStreamScheduler` and `SogStreamScheduler` to stream several inputs with one detail selection. The inputs share the splat budget and loading concurrency; RAD inputs also share both memory budgets; inputs with different SH degrees all use the memory of the highest one, up to `maxSh`. See [RAD streaming](docs/RadStreamScheduler.md#multiple-inputs) and [SOG streaming](docs/SogStreamScheduler.md#multiple-inputs).
15
21
  - Added an `environment` option to `SogStreamScheduler` and each of its `sources`. Set it to `false` to skip that input's environment.
16
- - Added `maxSh` to `RadStreamScheduler` and `SogStreamScheduler` to limit SH decoding, storage, and rendering. Set it at creation to `0`–`3` (default `3`) to reduce SH memory use; `0` keeps only the base color. RAD page budgets account for the reduced storage, and the built-in SOG loader skips higher-order SH assets at `0`.
17
- - Added a loading-time `maxSh` option to `SplatMesh` and `Splats`, and a `SplatLoader.maxSh` setting (`0`–`4`, default `4`). PLY, SPZ, SOG, and RAD loads omit higher SH bands from CPU arrays and GPU source textures.
18
- - Added default SH codebook compression to `gsl-build-lod`: up to 65,536 shared SH entries and a 16-bit index per splat. Compression can reduce file size at the cost of view-dependent detail; small models may grow. Use `--cluster-sh=<n>` to change the default 10 refinement iterations or `--no-cluster-sh` to store coefficients directly. Clustering uses CPU workers within the memory target. See [SH codebook](docs/BuildRad.md#sh-codebook).
22
+ - Added `maxSh` to `RadStreamScheduler` and `SogStreamScheduler` to limit SH decoding, storage, and rendering. Set it at creation to `0`–`3` (default `3`) to reduce memory use; `0` keeps only the base color, and streamed SOG then also skips downloading SH data.
23
+ - Added a loading-time `maxSh` option to `SplatMesh` and `Splats`, and a `SplatLoader.maxSh` setting (`0`–`4`, default `4`). Lower values reduce memory use.
24
+ - Added SH codebook compression to `gsl-build-lod`, on by default: splats share up to 65,536 SH entries. This can make large files much smaller at the cost of some view-dependent detail; small models may grow. Use `--cluster-sh=<n>` to change the default 10 refinement iterations or `--no-cluster-sh` to store SH without a codebook. Clustering stays within `--memory-budget`. See [SH codebook](docs/BuildRad.md#sh-codebook).
19
25
 
20
26
  ### Changed
21
27
 
22
28
  - Raised the minimum Node.js version to 22.12 for the package and `gsl-build-lod`.
23
29
  - `SplatMesh.maxSh` is now read-only and set through its constructor options, matching the streaming schedulers. Assigning `mesh.maxSh` now throws a `TypeError` in strict-mode code, including ES modules. Create a new mesh to change the limit. The viewer's Max SH control has been removed.
24
- - RAD streaming now uses fixed 65,536-splat page slots. Smaller chunks use a full slot; chunks larger than 65,536 splats are rejected during initialization.
30
+ - RAD streaming no longer accepts files with chunks of more than 65,536 splats. Files from `gsl-build-lod` are unaffected.
25
31
  - RAD and SOG schedulers now create their own `THREE.Group`; the `group` constructor option has been removed. Add and transform `streaming.group` instead.
26
- - RAD and SOG streaming upload written texture layers before their batches are first displayed. Each scheduler limits pending source texture uploads to 24 MiB until rendering submits them, preventing skipped renders from accumulating larger uploads. A larger SOG region proceeds alone.
27
- - `gsl-build-lod` now quantizes SH in fixed `1/128` steps instead of using adaptive per-band ranges. Both codebook and direct output clip coefficients to `[-127/128, 127/128]`. With `--no-cluster-sh`, original SPZ splats retain their SH coefficients except `-1`, which clips to `-127/128`.
32
+ - RAD and SOG streamed data now reaches the GPU only when you render. Keep rendering, not just calling `update()`, while waiting for `firstRenderable`.
33
+ - With `--no-cluster-sh`, `gsl-build-lod` now keeps the view-dependent color of SPZ inputs almost exactly.
28
34
 
29
35
  ### Fixed
30
36
 
31
- - Fixed delayed cache memory reclamation in `gsl-build-lod` when reserving memory for worker threads.
37
+ - Fixed `gsl-build-lod` briefly using more memory than `--memory-budget` when starting worker threads.
32
38
 
33
39
  ## [1.4.3] - 2026-10-25
34
40
 
@@ -703,7 +709,9 @@ and this project follows [Semantic Versioning](https://semver.org/).
703
709
 
704
710
  - Initial public release of the Three.js Gaussian Splatting renderer.
705
711
 
706
- [Unreleased]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.4.3...HEAD
712
+ [Unreleased]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.5.1...HEAD
713
+ [1.5.1]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.5.0...v1.5.1
714
+ [1.5.0]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.4.3...v1.5.0
707
715
  [1.4.3]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.4.2...v1.4.3
708
716
  [1.4.2]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.4.1...v1.4.2
709
717
  [1.4.1]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.4.0...v1.4.1
@@ -12,12 +12,15 @@ import { PagedArray } from "./storage.js";
12
12
  const MAX_CODES = 65536;
13
13
  // Training reads SAMPLE_SHARE of the splats, and at least SAMPLES_PER_CODE
14
14
  // per entry; larger models train on a sample by weight, and only the final
15
- // assignment reads all. Entries start at evenly spaced training splats,
16
- // best at heavy ones: on Elevator (3.9M splats after LOD) 16 per entry fit
17
- // better than all splats, and on C-NorthSouth (111M) 5% fit 8.5% closer
18
- // than 16 per entry, for 5% more conversion time.
19
- const SAMPLES_PER_CODE = 16;
20
- const SAMPLE_SHARE = 0.05;
15
+ // assignment reads all. Entries start at evenly spaced training splats.
16
+ // With codebooks shrunk to keep 16 per entry at 5%, renders of Elevator and
17
+ // JunkShop came 5–14% closer to the uncompressed SH at 10% than at 5%; on
18
+ // C-NorthSouth (111M splats after LOD) clustering took about 185 s, not 170.
19
+ // On Elevator (3.9M splats after LOD), 64 per entry, here all splats, came
20
+ // 5.8% closer than 16 at full detail, with 41% fewer pixels off by more than
21
+ // 32 levels in LOD views, in 18 s instead of 6 s.
22
+ const SAMPLES_PER_CODE = 64;
23
+ const SAMPLE_SHARE = 0.1;
21
24
  // Splats per job of a thread, and per call of the kernel.
22
25
  const JOB = 4096;
23
26
  const BATCH = 1024;
@@ -587,8 +590,8 @@ class Grouper {
587
590
  // weighted k-means as Spark does: entries start at evenly spaced splats,
588
591
  // each of `iterations` moves them to the weighted mean of their splats, an
589
592
  // entry without any stays, and a final pass labels each splat with its
590
- // nearest entry. Weights are area × opacity. Training uses 5% of the
591
- // splats, at least 16 per entry, sampled in proportion to their weights;
593
+ // nearest entry. Weights are area × opacity. Training uses 10% of the
594
+ // splats, at least 64 per entry, sampled in proportion to their weights;
592
595
  // with many entries, passes search only groups of them. Returns the
593
596
  // entries, `count` rows of `dims` SH coefficients, and the labels.
594
597
  export async function clusterSh(splats, iterations, module) {
package/docs/BuildRad.md CHANGED
@@ -59,9 +59,9 @@ gsl-build-lod scene.ply --cluster-sh=20
59
59
  gsl-build-lod scene.ply --no-cluster-sh
60
60
  ```
61
61
 
62
- By default, SH coefficients are stored as a shared codebook of up to 65,536 entries, and each splat stores the index of its entry. This can substantially reduce SH data for large models; the savings depend on the splat count and SH values. Models with at most 65,536 splats after LOD still store one codebook entry per splat plus labels, so the file may grow. Each splat's view-dependent color comes from its nearest entry, so highlights and reflections can lose some detail. Positions, shapes, base colors and LOD are unchanged. Use `--no-cluster-sh` to disable the codebook.
62
+ By default, SH coefficients are stored as a shared codebook of up to 65,536 entries, and each splat stores the index of its entry. This can substantially reduce SH data for large models; the savings depend on the splat count and SH values. Models with at most 65,536 splats after LOD still store one codebook entry per splat plus an index for each splat, so the file may grow. Each splat's view-dependent color comes from its nearest entry, so highlights and reflections can lose some detail. Positions, shapes, base colors and LOD are unchanged. Use `--no-cluster-sh` to disable the codebook.
63
63
 
64
- The codebook is refined in 10 iterations by default; `--cluster-sh=<n>` sets another number. Clustering runs on as many CPU cores as the memory target leaves room for and usually takes less time than the rest of the conversion. When there are more than 1,048,576 splats after LOD, the iterations use a sample that favors large, opaque splats: 1,048,576 splats or 5% of them, whichever is larger. Only the final assignment visits every splat. With 16,384 or more entries, each iteration and the final assignment compare a splat only with the entries in the groups of similar entries nearest to it; a few splats then get an entry that is nearly, but not exactly, the nearest.
64
+ The codebook is refined in 10 iterations by default; `--cluster-sh=<n>` sets another number. Clustering runs on as many CPU cores as the memory target leaves room for and usually takes less time than the rest of the conversion.
65
65
 
66
66
  Models without SH, or converted with `--max-sh 0`, are written without a codebook.
67
67
 
@@ -57,7 +57,7 @@ const streaming = new RadStreamScheduler({
57
57
  });
58
58
  ```
59
59
 
60
- All inputs use the coordinates stored in their files, relative to `streaming.group`. Detail is chosen across the combined scene, and the inputs share the splat budget, loading concurrency, and both memory budgets. Memory is reserved at the highest SH degree among the inputs, limited by `maxSh`; lower-SH inputs use the same per-Splat storage. Inputs may use different chunk sizes, up to 65,536 Splats per chunk.
60
+ All inputs use the coordinates stored in their files, relative to `streaming.group`. Detail is chosen across the combined scene, and the inputs share the splat budget, loading concurrency, and both memory budgets. Inputs with different SH degrees all use the memory of the highest one, up to `maxSh`.
61
61
 
62
62
  Each entry accepts the single-input loading options, including `resolveFile`, `manager`, `requestHeader`, and `withCredentials`; options omitted from an entry inherit the scheduler's settings. `sources` must be nonempty. Use separate schedulers for inputs that need independent transforms or budgets.
63
63
 
@@ -105,7 +105,7 @@ renderer.setAnimationLoop(() => {
105
105
  | `maxResidentGpuBytes` | 1 GiB | GPU memory budget for cached data, in bytes. Set a positive integer when creating the scheduler |
106
106
  | `fadeDurationMs` | `200` | Duration of the fade when the scene first appears and when detail changes; `0` switches instantly |
107
107
  | `cooldownMs` | `2000` | How long unused detail stays ready for reuse; it can be released sooner when either memory budget is reached. `0` releases it at once |
108
- | `maxConcurrentLoads` | `4` | Maximum number of simultaneous loads, regardless of page size. |
108
+ | `maxConcurrentLoads` | `4` | Maximum number of simultaneous loads |
109
109
  | `manager` | `THREE.DefaultLoadingManager` | Three.js loading manager, including its URL modifiers |
110
110
  | `requestHeader` / `withCredentials` | `{}` / `false` | Request settings. Sensitive settings are not sent to other origins |
111
111
  | `onChange` | — | Called when the scene needs a redraw |
@@ -137,7 +137,7 @@ Unused detail is released after `cooldownMs`, including while hidden, and loads
137
137
 
138
138
  Request a redraw from `onChange`, and keep calling `update()` on every animation tick, also when you skip the render. Loading, retries, and fades only make progress inside `update()`.
139
139
 
140
- Each scheduler has a 24 MiB allowance for source texture layers waiting for GPU upload. Repeated `update()` calls do not renew it; rendering submits the queued layers and makes room for more data. Keep rendering while waiting for `firstRenderable`, even before any batches are visible. This allowance does not cap total CPU/GPU memory or uploads from other schedulers.
140
+ New data reaches the screen only when you render, so keep rendering while waiting for `firstRenderable`, even before anything is visible.
141
141
 
142
142
  ### Picking
143
143
 
@@ -114,7 +114,7 @@ In WebXR, register `renderer.xr.getCamera()` in place of your camera, as shown f
114
114
 
115
115
  Request a redraw from `onChange`, and keep calling `update()` on every animation tick, also when you skip the render. Loading, retries, and fades only make progress inside `update()`.
116
116
 
117
- Each scheduler has a 24 MiB allowance for source texture layers waiting for GPU upload. Repeated `update()` calls do not renew it; rendering submits the queued layers and makes room for more data. A region larger than the allowance proceeds when no upload bytes are pending. Keep rendering while waiting for `firstRenderable`, even before any batches are visible. This allowance does not cap total CPU/GPU memory or uploads from other schedulers.
117
+ New data reaches the screen only when you render, so keep rendering while waiting for `firstRenderable`, even before anything is visible.
118
118
 
119
119
  ## Error recovery
120
120
 
@@ -17,6 +17,7 @@ scene.add(splat);
17
17
  ```
18
18
 
19
19
  Set `loader.maxSh` before loading to limit decoded and stored SH to degree `0`–`4` (default `4`).
20
+
20
21
  The callback form matches the usual Three.js pattern:
21
22
 
22
23
  ```js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gaussian-splat-lite",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Three.js Gaussian Splatting renderer with WebGPU/WebGL2, GPU sorting, streaming LOD, and high-precision GIS/ECEF support. Supports PLY, SPZ, SOG and RAD.",
5
5
  "author": "William Liu <lyz15972107087@gmail.com>",
6
6
  "type": "module",