import * as THREE from 'three/webgpu'; import { GaussianSplatsMaterial } from './GaussianSplatsMaterial.js'; import { SplatBlendBracket } from './SplatBlendBracket.js'; import { SplatSHResolver } from './SplatSHResolver.js'; import { SplatComputeTileRenderer } from './SplatComputeTileRenderer.js'; import { GaussianSplatShadowCaster } from './GaussianSplatShadowNode.js'; import type { GaussianSplatsAlphaMode, GaussianSplatsCompositing, GaussianSplatsLightingMode, GaussianSplatsMaterialOptions } from './GaussianSplatsMaterial.js'; import type { SplatComputeTileLightingOptions, SplatComputeTileRendererOptions, SplatComputeTileStats } from './SplatComputeTileRenderer.js'; import type { SplatRenderViewContext, SplatSceneCoordinatorHandle } from './SplatSceneCoordinator.js'; import type { SplatSourceData, SplatSourceResource, SplatSourceResourceOptions } from './SplatSourceResource.js'; import type { SplatSHResource, SplatSHResourceData } from './SplatSHResource.js'; import type { GaussianSplatShadowLight, GaussianSplatShadowNode, GaussianSplatShadowOptions } from './GaussianSplatShadowNode.js'; import type { GaussianSplatsLoaderOptions, GaussianSplatsLoadTimings, GaussianSplatsParseSource, GaussianSplatsProcessProgressCallback } from './GaussianSplatsLoader.js'; import type { ComputeBatch } from '../Utils/ComputeBatch.js'; import type { TSLStorageNode, TSLUniformArrayNode, TSLUniformNode } from '../types/tsl.js'; export type GaussianSplatsSortMode = 'radial' | 'depth'; export type GaussianSplatsSortPrecision = 'float16' | 'float32'; export type GaussianSplatsSortAlgorithm = 'radix' | 'bitonic'; export type GaussianSplatsAttributeMode = 'expanded' | 'compact' | 'sog' | 'auto'; export type GaussianSplatsRendererMode = 'auto' | 'raster' | 'compute-tiles'; export type GaussianSplatsCoordinateSystem = 'threejs' | 'source'; export interface GaussianSplatsOptions { maxSplats?: number | undefined; maxBufferBytes?: number | undefined; splatCapacity?: number | undefined; enableSH?: boolean | undefined; shDegree?: number | undefined; frustumCulling?: boolean | undefined; frustumPadding?: number | undefined; sortEnabled?: boolean | undefined; sortMode?: GaussianSplatsSortMode | undefined; sortPrecision?: GaussianSplatsSortPrecision | undefined; sortAlgorithm?: GaussianSplatsSortAlgorithm | undefined; sortRadixBits?: number | 'auto' | undefined; temporalStability?: boolean | undefined; coordinateSystem?: GaussianSplatsCoordinateSystem | undefined; maxStdDev?: number | undefined; blurAmount?: number | undefined; preBlurAmount?: number | undefined; radiusClip?: number | undefined; compaction?: boolean | undefined; attributeMode?: GaussianSplatsAttributeMode | undefined; compactAllowColorClamping?: boolean | undefined; alphaClip?: number | undefined; minContribution?: number | undefined; opacityAwareRadius?: boolean | undefined; fragmentAlphaClip?: number | undefined; shColorMode?: 'direct' | 'cached' | undefined; shColorUpdateAngle?: number | undefined; shColorUpdateDistance?: number | undefined; recommendedRenderScale?: number | undefined; rendererMode?: GaussianSplatsRendererMode | undefined; computeTiles?: SplatComputeTileRendererOptions | undefined; alphaMode?: GaussianSplatsAlphaMode | undefined; lightingMode?: GaussianSplatsLightingMode | undefined; /** * Unlit blend space. Every 3DGS forward model alpha-blends display-encoded colors: * - 'faithful' (default) blends them that way inside a color-managed renderer (any tone mapping * or output color space) by bracketing the draw with a scene copy and a display-space resolve. * Lit mode, MRT passes and the compute-tile renderer render as 'linear'. * - 'display' writes them raw and REQUIRES NoToneMapping + LinearSRGBColorSpace output. Same * image, no bracket cost. * - 'linear' linearizes per splat and blends in linear light: cheapest, lifts translucent stacks. */ compositing?: GaussianSplatsCompositing | undefined; material?: THREE.Material | null | undefined; ownsMaterial?: boolean | undefined; createSource?: SplatSourceFactory | null | undefined; } export interface SplatSourceFactoryContext extends SplatSourceResourceOptions { capacity: number; } export type SplatSourceFactory = (data: GaussianSplatsData, count: number, options: SplatSourceFactoryContext) => SplatSourceResource | null; export interface GaussianSplatsData extends SplatSourceData, SplatSHResourceData { count: number; shDegree?: number | undefined; normals?: Float32Array | null | undefined; chunkBounds?: Float32Array | null | undefined; chunkSize?: number | undefined; chunkBoundsMaxStdDev?: number | undefined; sourceFormat?: string | undefined; } export type SplatQualityProfileName = 'quality'; export interface SplatMeshOptions extends GaussianSplatsOptions { quality?: SplatQualityProfileName | undefined; sh?: number | boolean | 'auto' | undefined; performance?: Partial | undefined; appearance?: SplatMeshAppearanceOptions | undefined; autoUpdate?: boolean | undefined; manager?: THREE.LoadingManager | undefined; onProgress?: (event: ProgressEvent) => void; onProcessProgress?: GaussianSplatsProcessProgressCallback | undefined; signal?: AbortSignal | undefined; worker?: boolean | 'auto' | undefined; workerThreshold?: number | undefined; transferSourceBuffer?: boolean | undefined; } export interface SplatMeshAppearanceOptions extends Partial { mode?: GaussianSplatsLightingMode | undefined; opacity?: number | undefined; } export interface NormalizedSplatMeshOptions { appearance: SplatMeshAppearanceOptions; autoUpdate: boolean; loaderOptions: GaussianSplatsLoaderOptions; manager: THREE.LoadingManager | undefined; onProgress: ((event: ProgressEvent) => void) | undefined; performanceOptions: Record; } export interface GaussianSplatsUniforms { modelMatrix: TSLUniformNode<'mat4', THREE.Matrix4>; inverseModelMatrix: TSLUniformNode<'mat4', THREE.Matrix4>; viewMatrix: TSLUniformNode<'mat4', THREE.Matrix4>; inverseViewMatrix: TSLUniformNode<'mat4', THREE.Matrix4>; projMatrix: TSLUniformNode<'mat4', THREE.Matrix4>; viewProjMatrix: TSLUniformNode<'mat4', THREE.Matrix4>; cameraPosition: TSLUniformNode<'vec3', THREE.Vector3>; screenSize: TSLUniformNode<'vec2', THREE.Vector2>; frustumPadding: TSLUniformNode<'float', number>; focalLength: TSLUniformNode<'vec2', THREE.Vector2>; splatCount: TSLUniformNode<'uint', number>; visibleCount: TSLUniformNode<'uint', number>; near: TSLUniformNode<'float', number>; far: TSLUniformNode<'float', number>; sortRangeMin: TSLUniformNode<'float', number>; sortEnabled: TSLUniformNode<'uint', number>; sortRangeMax: TSLUniformNode<'float', number>; sortKeyHashMask: TSLUniformNode<'uint', number>; tanFovY: TSLUniformNode<'float', number>; tanFovX: TSLUniformNode<'float', number>; maxStdDev: TSLUniformNode<'float', number>; blurAmount: TSLUniformNode<'float', number>; shStrength: TSLUniformNode<'float', number>; preBlurAmount: TSLUniformNode<'float', number>; radiusClip: TSLUniformNode<'float', number>; alphaClip: TSLUniformNode<'float', number>; minContribution: TSLUniformNode<'float', number>; opacityAwareRadius: TSLUniformNode<'bool', boolean>; fragmentAlphaClip: TSLUniformNode<'float', number>; numChunks: TSLUniformNode<'uint', number>; frustumPlanes: TSLUniformArrayNode<'vec4'>; } export interface GaussianSplatsBuffers { projected: TSLStorageNode<'vec4'>; bakedNormals: TSLStorageNode<'uint'> | null; sortKeys: TSLStorageNode<'uint'> | null; sortIndices: TSLStorageNode<'uint'> | null; sortPairs: TSLStorageNode<'uvec2'> | null; chunkBounds: TSLStorageNode<'float'> | null; visibleChunks: TSLStorageNode<'uint'> | null; compactedCount: TSLStorageNode<'uint'> | null; regionKeys?: TSLStorageNode<'uint'> | null; regionIndices?: TSLStorageNode<'uint'> | null; regionPrefix?: TSLStorageNode<'uint'> | null; resolvedSH?: TSLStorageNode<'vec4'> | null; [name: string]: object | null | undefined; } export type GaussianSplatsGPUStage = 'unpack' | 'projection' | 'sort' | 'tiles'; export interface GaussianSplatsGPUTimings { available: boolean; uploadMilliseconds: number | null; unpackMilliseconds: number | null; projectionMilliseconds: number | null; sortMilliseconds: number | null; tilesMilliseconds: number | null; totalMilliseconds: number | null; } export interface GaussianSplatsStats { sourceSplats: number; visibleChunks: number | null; intervalSplats: number | null; compactedSplats: number | null; projectedSplats: number | null; sortedSplats: number | null; drawSplats: number; gpuBytes: number; sourceCpuBytes: number; sourceGpuBytes: number; attributeMode: string | null; shStorageMode: string | null; shCpuBytes: number; shGpuBytes: number; sourceFormat: string | null; parseMilliseconds: number | null; uploadMilliseconds: number | null; loadTimings: GaussianSplatsLoadTimingSnapshot | null; recommendedRenderScale: number; rendererMode: string; computeTiles: SplatComputeTileStats | null; shColorMode: 'cached' | 'direct'; shRefreshes: number; gpuTimings: GaussianSplatsGPUTimings; shadowLights: number; shadowInstances: number; shadowRenders: number; } export interface GaussianSplatsLoadTimingSnapshot extends Partial { parseMilliseconds?: number | undefined; [name: string]: number | undefined; } export interface GaussianSplatsWaitOptions { afterVersion?: number | undefined; signal?: AbortSignal | undefined; timeout?: number | undefined; } export interface GaussianSplatsRenderEvent { type: 'rendercomplete'; version: number; renderer?: THREE.Renderer | undefined; scene?: THREE.Scene | undefined; camera?: THREE.Camera | undefined; } export interface GaussianSplatsEventMap extends THREE.Object3DEventMap { beforeupdate: { renderer: THREE.Renderer; camera: THREE.Camera; }; rendercomplete: Omit; dispose: Record; } export interface GaussianSplatsRangeData { positions: Float32Array; scales: Float32Array; rotations: Float32Array; colors: Float32Array; } export interface GaussianSplatsRenderRecommendation { scale: number; minDimensionCap: number; reason: string; rendererMode: string; } export interface GaussianSplatsReadback { keys: Uint32Array; indices: Uint32Array; } interface GaussianSplatsShadowRegistration { node: GaussianSplatShadowNode; options: GaussianSplatShadowOptions; caster: GaussianSplatShadowCaster | null; } interface GaussianSplatsSorter { compute(renderer: THREE.Renderer): void; init(renderer: THREE.Renderer): void; dispose(): void; timestampContexts?: Array | undefined; } interface GaussianSplatsRangedSourceResource extends SplatSourceResource { uploadRange?(buffers: object, offset: number, data: GaussianSplatsRangeData | null, sourceIndex: number, count: number): void; } interface GaussianGUIController { name(label: string): this; listen(): this; } export interface GaussianGUIFolder { add(target: object, property: string, ...parameters: number[]): GaussianGUIController; addFolder?(label: string): GaussianGUIFolder; } /** * GPU-accelerated 3D Gaussian Splatting renderer for Three.js WebGPU. * * **Features** * - WebGPU compute pipeline for frustum culling and depth sorting * - Efficient packed data format (32 bytes/splat base) * - Optional spherical harmonics (SH degree 0-3) for view-dependent color * - Radix sort for O(n) back-to-front depth ordering * - Billboard quad generation in vertex shader * - Anisotropic Gaussian rendering with 2D covariance projection * * **Usage** * ```js * import { SplatMesh } from 'three-blocks/gaussian-splats'; * import * as THREE from 'three/webgpu'; * * const renderer = new THREE.WebGPURenderer(); * await renderer.init(); * * const splats = await SplatMesh.load('/models/scene.ply'); * scene.add(splats); * * function animate() { * renderer.render(scene, camera); * } * ``` * * @class GaussianSplats * @extends THREE.Object3D * @short GPU Gaussian Splatting with compute culling, radix depth sort, and anisotropic quad rendering. * @category Rendering * @tags WebGPU */ export declare class GaussianSplats extends THREE.Object3D { /** Runtime type guard that is always `true` for Gaussian splat renderers. */ readonly isGaussianSplats: true; /** Number of active splats in the current data set. */ count: number; /** Allocated upper bound for resident splats. */ maxSplats: number; /** Whether compute projection rejects splats outside the camera frustum. */ frustumCullingEnabled: boolean; /** Whether visible splats are depth-sorted before drawing. */ sortEnabled: boolean; /** Active sorting policy. */ sortMode: GaussianSplatsSortMode; /** Depth-key precision used by the sorter. */ sortPrecision: GaussianSplatsSortPrecision; /** GPU sorting algorithm used for visible splats. */ sortAlgorithm: GaussianSplatsSortAlgorithm; /** Radix bits processed by each sort pass. */ sortRadixBits: 1 | 2 | 4 | 'auto'; /** Number of splats submitted to the latest sort. */ sortCount: number; /** Whether unchanged camera state may reuse the previous projection and sort. */ temporalStability: boolean; /** Whether projected records are compacted before sorting and drawing. */ compaction: boolean; /** Resident attribute-storage representation. */ attributeMode: GaussianSplatsAttributeMode; /** Whether compact attribute conversion may clamp out-of-range colours. */ compactAllowColorClamping: boolean; /** Recommended application-managed render-scale multiplier. */ recommendedRenderScale: number; /** Active raster or compute-tile rendering path. */ rendererMode: GaussianSplatsRendererMode; /** Material currently used by the renderable splat mesh. */ material: THREE.Material | GaussianSplatsMaterial | null; /** Resident GPU attribute buffers, or `null` before data is installed. */ buffers: GaussianSplatsBuffers | null; /** Mutable uniforms shared by the projection and draw graphs. */ uniforms: GaussianSplatsUniforms; /** Indirect draw arguments owned by the renderer. */ indirect: THREE.IndirectStorageBufferAttribute | null | undefined; /** TSL storage node exposing the indirect draw structure. */ drawStructNode: TSLStorageNode | null | undefined; /** Group containing the current static render mesh. */ staticGroup: THREE.Group | null | undefined; _coordTransform: THREE.Matrix4; _createSource: SplatSourceFactory | null; _requestedMaxSplats: number; _maxBufferBytes: number; _splatCapacity: number; _enableSH: boolean; _shDegree: number; _maxDataSHDegree: number; _sourceResource: GaussianSplatsRangedSourceResource | null; _shResource: SplatSHResource | null; _shResolver: SplatSHResolver; _initialLightingMode: GaussianSplatsLightingMode; _compositing: GaussianSplatsCompositing; _blendBracket: SplatBlendBracket | null; _projectedRecordCount: number; _hasSurfaceRecord: boolean; _colorRecordIndex: number; _computeTilesOptions: SplatComputeTileRendererOptions; _tileRenderer: SplatComputeTileRenderer | null | undefined; _maxStdDev: number; _customMaterial: THREE.Material | null; _ownsCustomMaterial: boolean; _alphaMode: GaussianSplatsAlphaMode; _frustumPadding: number; _packedBakedNormals: Uint32Array | null; _allocatedSHCoeffCount: number; _allocatedNumChunks: number; _allocatedChunkSize: number; _data: GaussianSplatsData | null; _sourceBounds: THREE.Box3 | null; _chunkSize: number; _numChunks: number; _chunkBoundsData: Float32Array | null; _chunkBoundsMaxStdDev: number; _hierarchyEnabled: boolean; _initialized: boolean; _needsUpdate: boolean; _renderer: THREE.Renderer | null; _sorter: GaussianSplatsSorter | null; _mesh: THREE.Mesh | null; _autoUpdate: boolean; _disposed: boolean; readonly _splatSceneCoordinators: Set; readonly _shadowLights: Map; readonly _watchedHierarchy: Set; _onHierarchyChanged: () => void; _lastViewMatrix: THREE.Matrix4; _lastScreenSize: THREE.Vector2; _lastModelMatrix: THREE.Matrix4; _lastProjectionMatrix: THREE.Matrix4; _cameraMoved: boolean; _firstFrameRendered: boolean; _renderVersion: number; _gpuTimestampUIDs: Record; _gpuTimings: GaussianSplatsGPUTimings; _projectCompactedBatch: ComputeBatch | null | undefined; _projectBatch: ComputeBatch | null | undefined; _projectCompactedColorBatch: ComputeBatch | null | undefined; _projectColorBatch: ComputeBatch | null | undefined; _computeClear: THREE.ComputeNode | null | undefined; _computeClearSortTail: THREE.ComputeNode | null | undefined; _computeResetAll: THREE.ComputeNode | null | undefined; _computeChunkCull: THREE.ComputeNode | null | undefined; _computeProjectIndirect: THREE.ComputeNode | null | undefined; _computeCullProject: THREE.ComputeNode | null | undefined; _computeCapCount: THREE.ComputeNode | null | undefined; _computeScanRegions: THREE.ComputeNode | null | undefined; _computeCompactEntries: THREE.ComputeNode | null | undefined; _densePrefix: boolean; _resolveDispatchBuffer: THREE.IndirectStorageBufferAttribute | null | undefined; _sortDispatchBuffer: THREE.IndirectStorageBufferAttribute | null | undefined; _indirectDispatchBuffer: THREE.IndirectStorageBufferAttribute | null | undefined; _indirectDispatchNode: TSLStorageNode | null | undefined; _validatedDevice: object | null | undefined; _pendingMaterialState: Record | null | undefined; _pendingSHScatter: boolean; _recordResolverActive: boolean; _stillFrames: number; _loadTimings: GaussianSplatsLoadTimingSnapshot | null | undefined; _lastUploadMilliseconds: number | undefined; _quietLoad?: boolean; _hasLoggedLoad: boolean | undefined; _debugIndirect: boolean | undefined; _guiFolder: GaussianGUIFolder | undefined; _statsInterval: ReturnType | null | undefined; /** * Load a splat mesh with automatic scene updates and full-quality rendering. * * @param {string} url URL to a .ply, .splat, .splats, or .sog file. * @param {Object} [options={}] Loading, quality, appearance, and advanced renderer options. * @param {string} [options.quality='quality'] The sole rendering preset; quality is also the default. * @param {number|boolean|string} [options.sh='auto'] SH degree, false to disable SH, or 'auto'. * @param {Object} [options.performance] Performance overrides such as radiusClip and maxStdDev. * @param {Object} [options.appearance] Material overrides such as mode, roughness, and opacity. * @param {boolean} [options.autoUpdate=true] Automatically update before the containing scene renders. * @param {THREE.LoadingManager} [options.manager] Loading manager. * @param {Function} [options.onProgress] Progress callback. * @param {Function} [options.onProcessProgress] Processing-stage progress callback. * @param {AbortSignal} [options.signal] Optional cancellation signal for asynchronous preprocessing. * @param {boolean|'auto'} [options.worker='auto'] Use a module worker for large PLY preprocessing, force it, or disable it. * @param {number} [options.workerThreshold=4194304] Minimum PLY byte length before automatic worker preprocessing. * @param {boolean} [options.transferSourceBuffer=true] Transfer ownership of URL-loaded source bytes to the worker without copying. * @returns {Promise} Loaded splat mesh. */ static load(url: string, options?: SplatMeshOptions): Promise; /** * Parse a splat mesh buffer with automatic scene updates and an optional quality preset. * * @param {ArrayBuffer} buffer File data. * @param {string} url Original URL or filename for format detection. * @param {Object} [options={}] Loading, quality, appearance, and advanced renderer options. * @param {Function} [options.onProcessProgress] Processing-stage progress callback. * @param {AbortSignal} [options.signal] Optional cancellation signal for asynchronous preprocessing. * @param {boolean|'auto'} [options.worker='auto'] Use a module worker for large PLY preprocessing, force it, or disable it. * @param {number} [options.workerThreshold=4194304] Minimum PLY byte length before automatic worker preprocessing. * @param {boolean} [options.transferSourceBuffer=true] Transfer and detach the caller-owned source buffer instead of copying it for the worker. Pass false to keep using the buffer after parse. * @returns {Promise} Parsed splat mesh. */ static parse(buffer: GaussianSplatsParseSource, url: string, options?: SplatMeshOptions): Promise; /** * Create a Gaussian Splatting renderer. * * @param {Object} [options={}] Configuration options. * @param {number} [options.maxSplats=Infinity] Maximum splat capacity. Unbounded by default; the GPU storage-buffer limit still applies (see maxBufferBytes) and any clamp warns loudly. * @param {boolean} [options.enableSH=true] Enable spherical harmonics for view-dependent color. * @param {number} [options.shDegree=2] SH degree (0-3). Higher = more view-dependent detail. * @param {boolean} [options.frustumCulling=true] Enable GPU frustum culling. * @param {number} [options.frustumPadding=0.1] Frustum padding factor. * @param {boolean} [options.sortEnabled=true] Enable depth sorting (required for correct transparency). * @param {string} [options.sortMode='radial'] Sort mode: 'radial' (distance from camera, SparkJS default) or 'depth' (Z-depth). * @param {string} [options.sortPrecision='float16'] Sort precision: 'float16' (faster, default) or 'float32' (precise but 2x slower). * @param {string} [options.sortAlgorithm='radix'] Sort algorithm: 'radix' (O(n), default) or 'bitonic' (O(n log²n)). * @param {number|'auto'} [options.sortRadixBits='auto'] Radix bits per pass (1, 2, 4, or 'auto'). 'auto' uses 4 bits up to 256k splats (fewer passes win while dispatch-latency-bound) and 2 bits above (measured faster at 1M+, where passes are bandwidth-bound). * @param {boolean} [options.temporalStability=true] Skip re-sorting when camera barely moves (optimization). * @param {number} [options.maxStdDev=Math.sqrt(8)] Max Gaussian extent in std devs. sqrt(8)≈2.83 default, sqrt(5)≈2.24 for VR/mobile. * @param {number} [options.blurAmount=0.3] Screen-space Mip filter variance with opacity compensation. Reduces aliasing without changing apparent energy. * @param {number} [options.preBlurAmount=0.0] Uncompensated screen-space blur variance for scenes trained without antialiasing. * @param {number} [options.radiusClip=0.0] Skip projected splats at or below this pixel radius during compute. Raise for large scenes when a fidelity tradeoff is acceptable. * @param {boolean} [options.compaction=true] Pack each chunk's visible splats contiguously in splat order (deterministic, atomic-free) and track the visible count for the compute-tile renderer. Applies to radix sorting; set false for the one-slot-per-splat sentinel/debug path. * @param {'expanded'|'compact'|'sog'|'auto'} [options.attributeMode='expanded'] GPU source attribute storage mode. * @param {number} [options.alphaClip=0.5/255] Reject splats below this base opacity before projection. * @param {number} [options.minContribution=1] Reject splats with negligible projected alpha-area contribution. Zero disables rejection (the quality profile does). * @param {boolean} [options.opacityAwareRadius=true] Crop quads where the falloff crosses fragmentAlphaClip. The cropped edge is invisible by construction. * @param {'auto'|'raster'|'compute-tiles'} [options.rendererMode='raster'] Renderer path. Tiled compute remains opt-in while visual parity is validated. * @param {Object} [options.computeTiles] Optional tiled compute capacity and readback settings. * @param {'straight'|'premultiplied'} [options.alphaMode='straight'] Output and blending alpha contract. Straight is bit-exact to reference 3DGS compositing for canvas/sRGB targets (invariant I2); premultiplied premultiplies in encoded space and is intended for transparent-target accumulation (SplatRenderCompositor). * @param {'faithful'|'display'|'linear'} [options.compositing='faithful'] Unlit blend space. 'faithful' blends the stored display colors as trained inside a color-managed renderer; 'display' writes them raw and requires NoToneMapping + LinearSRGBColorSpace output; 'linear' blends in linear light. * @param {THREE.Material} [options.material] Custom material override. * @param {boolean} [options.ownsMaterial=false] Dispose a caller-provided custom material with the splat mesh. */ constructor(options?: GaussianSplatsOptions); /** * Extract frustum planes from view-projection matrix. * Updates this.uniforms.frustumPlanes with 6 normalized plane equations. * @private * @param {THREE.Matrix4} viewProjMatrix - Combined view-projection matrix. */ _updateFrustumPlanes(viewProjMatrix: THREE.Matrix4): void; /** * Create sort keys buffer filled with sentinel values. * Prevents first-frame artifacts by ensuring all keys sort to the end initially. * @private * @param {number} count Buffer size. * @returns {Uint32Array} Buffer filled with sentinel values. */ /** * Whether float16 sort keys carry the low-order spatial-hash byte. * * Dense scenes draw equal-depth buckets in hashed order to break same-pixel blend * hazard chains on tile GPUs (measured 16.4ms -> 11.1ms static on a fully visible * 1.25M-splat scene). Small scenes skip the hash: their buckets are shallow, and the * two extra radix passes would cost more than the decorrelation saves. * @private */ _sortKeyUsesSpatialHash(): boolean; /** * Sentinel key marking culled splats for the active sort-key layout. * @private */ _sortKeySentinelValue(): number; _createSortKeysBuffer(count: number): Uint32Array; /** * Create sequential index buffer [0, 1, 2, ...]. * Prevents first-frame artifacts from all-zero indices. * @private * @param {number} count Buffer size. * @returns {Uint32Array} Buffer with sequential indices. */ _createSequentialBuffer(count: number): Uint32Array; /** * Create sort pairs buffer with (sentinel, index) pairs for bitonic sort. * @private * @param {number} count Number of pairs. * @returns {Uint32Array} Buffer with uvec2 pairs (key, index). */ _createSortPairsBuffer(count: number): Uint32Array; _updateHierarchyPolicy(): void; _disposeBufferAttribute(attribute: unknown): void; /** Mesh-level intent for hosting the record fast path (final say is the resolver build). */ _recordDrawIntent(): boolean; _disposeProjectionComputeNodes(): void; _releaseGPUResources({ releaseMesh, releaseMaterial, }?: { releaseMesh?: boolean; releaseMaterial?: boolean; }): void; _createShadowCaster(registration: GaussianSplatsShadowRegistration): GaussianSplatShadowCaster | null; _disposeShadowCasters({ keepRegistrations }?: { keepRegistrations?: boolean; }): void; _rebuildShadowCasters(): void; _invalidateShadowLights(): void; /** * Allocate GPU storage buffers. * @private */ _allocateBuffers(): void; /** * Build compute shader passes. * Implements 2-pass hierarchical frustum culling with indirect dispatch. * @private */ _buildCompute(): void; /** * Projection submission for the active culling path, cached per variant. Dense mode * appends the region scan, the entry compaction and (when due) the visible-only color * resolve; the legacy path keeps the sentinel clear and the draw-count cap. * @private */ _projectionBatch(hierarchical: boolean, withColor: boolean): ComputeBatch; /** * Create the mesh with instanced geometry. * @private */ _createMesh(): void; /** * Wait until this splat mesh completes a render after the requested render version. * * @param {Object} [options={}] Wait options. * @param {number} [options.afterVersion=this.renderVersion] Resolve after this render version. * @param {AbortSignal} [options.signal] Optional cancellation signal. * @param {number} [options.timeout=0] Optional timeout in milliseconds. Zero disables the timeout. * @returns {Promise} Render-complete event. */ waitForRender(options?: GaussianSplatsWaitOptions): Promise; /** Completed non-shadow render count. @type {number} */ get renderVersion(): number; _clearHierarchyListeners(): void; _refreshSceneCoordinator(): void; _ensureSceneCoordinator(scene?: THREE.Scene | null): void; /** * Rebuild the material. * @private */ _rebuildMaterial(): void; /** * Set splat data from parsed arrays. * * @param {Object} data Parsed splat data. * @param {Float32Array} data.positions Position array (3 floats per splat). * @param {Float32Array} data.scales Scale array (3 floats per splat, log-space). * @param {Float32Array} data.rotations Rotation array (4 floats per splat, quaternion). * @param {Float32Array} data.colors Color array (4 floats per splat, RGBA). * @param {Float32Array} [data.shCoefficients] Optional SH coefficients. * @param {number} data.count Number of splats. * @param {number} [data.shDegree] SH degree from loaded data. */ setData(data: GaussianSplatsData): void; _validateDeviceLimits(renderer: THREE.Renderer): void; _beginGPUStageTimingFrame(renderer: THREE.Renderer): void; _recordGPUStageTimestamp(renderer: THREE.Renderer, stage: GaussianSplatsGPUStage, context: unknown): void; _resolveGPUStageTimings(): Promise; _dispatchSHScatter(renderer: THREE.Renderer): void; /** * Decide, per render call, whether this draw blends in display space ('faithful'). The * bracket rewrites the whole color target with NoBlending, which would also overwrite every * auxiliary MRT attachment; a scene override material would replace the pass shaders; and * lit shading needs linear light: all three render as 'linear'. * ponytail: MRT is only visible from inside the render call, i.e. under autoUpdate. With * autoUpdate off inside an MRT pass, construct with compositing: 'linear'. * @private */ _syncBlendBracket(renderer: THREE.Renderer): void; /** * Update splat rendering for current camera. * Normally called automatically before the containing scene renders. * * @param {THREE.WebGPURenderer} renderer WebGPU renderer. * @param {THREE.Camera} camera Active camera. * @param {Object} [viewContext] Active physical render-view context. */ update(renderer: THREE.Renderer, camera: THREE.Camera, viewContext?: SplatRenderViewContext): void; /** * Normalize float16 sort keys over the scene's visible metric range (invariant I3): the * log-depth mapping spans [sortRangeMin, sortRangeMax] derived from the world-space scene * bounds each frame, so all 65,534 key buckets land on actual content. Falls back to camera * near/far when no bounds are available. * @private * @param {THREE.PerspectiveCamera} camera Active camera. */ _updateSortKeyRange(camera: THREE.PerspectiveCamera): void; /** * Partial splat write for streaming residency (expanded attribute mode only): packs `count` * splats into GPU slots [offset, offset+count) with ranged buffer uploads, or zero-fills the * range (alpha 0 — projection-culled) when `data` is null. * * @param {number} offset First destination splat slot. * @param {{positions:Float32Array, scales:Float32Array, rotations:Float32Array, colors:Float32Array}|null} data Source arrays, or null to clear. * @param {number} [srcIndex=0] First source splat index within `data`. * @param {number} [count] Number of splats (defaults to data length minus srcIndex). * @returns {this} */ writeSplatRange(offset: number, data: GaussianSplatsRangeData | null, srcIndex?: number, count?: number): this; /** * Update hierarchical-culling chunk bounds for a chunk range (streaming residency). Each chunk * covers 256 splats; bounds are 6 floats (min xyz, max xyz) per chunk in source space. * * @param {number} chunkOffset First chunk index. * @param {Float32Array|number[]} bounds Flat bounds array (chunkCount × 6 floats). * @returns {this} */ writeChunkBoundsRange(chunkOffset: number, bounds: ArrayLike): this; /** * Override the source-space scene bounds used for scene-range sort-key normalization (I3). * Streaming scenes set this from their manifest, since resident data is a moving subset of * the full scene. * * @param {number[]} min Source-space minimum corner. * @param {number[]} max Source-space maximum corner. * @returns {this} */ setSourceBounds(min: ArrayLike, max: ArrayLike): this; /** * Force the projection and depth-sort compute passes to re-run on the next update, even when the * camera has not moved. Use this after mutating source data in place — for example when an animated * source (blend/morph, spacetime) changes an attribute uniform without moving the camera, so the * temporal-stability short-circuit would otherwise skip re-projection and re-sorting. * * @returns {this} */ invalidate(): this; /** * Get whether scene rendering automatically updates culling and sorting. * @type {boolean} */ get autoUpdate(): boolean; /** * Set whether scene rendering automatically updates culling and sorting. * Disable this only when manually calling update(renderer, camera). * @param {boolean} value Enable automatic scene updates. */ set autoUpdate(value: boolean); /** * Enable/disable indirect draw debug logging. * When enabled, logs instanceCount after each compute pass. * @type {boolean} */ set debugIndirect(value: boolean); get debugIndirect(): boolean; /** * Get current visible splat count. * Note: This reads from CPU-side array which may not reflect GPU value. * Use readIndirectArgs() for accurate GPU readback. * @type {number} * @readonly */ get visibleCount(): number; /** * Resident-buffer capacity pin (high-water mark) for dynamic reuse. Raising this lets subsequent * setData() calls with fewer splats reuse the resident buffers and compute pipeline instead of * reallocating — and recompiling the projection/sort shaders — every frame. setData never shrinks * below the live allocation, so this is effectively grow-only. 0 (default) leaves the static path * byte-identical. Dynamic players (SplatSequence) raise this to the clip's largest frame. * @type {number} */ get splatCapacity(): number; set splatCapacity(value: number); /** * Get CPU-visible renderer statistics without forcing GPU synchronization. * Use readStats() when current GPU counts are required. * @type {Object} * @readonly */ get stats(): GaussianSplatsStats; /** * Return a non-invasive render-scale recommendation for application-managed targets. * The renderer is never resized by this method. * * @param {THREE.WebGPURenderer} renderer Active renderer. * @param {THREE.Camera} camera Active camera. * @returns {{scale:number,minDimensionCap:number,reason:string,rendererMode:string}} Recommendation snapshot. */ getRenderRecommendation(renderer: THREE.Renderer, camera: THREE.Camera): GaussianSplatsRenderRecommendation; /** * Provide an opaque scene depth texture for compute-tile occlusion tests. * The texture must match the active renderer dimensions. * * @param {THREE.Texture|null} texture Opaque scene depth texture, or null to disable depth rejection. */ setOpaqueDepthTexture(texture: THREE.Texture | null): void; /** * Configure the compute-tile deferred lighting pass. * Use mode:'scene' to shade the reconstructed surface with native Three.js scene lights, * Scene.environment, AO, and received shadows. The default mode:'custom' preserves bounded Gaussian relighting. * Pass a shadow-casting DirectionalLight as directional.light to project its shadows onto reconstructed splat surfaces. * A shared directional.shadowNode avoids rendering the same shadow map again for standard mesh materials. * * @param {Object} lighting Deferred lighting configuration. */ setComputeTileLighting(lighting: SplatComputeTileLightingOptions): void; /** * Register this Gaussian scene as an alpha-clipped shadow caster for a directional, spot, or point light. * The returned proxy is isolated on a shadow-camera-only layer. Set * `light.shadow.autoUpdate = false` after the first render for static scenes. * * @param {THREE.DirectionalLight|THREE.SpotLight|THREE.PointLight} light Shadow-casting light. * @param {Object} [options={}] Shadow caster options. * @param {boolean} [options.enabled=true] Whether this caster participates in the shadow pass. * @param {'stochastic'|'clip'} [options.mode='stochastic'] Shadow transmittance mode. Stochastic dithers coverage proportionally to splat opacity (soft, PCF-resolved shadows); clip uses the binary alphaCutoff silhouette. * @param {number} [options.alphaCutoff=0.08] Alpha-clipped Gaussian silhouette threshold (dust floor in stochastic mode). * @param {number} [options.sigmaCoverage=1.75] Gaussian shadow footprint extent. * @param {number} [options.stride=1] Shadow-only LOD stride; higher values draw fewer splats. * @param {number} [options.opacity=1] Shadow caster opacity multiplier. * @returns {GaussianSplatShadowCaster|null} Layer-isolated shadow proxy, or null before data is loaded. */ addShadowLight(light: GaussianSplatShadowLight, options?: GaussianSplatShadowOptions): GaussianSplatShadowCaster | null; /** Update options for an existing Gaussian shadow-light registration. */ setShadowLightOptions(light: GaussianSplatShadowLight, options?: GaussianSplatShadowOptions): GaussianSplatShadowCaster | null; /** Remove this Gaussian scene from one light's shadow pass. */ removeShadowLight(light: GaussianSplatShadowLight): void; /** Request fresh shadow maps for all registered Gaussian shadow lights. */ invalidateShadows(): void; /** Rebuild Gaussian shadow materials after changing custom position, scale, or color hooks. */ refreshShadowLights(): void; /** * Read current GPU-visible renderer statistics asynchronously. * Intended for diagnostics and occasional performance checks, not per-frame application logic. * * @returns {Promise} Current renderer statistics. */ readStats(): Promise; /** * Estimate allocated GPU bytes from CPU-side buffer arrays. * @private * @returns {number} Estimated allocated byte count. */ _estimateGPUBytes(): number; /** * Read back indirect draw arguments from GPU (debug/stats). * * @returns {Promise} Array of 5 values: [indexCount, instanceCount, firstIndex, baseVertex, firstInstance], or null if not ready. */ readIndirectArgs(): Promise; /** * Rebuild the color resolver against the CURRENT material and reconcile the material's * vertex-path choice with the outcome. Record mode (F1) requires the resolver-written * color record and the record vertex path to activate together — any rebuild that flips * one side must flip the other, or record-path splats read a record nobody writes. */ _rebuildColorResolver(): void; /** * Rebuild projection and renderer nodes after changing custom material hooks. */ rebuildMaterialHooks(): void; /** * Get whether spherical harmonics are enabled. * @type {boolean} */ get enableSH(): boolean; /** * Set whether spherical harmonics are enabled. * Triggers compute shader rebuild when changed. * @param {boolean} value - Enable or disable SH. */ set enableSH(value: boolean); /** * Get the current spherical harmonics degree. * @type {number} */ get shDegree(): number; /** * Set the spherical harmonics degree (0-3). * Clamped to the maximum degree available from loaded data. * Triggers compute shader rebuild when changed. * @param {number} value - SH degree (0 = DC only, 1-3 = higher order harmonics). */ set shDegree(value: number); /** * Get the maximum SH degree available from loaded data. * @type {number} * @readonly */ get maxDataSHDegree(): number; /** * Get the maximum Gaussian extent in standard deviations. * @type {number} */ get maxStdDev(): number; /** @type {'straight'|'premultiplied'} */ get alphaMode(): GaussianSplatsAlphaMode; /** Set matching raster and compute-tile alpha semantics. */ set alphaMode(value: GaussianSplatsAlphaMode); /** * Set the maximum Gaussian extent in standard deviations. * Reduce from Math.sqrt(8) toward Math.sqrt(5) to trade fringe overdraw for speed. * @param {number} value - Non-negative standard-deviation extent. */ set maxStdDev(value: number); /** * Get the compensated screen-space filter variance. * @type {number} */ get blurAmount(): number; /** * Set the compensated screen-space filter variance. * Use 0.3 for the default Mip-style antialias filter or 0 to disable it. * @param {number} value - Non-negative screen-space covariance variance. */ set blurAmount(value: number); /** * Get the uncompensated pre-blur variance. * @type {number} */ get preBlurAmount(): number; /** * Set the uncompensated pre-blur variance. * Use this only for scenes trained without antialiasing. * @param {number} value - Non-negative screen-space covariance variance. */ set preBlurAmount(value: number); /** * Get the compute-level projected radius clipping threshold. * @type {number} */ get radiusClip(): number; /** * Skip splats at or below a projected pixel radius before sorting. * Keep this at 0 for maximum fidelity; raise it for large-scene performance tuning. * @param {number} value - Non-negative radius threshold in pixels. */ set radiusClip(value: number); /** @type {number} */ get alphaClip(): number; /** Reject source splats below this base opacity before covariance projection. */ set alphaClip(value: number); /** @type {number} */ get minContribution(): number; /** Reject projected splats below this alpha-area contribution estimate. Zero disables rejection. */ set minContribution(value: number); /** @type {boolean} */ get opacityAwareRadius(): boolean; /** Tighten projected raster footprints from opacity and the fragment cutoff. */ set opacityAwareRadius(value: boolean); /** @type {number} */ get fragmentAlphaClip(): number; /** Set the raster fragment cutoff used by both projection tightening and material alpha testing. */ set fragmentAlphaClip(value: number); /** * Read back sorted data from GPU for debugging. * @param {WebGPURenderer} renderer - The WebGPU renderer. * @returns {Promise<{keys: Uint32Array, indices: Uint32Array}>} Sorted keys and indices buffers. */ readback(renderer: THREE.Renderer): Promise; /** * Attach GUI controls. * * @param {Object} folder GUI folder instance. */ attachGUI(folder: GaussianGUIFolder): void; /** * Dispose of GPU resources. */ dispose(): void; } export { GaussianSplats as SplatMesh };