import { Box3, Vector3 } from 'three/webgpu'; import type { Renderer } from 'three/webgpu'; import type { GaussianSplats } from './GaussianSplats.cjs'; /** Controls the accuracy and bounded memory cost of a static splat collision snapshot. */ export interface SplatVoxelColliderOptions { /** World-space region to voxelize. Defaults to the transformed source bounds plus maxSplatRadius. */ bounds?: Box3 | undefined; /** World-space cell edge length. Default: 0.08. */ voxelSize?: number | undefined; /** Opacity at the collision surface; faint splats are ignored. Default: 0.2. */ opacityThreshold?: number | undefined; /** Ignore splats whose opacity ellipsoid exceeds this world-space radius. Default: 0.5. */ maxSplatRadius?: number | undefined; /** Maximum occupancy allocation, in bytes. Default: 16 MiB. Fails instead of reducing accuracy. */ maxBytes?: number | undefined; } /** * Static, world-space voxel collision for splats. One bit per cell, one GPU readback at build, * no GPU work or allocations during collision queries. Rebuild after changing the source or * its transform. Custom material deformations are not included in the snapshot. */ export declare class SplatVoxelCollider { /** World-space edge length of each collision cell. */ readonly voxelSize: number; /** Snapshot bounds, rounded out to whole cells. Treat as immutable. */ readonly bounds: Box3; /** Grid dimensions. Treat as immutable. */ readonly dimensions: Vector3; /** One bit per voxel, X fastest, then Y, then Z. */ readonly occupancy: Uint32Array; /** Total build wall time, including shader compilation and the one readback. */ buildMilliseconds: number; private readonly _normal; private readonly _bestNormal; private readonly _halfCell; /** Construct from a packed occupancy snapshot. Normally use {@link fromSplats}. */ constructor(bounds: Box3, voxelSize: number, occupancy?: Uint32Array); /** Build from the already loaded GPU source. Call after renderer.init() and source transforms. */ static fromSplats(renderer: Renderer, splats: GaussianSplats, options?: SplatVoxelColliderOptions): Promise; /** Whether an integer cell is occupied. Space outside the snapshot is empty. */ hasVoxel(x: number, y: number, z: number): boolean; /** Visit occupied cell centers for an optional debug view. The vector is reused. */ forEachVoxel(visit: (center: Vector3) => void): void; /** Move and bounce a sphere. Mutates position and velocity; gravity belongs to the caller. */ moveSphere(position: Vector3, velocity: Vector3, radius: number, delta: number, restitution?: number): boolean; /** Snap a capsule straight down to the first supporting cell, without sliding off a step edge. */ snapToGround(position: Vector3, radius: number, height: number, distance: number): boolean; /** * Move an upright capsule, slide against occupied cells, and return whether it touched ground. * Position is the capsule center; height includes its two hemispheres. Substeps are bounded by * both radius and cell size, so a fast body cannot jump through a one-cell wall. */ moveCapsule(position: Vector3, velocity: Vector3, radius: number, height: number, delta: number, restitution?: number): boolean; private _resolve; }