import type { ComputeNode, StorageBufferNode } from 'three/webgpu'; import type { TSLUintNode, TSLVec3Node } from '../types/tsl.js'; /** Shared spherical-harmonics palette payload used by SOG assets. */ export interface SOGSplatSHData { labels: Uint32Array; palette: Float32Array; } /** Loader payload fields consumed by the SH resource factory. */ export interface SplatSHResourceData { shCoefficients?: Float32Array | null; /** Packed half-float SH: two uint32 (four halves: r, g, b, pad) per coefficient, splat-major. */ shCoefficientsHalf?: Uint32Array | null; /** Output→source permutation applied to shCoefficientsHalf by a one-shot GPU scatter. */ shPermutation?: Uint32Array | null; sogSH?: SOGSplatSHData | null; } /** Storage selection and allocation fields shared by enabled and disabled SH resources. */ export interface SplatSHResourceAllocationOptions { attributeMode?: 'expanded' | 'compact' | 'sog' | 'auto'; capacity?: number; } /** Storage options, requiring a coefficient count whenever SH is enabled. */ export type SplatSHResourceOptions = SplatSHResourceAllocationOptions & ({ enableSH: true; coefficientCount: number; } | { enableSH?: false; coefficientCount?: number; }); /** TSL coefficient reader shared by expanded and palette-backed SH storage. */ export interface SplatSHReadNodes { readCoefficient: (splatIndex: TSLUintNode, coefficientIndex: number) => TSLVec3Node; } /** GPU allocation returned by expanded SH storage. */ export interface ExpandedSplatSHGPUResources { shCoefficients: StorageBufferNode<'vec4'>; } /** GPU allocations returned by SOG palette SH storage. */ export interface SOGPaletteSplatSHGPUResources { shLabels: StorageBufferNode<'uint'>; shPalette: StorageBufferNode<'vec4'>; } declare class ExpandedSplatSHResource { readonly mode: "expanded"; readonly count: number; readonly capacity: number; readonly coefficientCount: number; readonly coefficients: Float32Array; readonly cpuBytes: number; readonly gpuBytes: number; constructor(data: SplatSHResourceData & { shCoefficients: Float32Array; }, count: number, coefficientCount: number, capacity?: number); createGPUResources(): ExpandedSplatSHGPUResources; upload(buffers: ExpandedSplatSHGPUResources): void; buildReadNodes(buffers: ExpandedSplatSHGPUResources): SplatSHReadNodes; } declare class SOGPaletteSplatSHResource { readonly mode: "sog-palette"; readonly count: number; readonly capacity: number; readonly coefficientCount: number; readonly labels: Uint32Array; readonly palette: Float32Array; readonly cpuBytes: number; readonly gpuBytes: number; constructor(data: SplatSHResourceData & { sogSH: SOGSplatSHData; }, count: number, coefficientCount: number, capacity?: number); createGPUResources(): SOGPaletteSplatSHGPUResources; upload(buffers: SOGPaletteSplatSHGPUResources): void; buildReadNodes(buffers: SOGPaletteSplatSHGPUResources): SplatSHReadNodes; } /** GPU allocation returned by packed half-float SH storage. */ export interface PackedHalfSplatSHGPUResources { shCoefficients: StorageBufferNode<'uint'>; /** File-order staging released after the one-shot GPU scatter (permutation loads only). */ shCoefficientsStaging?: StorageBufferNode<'uvec2'>; /** Output→source scatter map released with the staging buffer. */ shScatterMap?: StorageBufferNode<'uint'>; } /** * Packed half-float SH storage: RGB halves, with only the last splat word padded. * * Keeps every loader half-float bit while removing per-coefficient padding. The loader delivers * coefficients packed in FILE order; when a Morton permutation is present, a one-shot GPU * scatter reorders them into the final buffer (a CPU gather of the SH payload costs hundreds * of milliseconds at multi-million-splat sizes), after which the staging buffer is released. * Without a permutation upload repacks the same input on the CPU. */ declare class PackedHalfSplatSHResource { readonly mode: "expanded-half"; readonly count: number; readonly capacity: number; readonly coefficientCount: number; readonly wordsPerSplat: number; packed: Uint32Array | null; permutation: Uint32Array | null; readonly cpuBytes: number; readonly gpuBytes: number; constructor(data: SplatSHResourceData & { shCoefficientsHalf: Uint32Array; }, count: number, coefficientCount: number, capacity?: number); get needsScatter(): boolean; /** Drop CPU-side staging references once the GPU scatter has consumed them. */ releaseStagingData(): void; createGPUResources(): PackedHalfSplatSHGPUResources; upload(buffers: PackedHalfSplatSHGPUResources): void; /** * Build the one-shot compute pass scattering file-order coefficients into the packed * splat order. Dispatch once, then release the staging buffers. */ buildScatterCompute(buffers: PackedHalfSplatSHGPUResources): ComputeNode | null; buildReadNodes(buffers: PackedHalfSplatSHGPUResources): SplatSHReadNodes; } /** Concrete SH storage selected for one decoded splat payload. */ export type SplatSHResource = ExpandedSplatSHResource | PackedHalfSplatSHResource | SOGPaletteSplatSHResource; export declare function createSplatSHResource(data: SplatSHResourceData, count: number, options?: SplatSHResourceOptions): SplatSHResource | null; export { ExpandedSplatSHResource, PackedHalfSplatSHResource, SOGPaletteSplatSHResource };