@viggle/splat-engine-three 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +290 -2
- package/dist/chunks/chunk-MM6DJU6S.js +7801 -0
- package/dist/chunks/chunk-MM6DJU6S.js.map +7 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +7 -0
- package/dist/types/anim/animation-conversion.d.ts +25 -0
- package/dist/types/anim/bind-pose.d.ts +15 -0
- package/dist/types/anim/keyframe-splines.d.ts +59 -0
- package/dist/types/anim/rest-relative.d.ts +32 -0
- package/dist/types/anim/spline.d.ts +14 -0
- package/dist/types/animation.d.ts +216 -0
- package/dist/types/armature.d.ts +524 -0
- package/dist/types/character.d.ts +540 -0
- package/dist/types/engine.d.ts +166 -0
- package/dist/types/environment.d.ts +53 -0
- package/dist/types/index.d.ts +37 -0
- package/dist/types/lighting/color.d.ts +13 -0
- package/dist/types/lighting/point-light.d.ts +33 -0
- package/dist/types/lighting/sky-light.d.ts +22 -0
- package/dist/types/lighting/sun-light.d.ts +34 -0
- package/dist/types/loader/animation/animation-glb.d.ts +117 -0
- package/dist/types/loader/character/index.d.ts +33 -0
- package/dist/types/loader/character/legacy/index.d.ts +34 -0
- package/dist/types/loader/character/legacy/interleaved-splat.d.ts +101 -0
- package/dist/types/loader/character/legacy/planar-splat.d.ts +139 -0
- package/dist/types/loader/character/load.d.ts +33 -0
- package/dist/types/loader/character/types.d.ts +129 -0
- package/dist/types/loader/character/v1/decode.d.ts +32 -0
- package/dist/types/loader/environment/ply.d.ts +16 -0
- package/dist/types/loader/shared/bin-cache.d.ts +19 -0
- package/dist/types/loader/skeleton/index.d.ts +19 -0
- package/dist/types/loader/skeleton/skeleton-data-441.d.ts +5 -0
- package/dist/types/loader/skeleton/skeleton-data.d.ts +6 -0
- package/dist/types/math.d.ts +82 -0
- package/dist/types/skeletal/animation-player.d.ts +185 -0
- package/dist/types/skeletal/bone-mask.d.ts +27 -0
- package/dist/types/skeletal/bone-stretch.d.ts +65 -0
- package/dist/types/skeletal/pose.d.ts +27 -0
- package/dist/types/skeletal/skeleton.d.ts +57 -0
- package/dist/types/skeletal/splat-skinning.d.ts +69 -0
- package/dist/types/splat/backend.d.ts +57 -0
- package/dist/types/splat/bone-binding.d.ts +38 -0
- package/dist/types/splat/depth-sort.d.ts +58 -0
- package/dist/types/splat/packed-splats.d.ts +36 -0
- package/dist/types/splat/splat-mesh.d.ts +71 -0
- package/dist/types/splat/splat.d.ts +186 -0
- package/dist/types/splat/transform-palette.d.ts +42 -0
- package/dist/types/splat/webgl/backend.d.ts +17 -0
- package/dist/types/splat/webgl/shaders.d.ts +2 -0
- package/dist/types/splat/webgl/splat-mesh.d.ts +52 -0
- package/dist/types/splat/webgpu/backend.d.ts +25 -0
- package/dist/types/splat/webgpu/lighting.d.ts +34 -0
- package/dist/types/splat/webgpu/radix-sort.d.ts +46 -0
- package/dist/types/splat/webgpu/splat-mesh.d.ts +71 -0
- package/dist/types/three/loaders.d.ts +77 -0
- package/dist/types/three/splat-character.d.ts +192 -0
- package/dist/types/types.d.ts +30 -0
- package/dist/types/webgpu.d.ts +5 -0
- package/dist/webgpu.js +813 -0
- package/dist/webgpu.js.map +7 -0
- package/package.json +46 -4
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
import { Group } from 'three';
|
|
2
|
+
import { Mat4, Quat, Vec3 } from './math';
|
|
3
|
+
import type { SplatEngine } from './engine';
|
|
4
|
+
import type { AnimEventCallback } from './skeletal/animation-player';
|
|
5
|
+
import type { BoneMask } from './skeletal/bone-mask';
|
|
6
|
+
import type { BoneScaleInput } from './skeletal/bone-stretch';
|
|
7
|
+
import { Pose } from './skeletal/pose';
|
|
8
|
+
import { Skeleton } from './skeletal/skeleton';
|
|
9
|
+
import type { Splat } from './splat/splat';
|
|
10
|
+
import type { ArmatureData } from './types';
|
|
11
|
+
/**
|
|
12
|
+
* Distance-based animation-LOD knobs. Used as the engine-wide preset
|
|
13
|
+
* (`SplatEngine.animLodPreset`) and as the per-armature override shape in
|
|
14
|
+
* {@link Armature.setAnimationLod}.
|
|
15
|
+
*/
|
|
16
|
+
export interface AnimLodPreset {
|
|
17
|
+
/** World-space distance (m) below which the armature animates full rate. */
|
|
18
|
+
nearDist?: number;
|
|
19
|
+
/** World-space distance (m) beyond which `farStride` applies. */
|
|
20
|
+
farDist?: number;
|
|
21
|
+
/** Frames-per-update between `nearDist` and `farDist`. 1 = every frame. */
|
|
22
|
+
nearStride?: number;
|
|
23
|
+
/** Frames-per-update beyond `farDist`. */
|
|
24
|
+
farStride?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Pluggable override that drives the per-frame pose in place of
|
|
28
|
+
* animation. The Armature has no knowledge of what's on the other end -
|
|
29
|
+
* ragdoll physics, an IK solver, an AI behavior tree's pose output, a
|
|
30
|
+
* network-replicated remote character - they all attach the same way.
|
|
31
|
+
*
|
|
32
|
+
* When `armature.poseProvider` is non-null, the Armature's animation
|
|
33
|
+
* player is **not advanced** that frame; the provider has total control
|
|
34
|
+
* of the pose. The Armature still owns the skinning pipeline (LOD,
|
|
35
|
+
* frustum cull, world-transform composition, GPU palette upload), so a
|
|
36
|
+
* provider only needs to fill `pose`.
|
|
37
|
+
*
|
|
38
|
+
* Implementations: {@link Ragdoll}.
|
|
39
|
+
*
|
|
40
|
+
* @group Characters & Animation
|
|
41
|
+
*/
|
|
42
|
+
export interface PoseProvider {
|
|
43
|
+
/**
|
|
44
|
+
* Fill `pose` (per-bone TRS in armature-local bone space) for this
|
|
45
|
+
* frame. The Armature runs this between its LOD/frustum gate and the
|
|
46
|
+
* `Skeleton.applyLocal` composition step. To restore animation,
|
|
47
|
+
* detach by setting `armature.poseProvider = null`.
|
|
48
|
+
*/
|
|
49
|
+
writePose(pose: Pose, armature: Armature, dt: number): void;
|
|
50
|
+
/**
|
|
51
|
+
* Optional teardown hook fired when the Armature is destroyed (or
|
|
52
|
+
* when a new provider replaces this one). Use to release external
|
|
53
|
+
* resources - e.g. ragdoll physics bodies.
|
|
54
|
+
*/
|
|
55
|
+
onDetach?(): void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* How the armature handles the pelvis X/Z motion extracted from the active
|
|
59
|
+
* animation.
|
|
60
|
+
*
|
|
61
|
+
* - `'off'` - Pelvis X/Z is clamped to bind in bone space. The character
|
|
62
|
+
* looks "in-place" regardless of whether the underlying clip is
|
|
63
|
+
* locomotive. The pivot is not touched by animation. **Default.**
|
|
64
|
+
* - `'apply'` - The pivot tracks the pelvis as an absolute offset from a captured
|
|
65
|
+
* baseline: `object3D.position = baseline + (pelvis_pose − bind)` each
|
|
66
|
+
* frame. Switching `off → apply` captures the current pivot position as
|
|
67
|
+
* the baseline; switching `apply → off` snaps the pivot back to the
|
|
68
|
+
* baseline. Best for toggling-on/off demos and in-place looping animations
|
|
69
|
+
* (pelvis returns to bind at loop end → no teleport). Locomotive clips
|
|
70
|
+
* visibly snap at loop wrap; use `'extract'` for those.
|
|
71
|
+
* - `'extract'` - Engine computes the per-frame pelvis Δ
|
|
72
|
+
* (`pelvis(t) − pelvis(t − dt)`) and accumulates it into an internal
|
|
73
|
+
* buffer; the caller reads it via {@link Armature.consumeRootMotionDelta}
|
|
74
|
+
* and feeds it to a motor / physics body / network layer. Unity-style
|
|
75
|
+
* `OnAnimatorMove` pattern. The engine does **not** write to the pivot in
|
|
76
|
+
* this mode. Loop wraps and hard `play` calls suppress the resulting
|
|
77
|
+
* pelvis discontinuity so the next Δ is `0`.
|
|
78
|
+
*
|
|
79
|
+
* In every mode the pelvis bone itself is clamped to bind X/Z in bone space -
|
|
80
|
+
* the motion lives on the pivot (or in the consumed delta), never on the
|
|
81
|
+
* bone.
|
|
82
|
+
*
|
|
83
|
+
* @group Characters & Animation
|
|
84
|
+
*/
|
|
85
|
+
export type RootMotionMode = 'off' | 'apply' | 'extract';
|
|
86
|
+
/**
|
|
87
|
+
* Composition root for one character: holds the three.js pivot object and
|
|
88
|
+
* wires together a {@link Skeleton}, an {@link AnimationPlayer}, a working
|
|
89
|
+
* {@link Pose}, and a {@link SplatSkinning} unit.
|
|
90
|
+
*
|
|
91
|
+
* Thin facade - `playAnimation` / `crossfadeTo` / `stop` / `update` delegate
|
|
92
|
+
* to the underlying modules. The rig-convention rules (pelvis X/Z clamp,
|
|
93
|
+
* pelvis-Y lock, root-bone clamp, root-motion extraction) live here, because
|
|
94
|
+
* they're a *character-setup* concern, not a pose-evaluation concern.
|
|
95
|
+
*
|
|
96
|
+
* Most users won't construct this directly - {@link Character.load} builds
|
|
97
|
+
* one automatically. It's exported for custom pipelines that need direct
|
|
98
|
+
* control over skeletal evaluation.
|
|
99
|
+
*
|
|
100
|
+
* @group Characters & Animation
|
|
101
|
+
*/
|
|
102
|
+
export declare class Armature {
|
|
103
|
+
/** Pivot object; all linked splats become children of this. */
|
|
104
|
+
object3D: Group;
|
|
105
|
+
/** Rig data (bone count, rest translations/rotations, parents). */
|
|
106
|
+
armatureData: ArmatureData;
|
|
107
|
+
/** Number of bones in the rig. */
|
|
108
|
+
numBones: number;
|
|
109
|
+
private readonly _skeleton;
|
|
110
|
+
private readonly _currentPose;
|
|
111
|
+
private readonly _snapshotPose;
|
|
112
|
+
private readonly _worldTransforms;
|
|
113
|
+
private _engine;
|
|
114
|
+
private readonly _worldMatrix;
|
|
115
|
+
private _player;
|
|
116
|
+
private _skinning;
|
|
117
|
+
private _provider;
|
|
118
|
+
private readonly _layers;
|
|
119
|
+
private readonly _layerTmpQ;
|
|
120
|
+
/**
|
|
121
|
+
* Optional override that drives the pose in place of animation.
|
|
122
|
+
* Setting this to a non-null value skips animation evaluation; the
|
|
123
|
+
* provider has full control of `_currentPose`. Setting back to `null`
|
|
124
|
+
* resumes animation immediately. See {@link PoseProvider}.
|
|
125
|
+
*
|
|
126
|
+
* Replacing the provider (set non-null while another is attached)
|
|
127
|
+
* fires the outgoing provider's `onDetach()` first.
|
|
128
|
+
*/
|
|
129
|
+
get poseProvider(): PoseProvider | null;
|
|
130
|
+
set poseProvider(p: PoseProvider | null);
|
|
131
|
+
private _poseProvider;
|
|
132
|
+
private _rootBoneIndex;
|
|
133
|
+
private _pelvisBoneIndex;
|
|
134
|
+
/**
|
|
135
|
+
* When true, {@link update} advances the animation player (so timers,
|
|
136
|
+
* crossfade, and event callbacks still fire) but skips pose evaluation
|
|
137
|
+
* and the skinning push. The previous frame's pose stays on the GPU
|
|
138
|
+
* palette and the splat keeps rendering at its last bone state.
|
|
139
|
+
*
|
|
140
|
+
* Use for dynamic animation LOD - e.g. when fps drops, set true on
|
|
141
|
+
* every other (or every Nth) frame to halve the per-frame skeletal
|
|
142
|
+
* cost. Cleared when fps recovers.
|
|
143
|
+
*/
|
|
144
|
+
skipPose: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* When true, {@link update} still pushes bone transforms to the GPU
|
|
147
|
+
* palette (so items, hitboxes, and outlines tracking bones still move
|
|
148
|
+
* correctly) but skips the CPU-side `splat.updatePositions(...)` call
|
|
149
|
+
* that recomputes sort centers from the deformed mesh. The depth-sort
|
|
150
|
+
* order lags one frame behind the visual pose.
|
|
151
|
+
*
|
|
152
|
+
* Use for alternate-frame throttling - `updatePositions` is the heavy
|
|
153
|
+
* call (full center buffer re-upload to the sort worker), and most
|
|
154
|
+
* frames don't visibly need a fresh sort.
|
|
155
|
+
*/
|
|
156
|
+
skipPositions: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Update rate divider. `1` = pose evaluation runs on every {@link update}
|
|
159
|
+
* call (default - one pose update per `engine.update()`).
|
|
160
|
+
* Set to N>1 to advance the animation player every call but only do the
|
|
161
|
+
* heavy pose-eval + skinning push every Nth call.
|
|
162
|
+
*
|
|
163
|
+
* `dt` from skipped frames is accumulated and passed to the next
|
|
164
|
+
* evaluated frame, so animation time stays correct - only the GPU
|
|
165
|
+
* palette refresh rate drops.
|
|
166
|
+
*
|
|
167
|
+
* Typical use: set to `2` on background characters so the per-character
|
|
168
|
+
* armature cost halves while the engine still ticks at 30 Hz.
|
|
169
|
+
*/
|
|
170
|
+
updateInterval: number;
|
|
171
|
+
private _updateCounter;
|
|
172
|
+
private _updateAccumDt;
|
|
173
|
+
private _lockPelvisY;
|
|
174
|
+
private _rootMotionMode;
|
|
175
|
+
private _baseLocalPosition;
|
|
176
|
+
private _lastPelvisPos;
|
|
177
|
+
private _hasLastPelvis;
|
|
178
|
+
private _rootMotionAccumDx;
|
|
179
|
+
private _rootMotionAccumDz;
|
|
180
|
+
private _lodNearDist;
|
|
181
|
+
private _lodFarDist;
|
|
182
|
+
private _lodNearStride;
|
|
183
|
+
private _lodFarStride;
|
|
184
|
+
private _lodFrameCounter;
|
|
185
|
+
private _sortLodNearDist;
|
|
186
|
+
private _sortLodFarDist;
|
|
187
|
+
private _sortLodNearStride;
|
|
188
|
+
private _sortLodFarStride;
|
|
189
|
+
private _sortLodFrameCounter;
|
|
190
|
+
constructor(name: string, armatureData: ArmatureData);
|
|
191
|
+
/** Splats currently being driven by this armature. */
|
|
192
|
+
get linkedSplats(): Set<Splat>;
|
|
193
|
+
/**
|
|
194
|
+
* Detach the armature from its engine and remove its pivot object. Splats
|
|
195
|
+
* still linked at the time of destroy are also destroyed so they stop
|
|
196
|
+
* holding GPU resources alive. The armature itself is not safe to
|
|
197
|
+
* reuse after this call.
|
|
198
|
+
*
|
|
199
|
+
* Use {@link Character.destroy} instead if you have the owning
|
|
200
|
+
* {@link Character} - it disposes both the armature and its primary splat.
|
|
201
|
+
*/
|
|
202
|
+
destroy(): void;
|
|
203
|
+
/**
|
|
204
|
+
* Attach this armature to an engine. Required before playback. Adds the
|
|
205
|
+
* armature pivot as a child of `engine.contentRoot` and wires up the
|
|
206
|
+
* animation provider + splat skinning.
|
|
207
|
+
*/
|
|
208
|
+
addToScene(engine: SplatEngine): void;
|
|
209
|
+
/**
|
|
210
|
+
* Register a {@link Splat} to be driven by this armature.
|
|
211
|
+
*
|
|
212
|
+
* Reparents the splat under the armature's pivot and pushes the current
|
|
213
|
+
* bone transforms so the splat appears in the correct pose immediately.
|
|
214
|
+
*/
|
|
215
|
+
linkSplat(splat: Splat): void;
|
|
216
|
+
/**
|
|
217
|
+
* Stop driving the given splat. The splat is not destroyed; it just no
|
|
218
|
+
* longer receives bone transform updates.
|
|
219
|
+
*/
|
|
220
|
+
unlinkSplat(splat: Splat): void;
|
|
221
|
+
/**
|
|
222
|
+
* Apply any combination of position, rotation, and scale to the armature
|
|
223
|
+
* pivot. All linked splats are requested to re-sort.
|
|
224
|
+
*/
|
|
225
|
+
move(position?: Vec3, rotation?: Quat, scale?: Vec3): void;
|
|
226
|
+
/**
|
|
227
|
+
* How pelvis X/Z motion is routed each frame. See {@link RootMotionMode}.
|
|
228
|
+
* Default `'off'`.
|
|
229
|
+
*
|
|
230
|
+
* Transitions are coordinated so toggling is well-behaved:
|
|
231
|
+
*
|
|
232
|
+
* - `off → apply` captures the current pivot position as the baseline.
|
|
233
|
+
* The pivot then tracks `baseline + (pelvis − bind)` each frame.
|
|
234
|
+
* - `apply → off` (or `apply → extract`) snaps the pivot back to the
|
|
235
|
+
* baseline so the apply-mode offset doesn't leak into the next mode.
|
|
236
|
+
* This is what prevents the toggle-ratchet bug.
|
|
237
|
+
* - `* → extract` resets the per-frame Δ tracker so the next Δ is `0`.
|
|
238
|
+
*/
|
|
239
|
+
get rootMotionMode(): RootMotionMode;
|
|
240
|
+
set rootMotionMode(m: RootMotionMode);
|
|
241
|
+
/**
|
|
242
|
+
* Convenience boolean alias for {@link rootMotionMode}.
|
|
243
|
+
* `true` ⇔ `'apply'`, `false` ⇔ `'off'`. To use `'extract'`, set
|
|
244
|
+
* {@link rootMotionMode} directly.
|
|
245
|
+
*/
|
|
246
|
+
get rootMotion(): boolean;
|
|
247
|
+
set rootMotion(v: boolean);
|
|
248
|
+
/**
|
|
249
|
+
* Return the pelvis X/Z delta accumulated since the previous call (or since
|
|
250
|
+
* the armature was created / `rootMotionMode` was changed), and reset the
|
|
251
|
+
* accumulator. The delta is in the pivot's parent space - feed it directly
|
|
252
|
+
* to a motor's velocity input or to a physics body.
|
|
253
|
+
*
|
|
254
|
+
* Returns `{ dx: 0, dz: 0 }` in `'off'` or `'apply'` modes. In `'apply'`
|
|
255
|
+
* mode the delta has already been written to {@link object3D}, so consumers
|
|
256
|
+
* shouldn't read and re-apply it.
|
|
257
|
+
*/
|
|
258
|
+
consumeRootMotionDelta(): {
|
|
259
|
+
dx: number;
|
|
260
|
+
dz: number;
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* When `true`, clamp the pelvis bone's Y translation to bind each frame.
|
|
264
|
+
* Use for in-place idle / gesture captures where vertical bob would push
|
|
265
|
+
* the character out of a tightly-framed thumbnail.
|
|
266
|
+
*/
|
|
267
|
+
get lockPelvisY(): boolean;
|
|
268
|
+
set lockPelvisY(v: boolean);
|
|
269
|
+
get isPlaying(): boolean;
|
|
270
|
+
get isFinished(): boolean;
|
|
271
|
+
get paused(): boolean;
|
|
272
|
+
set paused(v: boolean);
|
|
273
|
+
get animationTime(): number;
|
|
274
|
+
set animationTime(v: number);
|
|
275
|
+
get animationDuration(): number;
|
|
276
|
+
/**
|
|
277
|
+
* Crossfade progress in `[0, 1]`. `0` when no crossfade is active; `1`
|
|
278
|
+
* once the active crossfade has fully blended into the target animation.
|
|
279
|
+
*/
|
|
280
|
+
get crossfadeProgress(): number;
|
|
281
|
+
get frameRate(): number;
|
|
282
|
+
set frameRate(v: number);
|
|
283
|
+
/** Playback-speed multiplier (`1` = author speed). Scales how fast the
|
|
284
|
+
* active clip advances without touching its authored frame rate or
|
|
285
|
+
* crossfade timing. See {@link AnimationPlayer.playbackSpeed}. */
|
|
286
|
+
get playbackSpeed(): number;
|
|
287
|
+
set playbackSpeed(v: number);
|
|
288
|
+
hasAnimation(animName: string): boolean;
|
|
289
|
+
/**
|
|
290
|
+
* Bone names from the attached engine's skeleton library, or an empty array
|
|
291
|
+
* if the armature isn't bound yet. Consumers that need bone-name lookup
|
|
292
|
+
* (bone-tracked colliders, attachments, debug overlays) read from here
|
|
293
|
+
* instead of reaching into private armature state.
|
|
294
|
+
*/
|
|
295
|
+
get boneNames(): readonly string[];
|
|
296
|
+
/**
|
|
297
|
+
* Bone names matching THIS armature's rig size. {@link boneNames} always
|
|
298
|
+
* returns the 86-bone std-male list; the 441-bone facial rig has its own
|
|
299
|
+
* name table (`boneNames441`). Name-keyed per-bone features (bone stretch,
|
|
300
|
+
* body-part classification) must use this accessor or they silently
|
|
301
|
+
* misclassify every bone on the large rig.
|
|
302
|
+
*/
|
|
303
|
+
get rigBoneNames(): readonly string[];
|
|
304
|
+
/** The engine this armature is attached to, or `null` if not yet attached. */
|
|
305
|
+
get engine(): SplatEngine | null;
|
|
306
|
+
/** The skeleton owned by this armature (rest pose, parents, bind data). */
|
|
307
|
+
get skeleton(): Skeleton;
|
|
308
|
+
/**
|
|
309
|
+
* Live reference to the per-bone world-transform array filled in by
|
|
310
|
+
* the most recent {@link update}. Same Mat4 instances are reused
|
|
311
|
+
* across frames - callers may hold the array reference and re-read,
|
|
312
|
+
* or call {@link getBoneWorldMatrix} for a single bone. Empty until
|
|
313
|
+
* the first update.
|
|
314
|
+
*/
|
|
315
|
+
get boneWorldMatrices(): readonly Mat4[];
|
|
316
|
+
/**
|
|
317
|
+
* Snap any active crossfade to its terminal state (target pose fully
|
|
318
|
+
* applied) on the next {@link Armature.update}. Useful when scrubbing
|
|
319
|
+
* through animation frames for precompute, where the per-frame pose
|
|
320
|
+
* needs to be the pure animation evaluation without crossfade blend.
|
|
321
|
+
*/
|
|
322
|
+
endCrossfade(): void;
|
|
323
|
+
/**
|
|
324
|
+
* Return the world-space transform of bone `boneIdx` as computed by the
|
|
325
|
+
* most recent {@link Armature.update}. Returns a live reference into the
|
|
326
|
+
* armature's internal array - callers must not mutate it; copy first if
|
|
327
|
+
* you need to retain.
|
|
328
|
+
*
|
|
329
|
+
* Returns `null` if `boneIdx` is out of range, or if the bone transform
|
|
330
|
+
* array has not been populated yet (no `update()` has run, or the armature
|
|
331
|
+
* isn't attached to an engine).
|
|
332
|
+
*
|
|
333
|
+
* Used by per-bone attachments - bone-tracked colliders, weapon GLBs
|
|
334
|
+
* mounted to a bone, particle emitters following a bone, etc.
|
|
335
|
+
*/
|
|
336
|
+
getBoneWorldMatrix(boneIdx: number): Mat4 | null;
|
|
337
|
+
/**
|
|
338
|
+
* Name of the currently-playing animation, or `null` if no animation is
|
|
339
|
+
* active. Mirrors {@link AnimationPlayer.currentAnimationName}.
|
|
340
|
+
*/
|
|
341
|
+
get currentAnimationName(): string | null;
|
|
342
|
+
/**
|
|
343
|
+
* Subscribe to frame-aligned {@link AnimationEvent}s on the currently-
|
|
344
|
+
* playing animation. Events come from the active animation's
|
|
345
|
+
* {@link Animation.events} array; the engine doesn't interpret `name` or
|
|
346
|
+
* `payload` - games define their own vocabulary and route inside the
|
|
347
|
+
* callback.
|
|
348
|
+
*
|
|
349
|
+
* Listeners are kept across animation switches; one subscription is enough
|
|
350
|
+
* for the armature's lifetime. Returns an unsubscribe handle.
|
|
351
|
+
*/
|
|
352
|
+
onAnimEvent(cb: AnimEventCallback): () => void;
|
|
353
|
+
/**
|
|
354
|
+
* Start playing an animation immediately (no crossfade). Restarts from
|
|
355
|
+
* frame 0. Returns `false` if not registered, or if the armature isn't
|
|
356
|
+
* attached to an engine yet.
|
|
357
|
+
*
|
|
358
|
+
* Passing `rootMotion: true` sets {@link rootMotionMode} to `'apply'`;
|
|
359
|
+
* passing `false` sets it to `'off'`. For `'extract'`, set the mode
|
|
360
|
+
* separately and pass `rootMotion: false` (or omit) here - the per-clip
|
|
361
|
+
* flag is just a convenience shortcut for the common case.
|
|
362
|
+
*/
|
|
363
|
+
playAnimation(animName: string, rootMotion?: boolean, loop?: boolean): boolean;
|
|
364
|
+
/**
|
|
365
|
+
* Crossfade from the current pose to a new animation over `opts.duration`
|
|
366
|
+
* seconds. Snapshots current bone poses, then blends toward the new
|
|
367
|
+
* animation target. Pelvis motion stays continuous across the blend.
|
|
368
|
+
*
|
|
369
|
+
* `opts.rootMotion` is mapped to {@link rootMotionMode} the same way as
|
|
370
|
+
* {@link playAnimation}.
|
|
371
|
+
*/
|
|
372
|
+
crossfadeTo(animName: string, opts?: {
|
|
373
|
+
duration?: number;
|
|
374
|
+
rootMotion?: boolean;
|
|
375
|
+
loop?: boolean;
|
|
376
|
+
preserveTime?: boolean;
|
|
377
|
+
}): boolean;
|
|
378
|
+
/**
|
|
379
|
+
* Play `animName` on the named overlay layer, gated to `mask`'s bone set.
|
|
380
|
+
* Layers compose on top of the base animation in {@link update} - for each
|
|
381
|
+
* bone in the mask, the current pose is interpolated toward the overlay's
|
|
382
|
+
* pose by the layer weight.
|
|
383
|
+
*
|
|
384
|
+
* Creates the layer lazily on first use (allocates a per-layer
|
|
385
|
+
* {@link AnimationPlayer} sharing the same skeleton and animation provider
|
|
386
|
+
* as the base). Subsequent calls reuse the same player.
|
|
387
|
+
*/
|
|
388
|
+
playLayerAnimation(layerName: string, animName: string, mask: BoneMask, opts?: {
|
|
389
|
+
loop?: boolean;
|
|
390
|
+
crossfade?: number;
|
|
391
|
+
weight?: number;
|
|
392
|
+
}): boolean;
|
|
393
|
+
/** Set the overlay weight for a layer in `[0, 1]`. No-op if the layer doesn't exist. */
|
|
394
|
+
setLayerWeight(layerName: string, weight: number): void;
|
|
395
|
+
/**
|
|
396
|
+
* Pause or resume every active overlay layer. The base animation is
|
|
397
|
+
* controlled separately via {@link paused}. Useful so a single play/pause
|
|
398
|
+
* toggle in an editor or pause menu freezes the whole stack together.
|
|
399
|
+
*/
|
|
400
|
+
setAllLayersPaused(paused: boolean): void;
|
|
401
|
+
/**
|
|
402
|
+
* Stop and remove the named layer. With `fadeDuration > 0`, ramps the
|
|
403
|
+
* layer weight to zero over `fadeDuration` seconds before tearing down.
|
|
404
|
+
*/
|
|
405
|
+
stopLayer(layerName: string, fadeDuration?: number): void;
|
|
406
|
+
/** Stop with optional crossfade back to rest pose. */
|
|
407
|
+
stop(fadeDuration?: number): void;
|
|
408
|
+
/**
|
|
409
|
+
* Advance animation time by `dt` seconds, evaluate pose, and push bone
|
|
410
|
+
* transforms to linked splats. Called for you by `engine.update()` unless auto-update is detached.
|
|
411
|
+
*/
|
|
412
|
+
update(dt: number): void;
|
|
413
|
+
/**
|
|
414
|
+
* Resolve named rig conventions once skeleton library is available.
|
|
415
|
+
* If `boneNames` is present, looks up "root" and any name containing
|
|
416
|
+
* "pelvis"; otherwise falls back to bone index 0 as root.
|
|
417
|
+
*/
|
|
418
|
+
private _resolveRigIndices;
|
|
419
|
+
/**
|
|
420
|
+
* Compose overlay layers onto `_currentPose`. Each layer ticks its own
|
|
421
|
+
* player, evaluates a full pose into a scratch buffer, then per masked
|
|
422
|
+
* bone interpolates the current pose toward the overlay by the layer
|
|
423
|
+
* weight. Runs before `_applyRigPostClamps` so pelvis/root clamps stay
|
|
424
|
+
* authoritative.
|
|
425
|
+
*/
|
|
426
|
+
private _evaluateLayers;
|
|
427
|
+
/**
|
|
428
|
+
* Apply rig-convention rules to the freshly-evaluated pose:
|
|
429
|
+
* - root-motion routing - `'apply'` writes `baseline + (pelvis − bind)`
|
|
430
|
+
* to the pivot; `'extract'` accumulates the per-frame pelvis Δ;
|
|
431
|
+
* `'off'` does nothing.
|
|
432
|
+
* - pelvis X/Z clamp to bind in bone space (always - the motion lives on
|
|
433
|
+
* the pivot / in the consumed delta, not on the bone).
|
|
434
|
+
* - pelvis-Y lock to bind (when {@link lockPelvisY} is set).
|
|
435
|
+
* - root-bone full clamp to bind.
|
|
436
|
+
*/
|
|
437
|
+
private _applyRigPostClamps;
|
|
438
|
+
/**
|
|
439
|
+
* Apply runtime bone scaling. Each entry scales a bone's flesh + segment in
|
|
440
|
+
* its own frame - `{ along, width, thickness }` (each defaulting to `1`), or
|
|
441
|
+
* a bare number for uniform scale. e.g. `{ thigh_l: { along: 1.3 }, calf_l:
|
|
442
|
+
* { along: 1.3 } }` → a 1.3× longer left leg; `{ upperarm_l: { width: 1.4,
|
|
443
|
+
* thickness: 1.4 } }` → a beefier arm. Bones not listed stay at `1`. Pass
|
|
444
|
+
* `null` to clear. Works for any bone set (limbs, spine, …); see
|
|
445
|
+
* {@link computeBoneStretch} for the model. Recompute only when factors
|
|
446
|
+
* change - the result is applied every frame by the skeleton + skinning.
|
|
447
|
+
*/
|
|
448
|
+
setBoneStretch(factors: Record<string, BoneScaleInput> | null): void;
|
|
449
|
+
/** Push the current pose through skeleton + skinning. Called at link time. */
|
|
450
|
+
private _pushPose;
|
|
451
|
+
private _cameraFrustum;
|
|
452
|
+
/**
|
|
453
|
+
* The pivot's world matrix in the skeletal core's own matrix type. Refreshes
|
|
454
|
+
* the three.js world matrix first, so a transform set this frame is seen
|
|
455
|
+
* this frame.
|
|
456
|
+
*/
|
|
457
|
+
private _worldTransform;
|
|
458
|
+
/**
|
|
459
|
+
* Squared distance from the pivot's world origin to the engine camera, or
|
|
460
|
+
* `null` when the engine has no camera. Drives the distance-LOD bands.
|
|
461
|
+
* @internal
|
|
462
|
+
*/
|
|
463
|
+
cameraDistanceSq(): number | null;
|
|
464
|
+
/**
|
|
465
|
+
* Enable / configure distance-based animation LOD for THIS armature.
|
|
466
|
+
* LOD is off by default (full rate); calling this is the opt-in.
|
|
467
|
+
*
|
|
468
|
+
* - **No args**: pull the engine's `animLodPreset` (set via
|
|
469
|
+
* `SplatEngine.animLodPreset`). If the engine has no preset, fall back to a
|
|
470
|
+
* built-in default (full rate ≤12 m, every-2nd ≤24 m, every-4th
|
|
471
|
+
* beyond). Typical gameplay use: set the preset once, then call
|
|
472
|
+
* `armature.setAnimationLod()` on each throttle-able character.
|
|
473
|
+
* - **Partial opts**: tweak individual knobs on top of current values.
|
|
474
|
+
*
|
|
475
|
+
* `nearDist` / `farDist` are world-space distances (m) from the camera;
|
|
476
|
+
* `nearStride` / `farStride` are frames-per-update in the mid / far
|
|
477
|
+
* bands. A stride of 1 means every frame.
|
|
478
|
+
*/
|
|
479
|
+
setAnimationLod(opts?: {
|
|
480
|
+
nearDist?: number;
|
|
481
|
+
farDist?: number;
|
|
482
|
+
nearStride?: number;
|
|
483
|
+
farStride?: number;
|
|
484
|
+
}): void;
|
|
485
|
+
/** Disable LOD throttling - every character animates at full rate
|
|
486
|
+
* regardless of distance (frustum cull still applies). */
|
|
487
|
+
disableAnimationLod(): void;
|
|
488
|
+
/**
|
|
489
|
+
* Enable / configure distance-based SORT LOD for THIS armature.
|
|
490
|
+
*
|
|
491
|
+
* Throttles only the CPU-side `splat.updatePositions` call (the dominant
|
|
492
|
+
* cost - ~88% of per-character CPU at high counts) without freezing the
|
|
493
|
+
* rendered pose. On throttled frames the GPU palette still uploads, so
|
|
494
|
+
* animation looks correct; only the depth-sort order lags one frame.
|
|
495
|
+
*
|
|
496
|
+
* Composes with {@link setAnimationLod} - when anim LOD throttles a
|
|
497
|
+
* frame, sort LOD is moot for that frame; when anim LOD evaluates, sort
|
|
498
|
+
* LOD can independently decide to skip the positions push.
|
|
499
|
+
*
|
|
500
|
+
* Typical use: tighter near band than anim LOD (e.g. 5–10 m) so even
|
|
501
|
+
* mid-distance characters skip the sort re-upload most frames.
|
|
502
|
+
*
|
|
503
|
+
* - **No args**: enable with a built-in default
|
|
504
|
+
* (nearDist=5, farDist=15, nearStride=2, farStride=4).
|
|
505
|
+
* - **Partial opts**: tweak individual knobs on top of current values.
|
|
506
|
+
*/
|
|
507
|
+
setSortLod(opts?: {
|
|
508
|
+
nearDist?: number;
|
|
509
|
+
farDist?: number;
|
|
510
|
+
nearStride?: number;
|
|
511
|
+
farStride?: number;
|
|
512
|
+
}): void;
|
|
513
|
+
/** Disable sort LOD - every character does the full updatePositions
|
|
514
|
+
* every frame (still gated by `skipPositions` and anim LOD). */
|
|
515
|
+
disableSortLod(): void;
|
|
516
|
+
/** Frames-per-update for this armature this frame, based on camera
|
|
517
|
+
* distance. 1 = full rate. Returns 1 when no camera is available so
|
|
518
|
+
* we never freeze a character due to missing engine state. */
|
|
519
|
+
private _lodStride;
|
|
520
|
+
/** True when sort LOD says "skip the CPU positions re-upload this frame".
|
|
521
|
+
* Uses the same camera-distance bands shape as anim LOD, but a separate
|
|
522
|
+
* counter so the two strides don't lock-step. */
|
|
523
|
+
private _sortLodSkipThisFrame;
|
|
524
|
+
}
|