@viggle/splat-engine-three 0.0.0-stage → 0.1.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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +450 -2
  3. package/dist/chunks/chunk-WN5WBKM4.js +8606 -0
  4. package/dist/chunks/chunk-WN5WBKM4.js.map +7 -0
  5. package/dist/index.js +56 -0
  6. package/dist/index.js.map +7 -0
  7. package/dist/types/anim/animation-conversion.d.ts +25 -0
  8. package/dist/types/anim/bind-pose.d.ts +15 -0
  9. package/dist/types/anim/keyframe-splines.d.ts +59 -0
  10. package/dist/types/anim/rest-relative.d.ts +32 -0
  11. package/dist/types/anim/spline.d.ts +14 -0
  12. package/dist/types/animation.d.ts +216 -0
  13. package/dist/types/armature.d.ts +524 -0
  14. package/dist/types/character.d.ts +582 -0
  15. package/dist/types/engine.d.ts +166 -0
  16. package/dist/types/environment.d.ts +53 -0
  17. package/dist/types/index.d.ts +40 -0
  18. package/dist/types/lighting/color.d.ts +13 -0
  19. package/dist/types/lighting/point-light.d.ts +33 -0
  20. package/dist/types/lighting/sky-light.d.ts +22 -0
  21. package/dist/types/lighting/sun-light.d.ts +34 -0
  22. package/dist/types/loader/animation/animation-glb.d.ts +117 -0
  23. package/dist/types/loader/character/index.d.ts +33 -0
  24. package/dist/types/loader/character/legacy/index.d.ts +34 -0
  25. package/dist/types/loader/character/legacy/interleaved-splat.d.ts +101 -0
  26. package/dist/types/loader/character/legacy/planar-splat.d.ts +139 -0
  27. package/dist/types/loader/character/load.d.ts +33 -0
  28. package/dist/types/loader/character/types.d.ts +129 -0
  29. package/dist/types/loader/character/v1/decode.d.ts +32 -0
  30. package/dist/types/loader/environment/ply.d.ts +16 -0
  31. package/dist/types/loader/shared/bin-cache.d.ts +19 -0
  32. package/dist/types/loader/skeleton/index.d.ts +19 -0
  33. package/dist/types/loader/skeleton/skeleton-data-441.d.ts +5 -0
  34. package/dist/types/loader/skeleton/skeleton-data.d.ts +6 -0
  35. package/dist/types/math.d.ts +82 -0
  36. package/dist/types/skeletal/animation-player.d.ts +185 -0
  37. package/dist/types/skeletal/bone-mask.d.ts +27 -0
  38. package/dist/types/skeletal/bone-stretch.d.ts +65 -0
  39. package/dist/types/skeletal/pose.d.ts +27 -0
  40. package/dist/types/skeletal/skeleton.d.ts +57 -0
  41. package/dist/types/skeletal/splat-skinning.d.ts +69 -0
  42. package/dist/types/splat/backend.d.ts +57 -0
  43. package/dist/types/splat/bone-binding.d.ts +38 -0
  44. package/dist/types/splat/depth-sort.d.ts +76 -0
  45. package/dist/types/splat/importance.d.ts +60 -0
  46. package/dist/types/splat/packed-splats.d.ts +36 -0
  47. package/dist/types/splat/prune.d.ts +60 -0
  48. package/dist/types/splat/quality.d.ts +175 -0
  49. package/dist/types/splat/splat-mesh.d.ts +71 -0
  50. package/dist/types/splat/splat.d.ts +252 -0
  51. package/dist/types/splat/transform-palette.d.ts +42 -0
  52. package/dist/types/splat/webgl/backend.d.ts +17 -0
  53. package/dist/types/splat/webgl/shaders.d.ts +2 -0
  54. package/dist/types/splat/webgl/splat-mesh.d.ts +54 -0
  55. package/dist/types/splat/webgpu/backend.d.ts +25 -0
  56. package/dist/types/splat/webgpu/lighting.d.ts +34 -0
  57. package/dist/types/splat/webgpu/radix-sort.d.ts +46 -0
  58. package/dist/types/splat/webgpu/splat-mesh.d.ts +73 -0
  59. package/dist/types/three/loaders.d.ts +77 -0
  60. package/dist/types/three/splat-character.d.ts +220 -0
  61. package/dist/types/types.d.ts +30 -0
  62. package/dist/types/webgpu.d.ts +5 -0
  63. package/dist/webgpu.js +843 -0
  64. package/dist/webgpu.js.map +7 -0
  65. package/package.json +46 -4
@@ -0,0 +1,25 @@
1
+ import type { SplatEngine } from '../../engine';
2
+ import type { Mesh } from 'three/webgpu';
3
+ import type { SplatBackend, SplatRenderImpl } from '../backend';
4
+ import type { Splat } from '../splat';
5
+ /**
6
+ * Splat rendering for `WebGPURenderer` (`three/webgpu`), running on WebGPU.
7
+ *
8
+ * Skinning, projection and the depth sort all run in compute shaders, so the
9
+ * CPU does no per-splat work: adding an animated character costs a pose
10
+ * evaluation and a palette upload, not a pass over its splats.
11
+ *
12
+ * Importing `@viggle/splat-engine-three/webgpu` registers this backend, and
13
+ * splats then use it whenever a `WebGPURenderer` draws them; there is nothing
14
+ * to construct or pass.
15
+ *
16
+ * Requires the renderer's WebGPU backend. `WebGPURenderer`'s WebGL2 fallback
17
+ * (`forceWebGL`, or a browser without WebGPU) has no compute shaders; use
18
+ * `THREE.WebGLRenderer` there instead.
19
+ *
20
+ * @group Engine
21
+ */
22
+ export declare class WebGPUSplatBackend implements SplatBackend {
23
+ private readonly _lighting;
24
+ createImpl(host: Mesh, splat: Splat, engine: SplatEngine): SplatRenderImpl;
25
+ }
@@ -0,0 +1,34 @@
1
+ import type { SplatEngine } from '../../engine';
2
+ type Node = any;
3
+ /** Point lights the WebGPU backend evaluates per splat. Extra lights are ignored. */
4
+ export declare const MAX_POINT_LIGHTS = 16;
5
+ /**
6
+ * The engine's lighting registry as TSL uniforms, shared by every WebGPU splat
7
+ * drawable of one engine.
8
+ *
9
+ * @internal
10
+ */
11
+ export declare class WebGPULighting {
12
+ private readonly _engine;
13
+ private readonly _sunColor;
14
+ private readonly _sunIntensity;
15
+ private readonly _ambient;
16
+ private readonly _pointCount;
17
+ private readonly _pointPosRange;
18
+ private readonly _pointColor;
19
+ private readonly _pointPosRangeNode;
20
+ private readonly _pointColorNode;
21
+ private _version;
22
+ constructor(engine: SplatEngine);
23
+ /**
24
+ * Refresh the uniforms from the engine's lighting registry.
25
+ * @returns A number that changes whenever the lighting does.
26
+ */
27
+ sync(): number;
28
+ /**
29
+ * The multiplier applied to a splat's baked colour: ambient, plus sun, plus
30
+ * range-attenuated point lights. With no lights it is exactly 1.
31
+ */
32
+ litFactor(worldCenter: Node): Node;
33
+ }
34
+ export {};
@@ -0,0 +1,46 @@
1
+ type Node = any;
2
+ /** Sort keys are 16 bits, sorted as two 8-bit digits. */
3
+ export declare const SORT_KEY_BITS = 16;
4
+ /**
5
+ * A stable least-significant-digit radix sort over 16-bit keys, in compute.
6
+ *
7
+ * Stability is the point. The obvious GPU counting sort - histogram, prefix
8
+ * sum, then every element claiming its slot with an atomic add - leaves the
9
+ * order inside a bucket to whichever thread wins the race, and that changes
10
+ * from frame to frame. For splats sharing a depth bucket (a surface seen
11
+ * face-on is full of them) the result is visible shimmer on a perfectly still
12
+ * frame. Here ties always resolve in element-index order, exactly as a CPU
13
+ * counting sort does, so a still frame is bit-stable.
14
+ *
15
+ * Each digit takes three steps:
16
+ *
17
+ * histogram count digits per block of {@link BLOCK} consecutive elements
18
+ * (atomic adds; counts do not depend on thread order).
19
+ * prefix for each digit, in parallel, walk the blocks turning counts
20
+ * into starting offsets; then one thread turns the 256 digit
21
+ * totals into digit bases.
22
+ * scatter one invocation per block walks its elements in order, placing
23
+ * each at its digit's running offset.
24
+ *
25
+ * The first digit's histogram is folded into the caller's own per-element
26
+ * pass through {@link GpuRadixSort.countFirstDigit}, saving a dispatch.
27
+ */
28
+ export declare class GpuRadixSort {
29
+ readonly count: number;
30
+ /** Write each element's key here (`uint`, low 16 bits significant) before {@link GpuRadixSort.sortNodes} run. */
31
+ readonly keysWrite: Node;
32
+ /** Element indices in ascending key order, valid after {@link GpuRadixSort.sortNodes} have run. */
33
+ readonly orderRead: Node;
34
+ /** Run before the pass that writes keys: clears both digit histograms. */
35
+ readonly resetNode: Node;
36
+ /** Run, in order, after the pass that writes keys. */
37
+ readonly sortNodes: Node[];
38
+ private readonly _firstHistogram;
39
+ constructor(count: number);
40
+ /**
41
+ * Count `key`'s low digit for the element at `index`. Call from inside the
42
+ * compute pass that writes the keys.
43
+ */
44
+ countFirstDigit(index: Node, key: Node): void;
45
+ }
46
+ export {};
@@ -0,0 +1,73 @@
1
+ import { InstancedBufferGeometry, NodeMaterial } from 'three/webgpu';
2
+ import type { Camera, Mesh } from 'three/webgpu';
3
+ import type { SplatRenderImpl } from '../backend';
4
+ import type { Splat } from '../splat';
5
+ import type { WebGPULighting } from './lighting';
6
+ /** Groups a variant mask can address. The mask travels as a uniform array of this size. */
7
+ export declare const MAX_VARIANT_GROUPS = 64;
8
+ /**
9
+ * How one {@link Splat} is drawn under `WebGPURenderer`.
10
+ *
11
+ * Everything per-splat happens in compute, once per splat per frame:
12
+ *
13
+ * 1. project - skin, lift to world space, project the covariance to a
14
+ * screen-space ellipse, shade; write the result to a work
15
+ * buffer along with a 16-bit depth key.
16
+ * 2. sort - a stable radix sort of the keys ({@link GpuRadixSort}),
17
+ * giving splat indices in back-to-front order.
18
+ *
19
+ * Buffers are interleaved so no stage binds more than seven storage buffers:
20
+ * WebGPU only guarantees eight per stage, and some browsers stop there.
21
+ *
22
+ * The vertex stage then only expands each work-buffer entry into a quad. No
23
+ * per-splat work happens on the CPU, which is what lets this backend carry
24
+ * many animated characters: the WebGL backend re-skins every centre on the
25
+ * main thread each frame just to feed its sort.
26
+ *
27
+ * @internal
28
+ */
29
+ export declare class WebGPUSplatImpl implements SplatRenderImpl {
30
+ readonly geometry: InstancedBufferGeometry;
31
+ readonly material: NodeMaterial;
32
+ /** Skinning for the sort happens in compute; the CPU never touches a splat. */
33
+ readonly needsCpuCenters = false;
34
+ private readonly _host;
35
+ private readonly _splat;
36
+ private readonly _lighting;
37
+ private _paletteArray;
38
+ private _paletteAttribute;
39
+ private _paletteVersion;
40
+ private _boneAttribute;
41
+ private _groupAttribute;
42
+ private readonly _variantMask;
43
+ /** [sort reset, project] - everything that depends on the camera or the pose. */
44
+ private _projectNodes;
45
+ /** The sort proper - needed only when the depth ORDER may have changed. */
46
+ private _sortNodes;
47
+ private readonly _lastInputs;
48
+ private readonly _inputs;
49
+ private readonly _lastSortDirection;
50
+ private _buildId;
51
+ private _sortedBuildId;
52
+ private _allNodes;
53
+ private readonly _u;
54
+ constructor(host: Mesh, splat: Splat, lighting: WebGPULighting);
55
+ /** The sort runs in the same frame as the draw; the order is never stale. */
56
+ get sortPending(): boolean;
57
+ /** Force the next frame to re-project and re-sort even if nothing appears to have changed. */
58
+ requestSort(): void;
59
+ syncDefines(): void;
60
+ syncBounds(): void;
61
+ syncBoneData(): void;
62
+ syncVariantGroups(): void;
63
+ /**
64
+ * (Re)create the storage buffers, compute nodes and material nodes. Runs at
65
+ * construction, and again when a feature toggle changes the shader or the
66
+ * palette outgrows its buffer.
67
+ */
68
+ private _build;
69
+ beforeRender(renderer: any, camera: Camera): void;
70
+ /** Refresh this splat's uniforms and run whatever compute this frame needs. */
71
+ private _prepare;
72
+ dispose(): void;
73
+ }
@@ -0,0 +1,77 @@
1
+ import { Loader } from 'three';
2
+ import type { LoadingManager } from 'three';
3
+ import { Animation } from '../animation';
4
+ import { SplatEngine } from '../engine';
5
+ import type { SplatMesh } from '../splat/splat-mesh';
6
+ import { SplatCharacter } from './splat-character';
7
+ /**
8
+ * Shared plumbing: fetch bytes the three.js way - through a `FileLoader`, so
9
+ * the `LoadingManager`, base path, request headers and credentials mode all
10
+ * apply - then hand them to an asynchronous `parseAsync`.
11
+ */
12
+ declare abstract class SplatLoaderBase<T> extends Loader<T> {
13
+ /**
14
+ * The engine loaded objects belong to: the skeleton library, clip registry
15
+ * and lights they share. Leave unset to use {@link SplatEngine.shared}.
16
+ */
17
+ engine: SplatEngine | null;
18
+ constructor(manager?: LoadingManager);
19
+ setEngine(engine: SplatEngine | null): this;
20
+ /** Decode bytes already in memory. `name` labels the result; for a loaded file it is the file's base name. */
21
+ abstract parseAsync(data: ArrayBuffer, name?: string): Promise<T>;
22
+ load(url: string, onLoad: (result: T) => void, onProgress?: (event: ProgressEvent) => void, onError?: (error: unknown) => void): void;
23
+ protected get resolvedEngine(): SplatEngine;
24
+ }
25
+ /**
26
+ * Loads a `.vsplat` character bundle (or a legacy `.bin` one - the container
27
+ * is recognised from the file's own bytes) as a {@link SplatCharacter}.
28
+ *
29
+ * ```ts
30
+ * const character = await new VSplatLoader().loadAsync('/assets/hero.vsplat');
31
+ * scene.add(character);
32
+ * ```
33
+ *
34
+ * @group Loaders
35
+ */
36
+ export declare class VSplatLoader extends SplatLoaderBase<SplatCharacter> {
37
+ parseAsync(data: ArrayBuffer, name?: string): Promise<SplatCharacter>;
38
+ }
39
+ /**
40
+ * Loads an animation clip for {@link SplatCharacter.play}: a MetaHuman-rig
41
+ * `.glb`, or an `.anim` file.
42
+ *
43
+ * ```ts
44
+ * const run = await new SplatClipLoader().loadAsync('/assets/run.glb');
45
+ * character.play(run);
46
+ * ```
47
+ *
48
+ * A clip is not tied to one character; play the same one on as many as you like.
49
+ *
50
+ * @group Loaders
51
+ */
52
+ export declare class SplatClipLoader extends SplatLoaderBase<Animation> {
53
+ /** For a `.glb` holding several animations, the one to take. Default: the first. */
54
+ animationName: string | undefined;
55
+ parseAsync(data: ArrayBuffer, name?: string): Promise<Animation>;
56
+ }
57
+ /**
58
+ * Loads an uncompressed 3D Gaussian Splatting `.ply` as a static
59
+ * {@link SplatMesh} - an environment, a prop, a scanned object.
60
+ *
61
+ * ```ts
62
+ * const room = await new SplatPLYLoader().loadAsync('/assets/room.ply');
63
+ * room.rotation.x = Math.PI; // many captures are authored Y-down
64
+ * scene.add(room);
65
+ * ```
66
+ *
67
+ * The mesh is given `renderOrder = -1` so it draws before characters, which
68
+ * then always composite on top of it. Splats do not write depth, so without
69
+ * that a large environment whose origin happens to be nearer the camera would
70
+ * be drawn over a character standing in it.
71
+ *
72
+ * @group Loaders
73
+ */
74
+ export declare class SplatPLYLoader extends SplatLoaderBase<SplatMesh> {
75
+ parseAsync(data: ArrayBuffer, name?: string): Promise<SplatMesh>;
76
+ }
77
+ export {};
@@ -0,0 +1,220 @@
1
+ import { Matrix4, Object3D, Vector3 } from 'three';
2
+ import type { ColorRepresentation, Object3DEventMap } from 'three';
3
+ import type { Animation } from '../animation';
4
+ import type { Armature } from '../armature';
5
+ import { Character } from '../character';
6
+ import type { SplatEngine } from '../engine';
7
+ import type { CharacterBundle } from '../loader/character/load';
8
+ import type { BodyRegion, BoneMask } from '../skeletal/bone-mask';
9
+ import type { Splat } from '../splat/splat';
10
+ /**
11
+ * What a clip's horizontal travel does to the character.
12
+ *
13
+ * - `'off'` - the clip plays in place.
14
+ * - `'apply'` - the character's body moves with the clip, beneath
15
+ * {@link SplatCharacter.position}, which stays where you put it.
16
+ * - `'extract'` - the clip plays in place and its travel is handed to you by
17
+ * {@link SplatCharacter.consumeRootMotion}, to feed a controller or physics.
18
+ *
19
+ * @group Characters & Animation
20
+ */
21
+ export type SplatRootMotion = 'off' | 'apply' | 'extract';
22
+ /** @group Characters & Animation */
23
+ export interface SplatPlayOptions {
24
+ /** Repeat when the clip ends. Default `true`. */
25
+ loop?: boolean;
26
+ }
27
+ /** @group Characters & Animation */
28
+ export interface SplatCrossFadeOptions extends SplatPlayOptions {
29
+ /** Start the new clip at the same fraction of its length the old one had reached. Default `false`. */
30
+ preserveTime?: boolean;
31
+ }
32
+ /** @group Characters & Animation */
33
+ export interface SplatLayerOptions {
34
+ /** The bones the layer drives, as a named region. Give this or `mask`. */
35
+ region?: BodyRegion;
36
+ /** The bones the layer drives, as an explicit mask. Give this or `region`. */
37
+ mask?: BoneMask;
38
+ /** Repeat when the clip ends. Default `true`. */
39
+ loop?: boolean;
40
+ /** Seconds to blend the layer in. Default `0`. */
41
+ fadeDuration?: number;
42
+ /** How strongly the layer overrides the base pose, 0..1. Default `1`. */
43
+ weight?: number;
44
+ }
45
+ /**
46
+ * Events a {@link SplatCharacter} dispatches, alongside the usual `Object3D` ones.
47
+ * @group Characters & Animation
48
+ */
49
+ export interface SplatCharacterEventMap extends Object3DEventMap {
50
+ /** A non-looping clip reached its last frame. */
51
+ finished: {
52
+ clip: Animation;
53
+ };
54
+ /** A looping clip wrapped around to its start. */
55
+ loop: {
56
+ clip: Animation;
57
+ };
58
+ /** An event authored into the clip was crossed. */
59
+ clipevent: {
60
+ clip: Animation | null;
61
+ name: string;
62
+ frame: number;
63
+ payload?: unknown;
64
+ };
65
+ }
66
+ /**
67
+ * A gaussian-splat character, as a three.js object.
68
+ *
69
+ * Add it to a scene, move it with `position` / `rotation` / `scale`, and call
70
+ * {@link SplatCharacter.update} once per frame - the role `AnimationMixer.update`
71
+ * plays for a skinned mesh. Create one with {@link VSplatLoader}.
72
+ *
73
+ * ```ts
74
+ * const character = await new VSplatLoader().loadAsync('/assets/hero.vsplat');
75
+ * scene.add(character);
76
+ * character.position.set(1, 0, 0);
77
+ *
78
+ * const run = await new SplatClipLoader().loadAsync('/assets/run.glb');
79
+ * character.play(run);
80
+ *
81
+ * renderer.setAnimationLoop(() => {
82
+ * character.update(clock.getDelta());
83
+ * renderer.render(scene, camera);
84
+ * });
85
+ * ```
86
+ *
87
+ * `position` is the model origin. A character in its rest pose stands on it;
88
+ * how closely a clip keeps the feet on it depends on the clip.
89
+ *
90
+ * Animation is driven by this class rather than by `AnimationMixer`: a splat
91
+ * character has no `Bone` hierarchy for a mixer to write to. Clips are
92
+ * {@link Animation} objects from {@link SplatClipLoader}.
93
+ *
94
+ * @group Characters & Animation
95
+ */
96
+ export declare class SplatCharacter extends Object3D<SplatCharacterEventMap> {
97
+ /** Type flag, in the three.js manner. */
98
+ readonly isSplatCharacter = true;
99
+ readonly type: string;
100
+ /**
101
+ * The engine-level character this object wraps. Everything not surfaced
102
+ * here - multi-level LOD, variant splats, animation LOD - is reachable
103
+ * through it.
104
+ */
105
+ readonly character: Character;
106
+ private readonly _engine;
107
+ private readonly _bundles;
108
+ private _clip;
109
+ private _loop;
110
+ private _finishedSent;
111
+ private _rootMotion;
112
+ /** Optional world-space floor height. When set, the lowest visible splats
113
+ * are aligned to it after each pose. Useful for dances with no airborne
114
+ * phase; leave null for clips with intentional jumps or flight. */
115
+ groundLockY: number | null;
116
+ private _disposed;
117
+ /**
118
+ * @param bundles - Decoded character bundles, finest level of detail first.
119
+ * They are read, never modified, so clones share them.
120
+ * @internal Use {@link VSplatLoader}.
121
+ */
122
+ constructor(engine: SplatEngine, bundles: CharacterBundle[], name?: string);
123
+ /** The rig: bone names, bone matrices, bone-length scaling. */
124
+ get armature(): Armature;
125
+ /** The splats that draw this character, one per level of detail. */
126
+ get splats(): readonly Splat[];
127
+ /**
128
+ * Advance the animation by `delta` seconds and pose the splats. Call once
129
+ * per frame, before rendering.
130
+ */
131
+ update(delta: number): void;
132
+ /** Start `clip` from its first frame, cutting from whatever was playing. */
133
+ play(clip: Animation, options?: SplatPlayOptions): this;
134
+ /** Blend from the current pose into `clip` over `duration` seconds. */
135
+ crossFadeTo(clip: Animation, duration?: number, options?: SplatCrossFadeOptions): this;
136
+ /** Stop playback and return to the rest pose, blending over `fadeDuration` seconds. */
137
+ stop(fadeDuration?: number): this;
138
+ /**
139
+ * Play `clip` on a named layer that overrides part of the body - an upper
140
+ * body wave over a full-body run, say. Calling it again with the same layer
141
+ * name replaces what that layer plays.
142
+ */
143
+ playLayer(layer: string, clip: Animation, options: SplatLayerOptions): this;
144
+ setLayerWeight(layer: string, weight: number): this;
145
+ stopLayer(layer: string, fadeDuration?: number): this;
146
+ /** The clip the base track is playing, or `null`. */
147
+ get clip(): Animation | null;
148
+ get isPlaying(): boolean;
149
+ get paused(): boolean;
150
+ set paused(value: boolean);
151
+ /** Playback speed multiplier. `1` is the authored speed. */
152
+ get timeScale(): number;
153
+ set timeScale(value: number);
154
+ /** Position in the current clip, in seconds. */
155
+ get time(): number;
156
+ set time(seconds: number);
157
+ /** Length of the current clip in seconds, or `0` when nothing is playing. */
158
+ get duration(): number;
159
+ /** See {@link SplatRootMotion}. Applies to the current clip and every later one. */
160
+ get rootMotion(): SplatRootMotion;
161
+ set rootMotion(mode: SplatRootMotion);
162
+ /**
163
+ * The clip's horizontal travel since the last call, in this object's local
164
+ * space. Non-zero only in `'extract'` mode. `y` is always `0`.
165
+ */
166
+ consumeRootMotion(target?: Vector3): Vector3;
167
+ /**
168
+ * Blend the character's colour toward `color` by `amount` (0..1) - a hit
169
+ * flash, a selection highlight. `amount = 0` restores the authored colour.
170
+ */
171
+ setTint(color: ColorRepresentation, amount?: number): this;
172
+ /** Contrast and saturation multipliers for the character's colour. `(1, 1)` is unchanged. */
173
+ setGrade(contrast: number, saturation: number): this;
174
+ /**
175
+ * Draw fewer of this character's splats as it gets further away.
176
+ *
177
+ * `nearFraction` of them at `nearDist` and closer, `farFraction` at
178
+ * `farDist` and beyond, interpolated in between. Which splats those are is
179
+ * decided by importance within each 4 cm cell, so the character thins evenly
180
+ * rather than losing a region of itself. See {@link Character.setSplatCountLod}.
181
+ *
182
+ * Needs a camera on the engine to measure distance from - the same one the
183
+ * other distance throttles use:
184
+ *
185
+ * ```ts
186
+ * SplatEngine.shared.camera = camera;
187
+ * character.setSplatCountLod({ nearDist: 4, farDist: 16, farFraction: 0.25 });
188
+ * ```
189
+ */
190
+ setSplatCountLod(opts: {
191
+ nearDist: number;
192
+ farDist: number;
193
+ nearFraction?: number;
194
+ farFraction?: number;
195
+ }): this;
196
+ /** Stop thinning: every splat is drawn again, at any distance. */
197
+ disableSplatCountLod(): this;
198
+ /** Bone names, in rig order. */
199
+ get boneNames(): readonly string[];
200
+ /**
201
+ * World matrix of a bone as of the last {@link SplatCharacter.update} - for
202
+ * attaching a prop to a hand, or aiming a camera at a head.
203
+ *
204
+ * @returns `target`, or `null` when the rig has no bone of that name.
205
+ */
206
+ getBoneWorldMatrix(name: string, target?: Matrix4): Matrix4 | null;
207
+ /**
208
+ * A second character from the same decoded data, at the same transform. The
209
+ * copy starts in the rest pose with nothing playing; it does not share this
210
+ * one's animation state.
211
+ */
212
+ clone(): this;
213
+ /**
214
+ * Release every GPU resource the character holds. The object stays in the
215
+ * scene graph, empty; remove it yourself if you no longer want it there.
216
+ */
217
+ dispose(): void;
218
+ private _keyFor;
219
+ private _started;
220
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared data shapes used across the loader, skeletal and splat layers.
3
+ */
4
+ /**
5
+ * Rig description handed to {@link Armature}.
6
+ *
7
+ * The `stdMale*` field names are inherited from the skeleton library and mean
8
+ * "the rest pose this armature binds to", whichever rig that is.
9
+ */
10
+ export interface ArmatureData {
11
+ numBones: number;
12
+ /** Flat `[x,y,z] * numBones` rest translations carried by the character bundle. */
13
+ joints?: Float32Array;
14
+ /** Whether the bundle's geometric corrections are baked into its splats and joints. */
15
+ corrected?: boolean;
16
+ /** Whether `joints` is this character's own vetted rest pose. */
17
+ restIsPerCharacter?: boolean;
18
+ skeleton?: Int32Array;
19
+ stdMaleRestTranslations?: Float32Array;
20
+ stdMaleRestRotations?: Float32Array;
21
+ stdMaleParents?: Int32Array;
22
+ }
23
+ /** Per-splat skinning influences, `K` slots per splat. */
24
+ export interface SplatWeights {
25
+ /** `numSplats * K` rig bone indices. */
26
+ indices: Uint16Array;
27
+ /** `numSplats * K` weights, matching `indices`. */
28
+ weights: Float32Array;
29
+ }
30
+ export type { SkeletonLibrary } from './loader/skeleton';
@@ -0,0 +1,5 @@
1
+ import { WebGPUSplatBackend } from './splat/webgpu/backend';
2
+ export * from './index';
3
+ export { WebGPUSplatBackend };
4
+ export { MAX_POINT_LIGHTS } from './splat/webgpu/lighting';
5
+ export { MAX_VARIANT_GROUPS } from './splat/webgpu/splat-mesh';