gaussian-splat-lite 1.2.0 → 1.2.2
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 +44 -2
- package/README.md +22 -13
- package/dist/gaussian-splat-lite.cjs +819 -88
- package/dist/gaussian-splat-lite.cjs.map +1 -1
- package/dist/gaussian-splat-lite.min.cjs +81 -20
- package/dist/gaussian-splat-lite.min.cjs.map +1 -1
- package/dist/gaussian-splat-lite.module.js +821 -90
- package/dist/gaussian-splat-lite.module.js.map +1 -1
- package/dist/gaussian-splat-lite.module.min.js +2984 -2427
- package/dist/gaussian-splat-lite.module.min.js.map +1 -1
- package/dist/types/addons/TAANode.d.cts +4 -2
- package/dist/types/addons/TAANode.d.ts +4 -2
- package/dist/types/addons/TAAPass.d.cts +6 -15
- package/dist/types/addons/TAAPass.d.ts +6 -15
- package/dist/types/addons/taaShared.d.cts +4 -2
- package/dist/types/addons/taaShared.d.ts +4 -2
- package/dist/types/capture/SplatCapture.d.cts +66 -0
- package/dist/types/capture/SplatCapture.d.ts +66 -0
- package/dist/types/capture/WebGLCapture.d.cts +13 -0
- package/dist/types/capture/WebGLCapture.d.ts +13 -0
- package/dist/types/capture/WebGPUCapture.d.cts +17 -0
- package/dist/types/capture/WebGPUCapture.d.ts +17 -0
- package/dist/types/capture/pixels.d.cts +5 -0
- package/dist/types/capture/pixels.d.ts +5 -0
- package/dist/types/capture/rendererState.d.cts +3 -0
- package/dist/types/capture/rendererState.d.ts +3 -0
- package/dist/types/capture/sceneView.d.cts +3 -0
- package/dist/types/capture/sceneView.d.ts +3 -0
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/rendering/GaussianSplatRenderer.d.cts +17 -11
- package/dist/types/rendering/GaussianSplatRenderer.d.ts +17 -11
- package/dist/types/rendering/SplatAccumulator.d.cts +2 -1
- package/dist/types/rendering/SplatAccumulator.d.ts +2 -1
- package/dist/types/rendering/backend.d.cts +1 -1
- package/dist/types/rendering/backend.d.ts +1 -1
- package/dist/types/rendering/rendererUtils.d.cts +1 -5
- package/dist/types/rendering/rendererUtils.d.ts +1 -5
- package/dist/types/rendering/tsl/ProjectionProgram.d.cts +2 -0
- package/dist/types/rendering/tsl/ProjectionProgram.d.ts +2 -0
- package/dist/types/rendering/tsl/SplatMaterial.d.cts +1 -0
- package/dist/types/rendering/tsl/SplatMaterial.d.ts +1 -0
- package/dist/types/rendering/tsl/tslCompat.d.cts +1 -0
- package/dist/types/rendering/tsl/tslCompat.d.ts +1 -0
- package/dist/types/rendering/uniforms.d.cts +3 -3
- package/dist/types/rendering/uniforms.d.ts +3 -3
- package/dist/types/scene/SplatMesh.d.cts +1 -1
- package/dist/types/scene/SplatMesh.d.ts +1 -1
- package/docs/Architecture.md +54 -3
- package/docs/GaussianSplatRenderer.md +71 -55
- package/docs/PostDecode.md +52 -36
- package/docs/RadStreamScheduler.md +53 -41
- package/docs/SogStreamScheduler.md +49 -39
- package/docs/SplatCapture.md +147 -0
- package/docs/SplatEdit.md +33 -26
- package/docs/SplatFileType.md +11 -13
- package/docs/SplatLoader.md +19 -14
- package/docs/SplatMesh.md +69 -49
- package/docs/Splats.md +33 -26
- package/docs/StochasticRendering.md +27 -30
- package/docs/TAAPass.md +98 -73
- package/package.json +1 -1
- package/docs/SplatAccumulator.md +0 -37
package/docs/SplatLoader.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[Back to documentation](../README.md#documentation)
|
|
4
4
|
|
|
5
|
-
`SplatLoader`
|
|
5
|
+
`SplatLoader` works like other Three.js loaders. It loads a model as [Splats](Splats.md) data, and `parse()` turns that data into a `SplatMesh` for your scene. The format is detected automatically.
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
8
|
import { SplatLoader } from "gaussian-splat-lite";
|
|
@@ -16,7 +16,7 @@ const splat = loader.parse(decoded);
|
|
|
16
16
|
scene.add(splat);
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
The callback form matches the
|
|
19
|
+
The callback form matches the usual Three.js pattern:
|
|
20
20
|
|
|
21
21
|
```js
|
|
22
22
|
loader.load(
|
|
@@ -27,7 +27,13 @@ loader.load(
|
|
|
27
27
|
);
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
`
|
|
30
|
+
If you do not need the loader API, `new SplatMesh({ url })` loads a model in one step; see [SplatMesh](SplatMesh.md).
|
|
31
|
+
|
|
32
|
+
For large RAD scenes with levels of detail, use [RadStreamScheduler](RadStreamScheduler.md). For SOG `lod-meta.json` scenes, use [SogStreamScheduler](SogStreamScheduler.md).
|
|
33
|
+
|
|
34
|
+
## Cancel loading
|
|
35
|
+
|
|
36
|
+
`loadAsync(url, onProgress?, signal?)` accepts an optional `AbortSignal`:
|
|
31
37
|
|
|
32
38
|
```js
|
|
33
39
|
const controller = new AbortController();
|
|
@@ -35,26 +41,25 @@ const loading = loader.loadAsync("/assets/model.sog", undefined, controller.sign
|
|
|
35
41
|
controller.abort(); // `loading` rejects with the signal's reason.
|
|
36
42
|
```
|
|
37
43
|
|
|
38
|
-
`loader.abort()` cancels every load the loader has in progress; loads started afterwards are not affected. For `Splats` or `SplatMesh
|
|
39
|
-
|
|
40
|
-
For large RAD scenes with levels of detail, use [RadStreamScheduler](RadStreamScheduler.md).
|
|
41
|
-
For `lod-meta.json` scenes, use [SogStreamScheduler](SogStreamScheduler.md).
|
|
44
|
+
`loader.abort()` cancels every load the loader has in progress; loads started afterwards are not affected. For a `Splats` or `SplatMesh` that is still loading, call its `dispose()`.
|
|
42
45
|
|
|
43
46
|
## Loading progress
|
|
44
47
|
|
|
45
|
-
`onProgress` receives a `SplatProgressEvent
|
|
48
|
+
`onProgress` receives a `SplatProgressEvent`: a standard `ProgressEvent` with an extra `stage` field. `Splats` and `SplatMesh` report progress the same way.
|
|
46
49
|
|
|
47
50
|
| `stage` | `loaded` / `total` |
|
|
48
51
|
| --- | --- |
|
|
49
|
-
| `download` | Bytes read or downloaded; `total === 0` means
|
|
50
|
-
| `postDecode` | Splats processed by
|
|
51
|
-
| `optimize` |
|
|
52
|
+
| `download` | Bytes read or downloaded; `total === 0` means the size is unknown |
|
|
53
|
+
| `postDecode` | Splats processed by your [`postDecode`](PostDecode.md) program; skipped when none is set |
|
|
54
|
+
| `optimize` | Steps completed while preparing the model for rendering |
|
|
55
|
+
|
|
56
|
+
Progress starts again from zero for each stage. Use `event.loaded / event.total` when `event.lengthComputable` is true. It measures completed work, not time.
|
|
52
57
|
|
|
53
|
-
|
|
58
|
+
The model is ready when `loadAsync()` or `.initialized` resolves, which can be a little after the download reaches 100%.
|
|
54
59
|
|
|
55
60
|
## Local split files
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
A single `.sog` or `.rad` file needs only `file`. Some models are split across several files: a SOG `meta.json` with `.webp` images, or a RAD file with `.radc` pages. For these, pass the main file as `file` and supply the others through `resolveFile`:
|
|
58
63
|
|
|
59
64
|
```js
|
|
60
65
|
import { SplatMesh } from "gaussian-splat-lite";
|
|
@@ -75,4 +80,4 @@ scene.add(mesh);
|
|
|
75
80
|
await mesh.initialized;
|
|
76
81
|
```
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
`resolveFile` is called with each file name the model refers to. Return a URL, `Blob`, `Uint8Array`, or `ArrayBuffer`, directly or as a promise. If the model refers to files in subfolders, match those paths.
|
package/docs/SplatMesh.md
CHANGED
|
@@ -2,15 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
[Back to documentation](../README.md#documentation)
|
|
4
4
|
|
|
5
|
-
`SplatMesh` is a `THREE.Object3D
|
|
5
|
+
A Splat model in your scene. `SplatMesh` is a `THREE.Object3D`, so position, rotation, scale, visibility, layers, and children work as usual.
|
|
6
6
|
|
|
7
|
-
```
|
|
8
|
-
|
|
7
|
+
```js
|
|
8
|
+
import { SplatMesh } from "gaussian-splat-lite";
|
|
9
|
+
|
|
10
|
+
const splat = new SplatMesh({ url: "/assets/model.spz" });
|
|
11
|
+
scene.add(splat);
|
|
12
|
+
await splat.initialized;
|
|
9
13
|
```
|
|
10
14
|
|
|
11
15
|
## Loading
|
|
12
16
|
|
|
13
|
-
Use `url` for remote
|
|
17
|
+
Use `url` for a remote file. For a local PLY, SPZ, SOG, or RAD file:
|
|
14
18
|
|
|
15
19
|
```js
|
|
16
20
|
const file = fileInput.files[0];
|
|
@@ -19,68 +23,85 @@ scene.add(splat);
|
|
|
19
23
|
await splat.initialized;
|
|
20
24
|
```
|
|
21
25
|
|
|
22
|
-
`file` accepts a `File` or `Blob`. For
|
|
26
|
+
`file` accepts a `File` or `Blob`. For data already in memory, use `fileBytes`. The format is detected from the file name; pass `fileName` or [`fileType`](SplatFileType.md) when there is no name to go by.
|
|
27
|
+
|
|
28
|
+
Splats are reordered while loading, so their indices differ from the order in the file; see [data rules](Splats.md#data-rules).
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
For large streamed scenes, use [RadStreamScheduler](RadStreamScheduler.md) or [SogStreamScheduler](SogStreamScheduler.md) instead.
|
|
25
31
|
|
|
26
32
|
## Options
|
|
27
33
|
|
|
28
34
|
| Option | Type | Default | Description |
|
|
29
35
|
| --- | --- | --- | --- |
|
|
30
|
-
| `url` | `string` | `undefined` | PLY/SPZ/SOG/RAD file or SOG
|
|
36
|
+
| `url` | `string` | `undefined` | PLY/SPZ/SOG/RAD file or SOG `meta.json` URL |
|
|
31
37
|
| `file` | `Blob` (including `File`) | `undefined` | Local file |
|
|
32
38
|
| `fileBytes` | `Uint8Array \| ArrayBuffer` | `undefined` | Complete file data in memory |
|
|
33
|
-
| `fileType` | `SplatFileType` |
|
|
34
|
-
| `fileName` | `string` | `File.name` when available |
|
|
35
|
-
| `resolveFile` | `SplatFileResolver` | `undefined` |
|
|
36
|
-
| `postDecode` | `SplatPostDecodeProgram` | `undefined` |
|
|
37
|
-
| `splats` | `Splats` | New `Splats` |
|
|
38
|
-
| `onProgress` | `(event: SplatProgressEvent) => void` | `undefined` | [
|
|
39
|
-
| `onLoad` | `(mesh) => void \| Promise<void>` | `undefined` | Called
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
|
|
45
|
-
Choose at most one of `url`, `file`, `fileBytes`, or `splats`;
|
|
46
|
-
|
|
47
|
-
##
|
|
39
|
+
| `fileType` | `SplatFileType` | Detected from the name | Set the format explicitly: `PLY`, `SPZ`, `SOG`, or `RAD` |
|
|
40
|
+
| `fileName` | `string` | `File.name` when available | Name used to detect the format |
|
|
41
|
+
| `resolveFile` | `SplatFileResolver` | `undefined` | Supply the extra files of a split SOG or RAD model; see [local split files](SplatLoader.md#local-split-files) |
|
|
42
|
+
| `postDecode` | `SplatPostDecodeProgram` | `undefined` | [Change each Splat while loading](PostDecode.md) |
|
|
43
|
+
| `splats` | `Splats` | New `Splats` | Use existing [Splats](Splats.md) data instead of loading |
|
|
44
|
+
| `onProgress` | `(event: SplatProgressEvent) => void` | `undefined` | [Loading progress](SplatLoader.md#loading-progress) callback |
|
|
45
|
+
| `onLoad` | `(mesh) => void \| Promise<void>` | `undefined` | Called when loading completes |
|
|
46
|
+
| `onFrame` | `({ mesh, time, deltaTime }) => void` | `undefined` | Called before each update of the model; use it for animation |
|
|
47
|
+
| `editable` | `boolean` | `true` | Allow [SDF edits](SplatEdit.md) to affect this model |
|
|
48
|
+
| `raycastable` | `boolean` | `true` | Include this model in Three.js raycasting |
|
|
49
|
+
| `minRaycastOpacity` | `number` | `0.15` | Ignore more transparent areas when picking; higher values narrow the area that can be hit |
|
|
50
|
+
|
|
51
|
+
Choose at most one of `url`, `file`, `fileBytes`, or `splats`; combining them throws.
|
|
52
|
+
|
|
53
|
+
## Properties
|
|
48
54
|
|
|
49
55
|
| Property | Type / default | Description |
|
|
50
56
|
| --- | --- | --- |
|
|
51
|
-
| `initialized` | `Promise<SplatMesh>` | Resolves
|
|
52
|
-
| `isInitialized` | `boolean` | Whether
|
|
57
|
+
| `initialized` | `Promise<SplatMesh>` | Resolves when loading and the `onLoad` callback have finished |
|
|
58
|
+
| `isInitialized` | `boolean` | Whether loading has finished |
|
|
53
59
|
| `numSplats` | `number` | Current Splat count |
|
|
54
|
-
| `recolor` | `THREE.Color(1, 1, 1)` |
|
|
55
|
-
| `opacity` | `1` | Opacity multiplier
|
|
56
|
-
| `maxSh` | `3` | Limit view-dependent color detail; `0` uses base color only |
|
|
57
|
-
| `edits` | `SplatEdit[] \| null` | Explicit
|
|
58
|
-
| `splats` | `Splats \| undefined` |
|
|
59
|
-
| `needsUpdate` | `boolean` setter | Set to `true` to force a refresh
|
|
60
|
+
| `recolor` | `THREE.Color(1, 1, 1)` | Color multiplier for the whole model |
|
|
61
|
+
| `opacity` | `1` | Opacity multiplier for the whole model |
|
|
62
|
+
| `maxSh` | `3` | Limit view-dependent color detail; `0` uses the base color only |
|
|
63
|
+
| `edits` | `SplatEdit[] \| null` | Explicit list of [edits](SplatEdit.md) for this mesh |
|
|
64
|
+
| `splats` | `Splats \| undefined` | The model's [Splats](Splats.md) data |
|
|
65
|
+
| `needsUpdate` | `boolean` setter | Set to `true` to force a refresh |
|
|
60
66
|
|
|
61
|
-
|
|
67
|
+
Changes to the transform, `recolor`, `opacity`, `maxSh`, and edits are picked up automatically. If the mesh's `Splats` is loaded again, `initialized` and `isInitialized` follow the new load, and `onLoad` runs again when it finishes.
|
|
62
68
|
|
|
63
|
-
##
|
|
69
|
+
## Methods
|
|
64
70
|
|
|
65
71
|
```ts
|
|
66
72
|
await mesh.initialized;
|
|
67
73
|
|
|
68
|
-
mesh.getBoundingBox(); //
|
|
69
|
-
mesh.getBoundingBox(false); //
|
|
74
|
+
mesh.getBoundingBox(); // Box around the Splat centers.
|
|
75
|
+
mesh.getBoundingBox(false); // Box that also covers each Splat's size and shape.
|
|
70
76
|
|
|
71
77
|
mesh.forEachSplat((index, center, scales, quaternion, opacity, color) => {});
|
|
72
78
|
|
|
73
|
-
mesh.updateVersion(); // Regenerate and re-sort.
|
|
74
|
-
mesh.updateVersion({ sort: false }); // Appearance only; reuse sorting.
|
|
75
|
-
mesh.updateMappingVersion(); // Count or mapping changed.
|
|
76
79
|
mesh.dispose();
|
|
77
80
|
```
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
### Bounding box
|
|
83
|
+
|
|
84
|
+
`getBoundingBox()` returns a new `Box3` in the mesh's local space; the mesh must be initialized first. To avoid creating a box each time, pass one as the second argument: `mesh.getBoundingBox(true, target)`.
|
|
85
|
+
|
|
86
|
+
- Pass `false` to cover each Splat's full size instead of only its center. Nearly transparent Splats, with opacity below `0.01`, are left out.
|
|
87
|
+
- The box describes the loaded data. It does not follow renderer settings, `opacity`, streaming fades, or SDF edits.
|
|
88
|
+
- For streamed models, the box follows the detail that is currently shown. With RAD it can be somewhat larger.
|
|
80
89
|
|
|
81
|
-
For world
|
|
90
|
+
For a box in world space, update the world matrix and apply `mesh.matrixWorld` to the result.
|
|
82
91
|
|
|
83
|
-
|
|
92
|
+
### Forcing an update
|
|
93
|
+
|
|
94
|
+
You rarely need these. They are for changes the mesh cannot detect by itself:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
mesh.updateVersion(); // Refresh the model and sort it again.
|
|
98
|
+
mesh.updateVersion({ sort: false }); // Refresh appearance only; keep the sort order.
|
|
99
|
+
mesh.updateMappingVersion(); // The Splat count changed.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Disposing
|
|
103
|
+
|
|
104
|
+
`mesh.dispose()` also disposes its `Splats`, even data you supplied yourself. To keep the data for reuse:
|
|
84
105
|
|
|
85
106
|
```js
|
|
86
107
|
await mesh.initialized;
|
|
@@ -88,7 +109,7 @@ const data = mesh.splats;
|
|
|
88
109
|
mesh.removeFromParent();
|
|
89
110
|
mesh.splats = undefined;
|
|
90
111
|
mesh.dispose();
|
|
91
|
-
// Call data?.dispose() when
|
|
112
|
+
// Call data?.dispose() when nothing uses it anymore.
|
|
92
113
|
```
|
|
93
114
|
|
|
94
115
|
## Raycasting
|
|
@@ -105,11 +126,10 @@ if (intersections.length > 0) {
|
|
|
105
126
|
}
|
|
106
127
|
```
|
|
107
128
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
Hits include `index` for reading the current Splat and `sourceIndex` for its original source ID (`SplatIntersection` in TypeScript). Streamed indices can change with the visible selection. RAD source IDs are file-global node indices; streamed SOG source IDs are indices within the hit batch's source chunk.
|
|
129
|
+
- The model needs `raycastable: true`, the default. Picking may return nothing while the model is still being set up.
|
|
130
|
+
- Each hit has an `index`, for reading the Splat from the current data, and a `sourceIndex`, its ID in the original file (`SplatIntersection` in TypeScript).
|
|
131
|
+
- Values of `minRaycastOpacity` below `0.01` have limited effect: areas that transparent may not be pickable.
|
|
132
|
+
- Streamed models can be picked. Hits ignore their display fades, and an `index` can change as the shown detail changes. For RAD, `sourceIndex` is the node index within the whole file; for streamed SOG, it is the index within the chunk file the hit Splat was loaded from.
|
|
113
133
|
|
|
114
134
|
## Scene integration
|
|
115
135
|
|
|
@@ -123,8 +143,8 @@ const splat = new SplatMesh({
|
|
|
123
143
|
scene.add(splat);
|
|
124
144
|
```
|
|
125
145
|
|
|
126
|
-
If `onFrame` throws, the
|
|
146
|
+
If `onFrame` throws, the error comes out of the render or `update()` call that ran it. Changes the callback already made are kept.
|
|
127
147
|
|
|
128
|
-
For GIS/ECEF scenes, keep model coordinates
|
|
148
|
+
For GIS/ECEF scenes, keep the model's own coordinates small and put the large offset in the mesh transform. This preserves detail; precision already lost in the source file cannot be restored.
|
|
129
149
|
|
|
130
|
-
For models
|
|
150
|
+
For models with `+Y` down and `+Z` forward, use `splat.quaternion.set(1, 0, 0, 0)` to turn them 180° around X.
|
package/docs/Splats.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
[Back to documentation](../README.md#documentation)
|
|
4
4
|
|
|
5
|
-
`Splats`
|
|
5
|
+
`Splats` holds the data of a loaded model. Every `SplatMesh` has one as `mesh.splats`. Use it to read individual Splats, or to share one model's data between meshes.
|
|
6
|
+
|
|
7
|
+
Wait for loading to finish before reading:
|
|
6
8
|
|
|
7
9
|
```js
|
|
8
10
|
await splat.initialized;
|
|
@@ -17,42 +19,47 @@ The constructor and `initialize()` accept `SplatsOptions`:
|
|
|
17
19
|
|
|
18
20
|
| Option | Type | Default | Description |
|
|
19
21
|
| --- | --- | --- | --- |
|
|
20
|
-
| `url` | `string` | `undefined` | PLY/SPZ/SOG/RAD file or SOG
|
|
22
|
+
| `url` | `string` | `undefined` | PLY/SPZ/SOG/RAD file or SOG `meta.json` URL |
|
|
21
23
|
| `file` | `Blob` (including `File`) | `undefined` | Local file |
|
|
22
|
-
| `fileBytes` | `Uint8Array \| ArrayBuffer` | `undefined` |
|
|
23
|
-
| `fileType` | `SplatFileType` |
|
|
24
|
-
| `fileName` | `string` | `File.name` when available | Name used to
|
|
25
|
-
| `resolveFile` | `SplatFileResolver` | `undefined` |
|
|
26
|
-
| `postDecode` | `SplatPostDecodeProgram` | `undefined` |
|
|
27
|
-
| `onProgress` | `(event: SplatProgressEvent) => void` | `undefined` | [
|
|
28
|
-
|
|
29
|
-
Choose at most one of `url`, `file`, or `fileBytes`; mixing inputs throws.
|
|
24
|
+
| `fileBytes` | `Uint8Array \| ArrayBuffer` | `undefined` | Complete file data in memory |
|
|
25
|
+
| `fileType` | `SplatFileType` | Detected from the name | Set the format explicitly |
|
|
26
|
+
| `fileName` | `string` | `File.name` when available | Name used to detect the format |
|
|
27
|
+
| `resolveFile` | `SplatFileResolver` | `undefined` | Supply the extra files of a split SOG or RAD model; see [local split files](SplatLoader.md#local-split-files) |
|
|
28
|
+
| `postDecode` | `SplatPostDecodeProgram` | `undefined` | [Change each Splat while loading](PostDecode.md) |
|
|
29
|
+
| `onProgress` | `(event: SplatProgressEvent) => void` | `undefined` | [Loading progress](SplatLoader.md#loading-progress) callback |
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
Choose at most one of `url`, `file`, or `fileBytes`; combining them throws.
|
|
32
32
|
|
|
33
33
|
## Methods
|
|
34
34
|
|
|
35
35
|
| API | Description |
|
|
36
36
|
| --- | --- |
|
|
37
|
-
| `initialized` / `isInitialized` |
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
37
|
+
| `initialized` / `isInitialized` | Promise that resolves when loading finishes, and whether it has |
|
|
38
|
+
| `initialize(options)` | Load new data from a URL, file, or bytes, replacing what was there. Returns the new `initialized` promise |
|
|
39
|
+
| `getNumSplats()` / `getNumSh()` | Splat count, and the level of view-dependent color (spherical harmonics degree) the model has |
|
|
40
|
+
| `getByteLength()` | Memory used by the data, in bytes |
|
|
41
|
+
| `getSplat(index, includeSh?)` | Read one Splat; pass `false` to skip its view-dependent color |
|
|
42
|
+
| `getSourceIndex(index)` | The Splat's ID in the original file |
|
|
43
|
+
| `forEachCenter(callback)` | Visit only the center of every Splat, for example to build a spatial index |
|
|
43
44
|
| `forEachSplat(callback)` | Visit every Splat |
|
|
44
|
-
| `
|
|
45
|
-
|
|
45
|
+
| `dispose()` | Cancel loading and release the data |
|
|
46
|
+
|
|
47
|
+
Calling `initialize()` again or `dispose()` cancels a load still in progress; its promise rejects with `AbortError`.
|
|
46
48
|
|
|
47
49
|
## Data rules
|
|
48
50
|
|
|
49
|
-
-
|
|
50
|
-
- `getSplat()` returns new `center`, `scales`, `quaternion`, `opacity`, `color`, and `sh`
|
|
51
|
-
-
|
|
52
|
-
-
|
|
51
|
+
- **Indices are not file order.** Splats are reordered while loading. Use `getSourceIndex(index)`, or a picking hit's `sourceIndex`, to get the ID from the original file. Passing existing `Splats` to a mesh keeps their order.
|
|
52
|
+
- **Reads return copies.** `getSplat()` returns new `center`, `scales`, `quaternion`, `opacity`, `color`, and `sh` values on each call; changing them does not change the model. `sh` holds 0, 3, 8, or 15 RGB coefficients, depending on the model's degree.
|
|
53
|
+
- **`forEachSplat()` reuses its objects.** The same objects are passed for every Splat, so clone anything you want to keep after the callback returns.
|
|
54
|
+
- **Streamed data is read-only.** Data from [RadStreamScheduler](RadStreamScheduler.md) or [SogStreamScheduler](SogStreamScheduler.md) cannot be reinitialized.
|
|
55
|
+
- **Bounds live on the mesh.** Use [`mesh.getBoundingBox()`](SplatMesh.md#bounding-box).
|
|
56
|
+
|
|
57
|
+
To change a model, use [postDecode](PostDecode.md) while loading, or [SplatMesh properties](SplatMesh.md#properties) and [SDF edits](SplatEdit.md) for display color and opacity.
|
|
58
|
+
|
|
59
|
+
## After reloading data
|
|
53
60
|
|
|
54
|
-
|
|
61
|
+
Data loaded with `initialize()` appears once the renderer has processed it. On WebGL this can take a few frames, and the previous data stays on screen meanwhile.
|
|
55
62
|
|
|
56
|
-
|
|
63
|
+
With [on-demand rendering](GaussianSplatRenderer.md#on-demand-rendering), request a redraw when `initialized` resolves, and connect `onDirty` to the same render request. With `autoUpdate: false`, await `splatRenderer.update({ scene, camera })` before rendering.
|
|
57
64
|
|
|
58
|
-
For loading progress, cancellation, and
|
|
65
|
+
For loading progress, cancellation, and split files, see [SplatLoader](SplatLoader.md).
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[Back to documentation](../README.md#documentation)
|
|
4
4
|
|
|
5
|
-
Stochastic rendering is an optional
|
|
5
|
+
Stochastic rendering is an optional way for `GaussianSplatRenderer` to draw transparency. It produces visible noise, so pair it with temporal anti-aliasing (TAA) to get a smooth image. Sorted alpha blending remains the default.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
It works on WebGPU, WebGL2, and `WebGPURenderer`'s WebGL2 fallback, including WebXR.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Turn it on
|
|
10
10
|
|
|
11
11
|
With an existing [GaussianSplatRenderer](GaussianSplatRenderer.md):
|
|
12
12
|
|
|
@@ -20,19 +20,15 @@ Splats are sorted from front to back by default. To skip this sorting:
|
|
|
20
20
|
splatRenderer.stochasticSort = false;
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Both
|
|
23
|
+
Both can be changed at any time. While stochastic rendering is active, Splats are drawn without blending and with depth testing and depth writing on. Your `transparent`, `depthTest`, and `depthWrite` settings apply again when you return to sorted rendering.
|
|
24
24
|
|
|
25
25
|
## Smooth the noise
|
|
26
26
|
|
|
27
|
-
Use
|
|
28
|
-
|
|
29
|
-
The noise pattern changes on each render by default so TAA can smooth it over time. The library does not enable TAA or schedule these extra renders for you. With on-demand rendering, keep rendering while TAA accumulates.
|
|
30
|
-
|
|
31
|
-
WebGPURenderer blends in Three.js's linear working color space, which makes partially transparent Splats slightly brighter than WebGLRenderer drawing directly to the canvas. `TAAPass` matches direct canvas rendering by default; see [TAAPass color space](TAAPass.md#color-space).
|
|
27
|
+
Use [`TAANode`](TAAPass.md#taanode-webgpurenderer) with `WebGPURenderer`, or [`TAAPass`](TAAPass.md#taapass-webglrenderer) with `WebGLRenderer`. The library does not turn TAA on for you. The examples assume an existing `renderer`, `scene`, `camera`, and `splatRenderer`, with one camera outside WebXR.
|
|
32
28
|
|
|
33
29
|
### WebGPURenderer: TAANode
|
|
34
30
|
|
|
35
|
-
Use this
|
|
31
|
+
Use this on both WebGPU and the WebGL2 fallback, after `await renderer.init()`:
|
|
36
32
|
|
|
37
33
|
```js
|
|
38
34
|
import { TAANode } from "gaussian-splat-lite";
|
|
@@ -41,8 +37,7 @@ import { RenderPipeline } from "three/webgpu";
|
|
|
41
37
|
splatRenderer.stochastic = true;
|
|
42
38
|
|
|
43
39
|
const taa = new TAANode(scene, camera);
|
|
44
|
-
// Chain Bloom or other
|
|
45
|
-
// RenderPipeline applies the final tone mapping and output conversion.
|
|
40
|
+
// Chain Bloom or other effects from taa here.
|
|
46
41
|
const pipeline = new RenderPipeline(renderer, taa);
|
|
47
42
|
|
|
48
43
|
renderer.setAnimationLoop(() => {
|
|
@@ -51,44 +46,46 @@ renderer.setAnimationLoop(() => {
|
|
|
51
46
|
});
|
|
52
47
|
```
|
|
53
48
|
|
|
54
|
-
Call `taa.reset()` after a camera cut, scene replacement, or an abrupt object change. See [TAANode](TAAPass.md#webgpurenderer-tsl-version) for behavior, supported cameras, and cleanup.
|
|
55
|
-
|
|
56
49
|
### WebGLRenderer: TAAPass
|
|
57
50
|
|
|
58
51
|
```js
|
|
59
52
|
import { TAAPass } from "gaussian-splat-lite";
|
|
53
|
+
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
|
|
54
|
+
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
|
|
60
55
|
|
|
61
56
|
splatRenderer.stochastic = true;
|
|
62
57
|
|
|
63
58
|
const taa = new TAAPass(scene, camera);
|
|
59
|
+
const composer = new EffectComposer(renderer);
|
|
60
|
+
composer.addPass(taa);
|
|
61
|
+
// Insert Bloom or other effects here.
|
|
62
|
+
composer.addPass(new OutputPass());
|
|
63
|
+
|
|
64
64
|
renderer.setAnimationLoop(() => {
|
|
65
65
|
// Update controls / animation here.
|
|
66
|
-
|
|
66
|
+
composer.render();
|
|
67
67
|
});
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
`TAAPass`
|
|
70
|
+
`TAAPass` takes the place of `RenderPass`. On resize, call `composer.setSize(width, height)` along with the renderer.
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
### With either setup
|
|
73
|
+
|
|
74
|
+
- Call `taa.reset()` after a camera cut, a scene replacement, or an abrupt change to an object. TAA follows camera movement, not moving objects.
|
|
75
|
+
- With on-demand rendering, keep rendering for several frames after the camera, a model, or streamed content changes, and after the Splat renderer's `onDirty` callback, so the noise can settle. The viewer renders 32.
|
|
76
|
+
|
|
77
|
+
See [TAAPass and TAANode](TAAPass.md) for effects, depth, color, and cleanup. The repository's `examples/viewer/viewerTAA.js` shows both setups.
|
|
73
78
|
|
|
74
79
|
## Control the noise pattern
|
|
75
80
|
|
|
76
|
-
To keep
|
|
81
|
+
The noise pattern changes on every render, which is what lets TAA smooth it over time. To keep it fixed, or to drive it from your own TAA:
|
|
77
82
|
|
|
78
83
|
```js
|
|
79
84
|
splatRenderer.autoAdvanceStochasticSample = false;
|
|
80
|
-
splatRenderer.stochasticSample = 0; // Keep fixed, or
|
|
85
|
+
splatRenderer.stochasticSample = 0; // Keep fixed, or increase it yourself.
|
|
81
86
|
```
|
|
82
87
|
|
|
83
|
-
Set `autoAdvanceStochasticSample = true` to
|
|
84
|
-
|
|
85
|
-
Coverage uses a 32-frame spatiotemporal blue-noise sequence on all backends.
|
|
86
|
-
Each Splat keeps its own spatial offset and temporal phase, so consecutive
|
|
87
|
-
samples follow the texture's time axis instead of choosing unrelated offsets.
|
|
88
|
-
The temporal sequence is optimized for exponential history accumulation.
|
|
89
|
-
The sequence wraps after 32 samples; this reduces temporal sampling error but
|
|
90
|
-
does not guarantee a noise-free result after 32 renders. Keep advancing the
|
|
91
|
-
sample once per scene render, including when using camera jitter.
|
|
88
|
+
When you advance it yourself, increase it by one for each render of the scene. The patterns repeat every 32 samples; a smooth image is not guaranteed after exactly 32 renders. Set `autoAdvanceStochasticSample = true` to hand control back.
|
|
92
89
|
|
|
93
90
|
## Return to sorted rendering
|
|
94
91
|
|
|
@@ -96,11 +93,11 @@ sample once per scene render, including when using camera jitter.
|
|
|
96
93
|
splatRenderer.stochastic = false;
|
|
97
94
|
```
|
|
98
95
|
|
|
99
|
-
|
|
96
|
+
The switch, in either direction, takes effect on a later frame rather than immediately. `stochasticActive` tells you which mode is being drawn; keep TAA running until it is `false`. With `autoUpdate = false`, update before drawing:
|
|
100
97
|
|
|
101
98
|
```js
|
|
102
99
|
await splatRenderer.update({ scene, camera });
|
|
103
100
|
renderer.render(scene, camera);
|
|
104
101
|
```
|
|
105
102
|
|
|
106
|
-
If you keep TAA running with sorted rendering, set `splatRenderer.depthWrite = true` so TAA can see
|
|
103
|
+
If you keep TAA running with sorted rendering, set `splatRenderer.depthWrite = true` so TAA can see the Splats' depth.
|