import * as THREE from 'three/webgpu'; import type { Renderer } from 'three/webgpu'; import type { GaussianSplats } from './GaussianSplats.cjs'; /** Options for {@link SplatSkin}. */ export interface SplatSkinOptions { /** * Splats farther than this from the rig's rest surface stay static (rig bind-space units). * Default: every splat follows the rig. */ maxDistance?: number | undefined; /** * How a splat's shape follows the rig. * - `'surface'` (default): the bound triangle, as posed by shape keys and skinning, stretches, * shears and turns the splat, so stretched skin stays covered and fur turns with a bulging muscle. * - `'rigid'`: splats only turn with their bones and keep their rest size; shape keys translate them. */ deformation?: 'surface' | 'rigid' | undefined; } /** * Drives Gaussian splats from a rigged glTF the way a `SkinnedMesh` is driven: skeleton, * `AnimationMixer` clips and `morphTargetInfluences` all apply, the splats replace the triangles. * * Binding is geometric and happens once on the GPU: every splat center is attached to the * closest point of the rig's rest-pose surface. Nothing is baked into the splat file, so any * splat that overlaps a rigged mesh can be bound, in any row order. * * Place the splats where the un-skinned meshes sit (the Mesh to Splat `--skinned` export does: * add both at the same transform), then: * * ```js * const skin = new SplatSkin( splats, gltf.scene ); * const mixer = new THREE.AnimationMixer( gltf.scene ); * mixer.clipAction( gltf.animations[ 0 ] ).play(); * ``` * * @class SplatSkin * @short Skeletal and morph-target animation for Gaussian splats. * @category GaussianSplatting */ export declare class SplatSkin { /** The splats being driven. */ readonly splats: GaussianSplats; /** Skeleton whose bones pose the splats. */ readonly skeleton: THREE.Skeleton; /** Skinned meshes whose surface the splats are bound to; their `morphTargetInfluences` apply. */ readonly meshes: THREE.SkinnedMesh[]; private readonly _count; private readonly _toBind; private readonly _pose; private readonly _poseScratch; private readonly _poseAttribute; private readonly _influenceBase; /** [ mesh, morph target index ] per global influence slot. */ private readonly _targets; /** Per-bone rest AABB of the vertices it moves, in splat source space (6 floats per bone). */ private readonly _boneBounds; private readonly _boundsMargin; private readonly _restBounds; private readonly _restChunkBounds; private readonly _chunkBounds; private readonly _keepRestBounds; private _bvhData; private _bindCompute; private readonly _resolveCompute; private readonly _storage; private _renderer; private readonly _onBeforeUpdate; /** * Bind splats to the skinned meshes found under a rig. Both must already sit where they * belong: the splats over the un-skinned meshes. * * @param {GaussianSplats} splats Loaded splats with `attributeMode: 'expanded'`. * @param {THREE.Object3D} root Rig root, typically `gltf.scene`; its `SkinnedMesh`es share one skeleton. * @param {SplatSkinOptions} [options] Binding options. */ constructor(splats: GaussianSplats, root: THREE.Object3D, options?: SplatSkinOptions); /** * Re-pose the splats when the skeleton or a morph influence changed. Runs by itself from the * splats' `beforeupdate`; call it manually only when `splats.autoUpdate` is off. * * @param {THREE.Renderer} renderer Active renderer. * @returns {boolean} Whether the splats were re-posed. */ update(renderer: Renderer): boolean; /** Conservative posed bounds: a skinned point is a convex blend of its bones' transformed rest points. */ private _updateBounds; /** Detach from the splats and put them back in their rest pose. */ dispose(): void; }