/** * splat-render — native WebGPU Gaussian-splat render to verified pixels (render "Part 2"). * * The volumetric sibling of `character-render.ts` (Part 1, rasterized skinned mesh): packs raw * Gaussian splats into the sorter's `SplatRaw` layout, drives the existing Paper-grade * `GaussianSplatSorter` (depth-sort → EWA splat raster) on a live GPUDevice, and reads pixels * back. This is the photoreal "skin/mesh upgrade" route for a character — a splat cloud trained * from capture renders as the same entity the rasterized mesh represents. * * NO Three.js, NO R3F. Like character-render, this is BOTH a production render entry AND the * headless verification/fallback floor (G.GOLD.006): it runs under Dawn in CI and on a real * browser device identically. It reuses the sorter unchanged except for two additive seams * (`GaussianSplatSorter.fromDevice` + the `renderFormat` option) so the trained splat pipeline * is not forked. * * @module native-render/splat-render */ import { type CameraState } from '../gpu/GaussianSplatSorter'; import type { Gaussian3D } from '../gpu/GaussianTrainer3D'; import type { GaussianSplatData } from '../gpu/codecs/types'; import type { PixelGrid } from './gpu-verify'; /** A single Gaussian splat in world space (the high-level input to {@link packRawSplats}). */ export interface RawSplatInput { /** World-space center. */ position: [number, number, number]; /** LINEAR per-axis scale (already exponentiated from the trained log-scale). */ scale: [number, number, number]; /** Orientation quaternion in (w, x, y, z) order. */ rotation: [number, number, number, number]; /** RGBA in 0..1; `a` is opacity. */ color: [number, number, number, number]; } /** * Pack high-level splats into the GPU `SplatRaw` buffer layout the sorter's compress pass reads * (64 bytes / 16 floats per splat, vec3 fields followed by 4 bytes of std-layout padding): * pos@0 (+pad@3), scale@4 (+pad@7), rotation@8 (w,x,y,z), color@12 (rgba). * Returns an `ArrayBuffer`-backed Float32Array so it is a valid `writeBuffer` source. */ export declare function packRawSplats(splats: readonly RawSplatInput[]): Float32Array; /** * Adapt the trainer / PLY-loader `Gaussian3D` SoA buffers (the `loadGaussianPly` output, the * decode proven correct against real captures) into render-input splats. `Gaussian3D` already * uses this pipeline's conventions: LINEAR scale, `(w,x,y,z)` quaternion, `[0,1]` color+opacity — * so this is a straight per-splat gather, no convention conversion. */ export declare function gaussian3DToSplats(g: Gaussian3D): RawSplatInput[]; /** * Adapt the codec interchange format (`GaussianSplatData` — the `GltfGaussianSplatCodec` / * KHR_gaussian_splatting / SPZ decode target) into render-input splats. Two conventions differ * from this pipeline and are converted here: codec rotations are `(x,y,z,w)` → reordered to * `(w,x,y,z)`, and opacity is the dedicated `opacities[i]` (used as the splat's alpha). Scales are * already LINEAR (the codec exponentiates KHR log-space scales on decode). */ export declare function gaussianSplatDataToSplats(d: GaussianSplatData): RawSplatInput[]; /** * Default headless camera that frames splats placed at positive camera-space Z. The splat * pipeline treats `depth = (view·pos).z` and culls `depth < 0.01` to the back, so the view is * identity (camera at the origin looking down +Z) and the projection is a +Z-forward perspective * (`clip.w = z_eye`). Square `size`, `fovYDeg` vertical FoV. focalX/Y are derived so the compress * pass recovers the same FoV (`tanFov = 0.5·dim / focal`). */ export declare function defaultSplatCamera(size: number, fovYDeg?: number): CameraState; export interface SplatRenderOptions { /** Square framebuffer edge (default 128 → bytesPerRow 512, 256-aligned). */ size?: number; /** Camera override; defaults to {@link defaultSplatCamera}. */ camera?: CameraState; /** Clear RGBA, 0..1 (default opaque black). */ clear?: [number, number, number, number]; /** Vertical FoV in degrees for the default camera (ignored when `camera` is given). */ fovYDeg?: number; } /** * Render depth-sorted Gaussian splats to an offscreen rgba8unorm texture and read the pixels * back. Builds a `GaussianSplatSorter` over the given device (`fromDevice`, `renderFormat` * matched to the readback texture), uploads the packed splats, runs the full sort+raster frame, * then copies the color attachment to a mappable buffer. */ export declare function renderSplats(device: GPUDevice, splats: readonly RawSplatInput[], opts?: SplatRenderOptions): Promise; //# sourceMappingURL=splat-render.d.ts.map