@voluma/vlam 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/compute-sorter.d.ts +7 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/radix-sorter.d.ts +6 -0
- package/dist/core/sort-worker-protocol.d.ts +2 -0
- package/dist/core/sorter.d.ts +4 -4
- package/dist/core/splat-mesh-types.d.ts +22 -5
- package/dist/core/splat-mesh.d.ts +11 -2
- package/dist/core/splat-sort-bounds.d.ts +17 -0
- package/dist/core/worker-sorter.d.ts +7 -5
- package/dist/index.js +3 -3
- package/dist/radix-sorter-tSffmerk.js +181 -0
- package/dist/radix-sorter-tSffmerk.js.map +1 -0
- package/dist/relighting-qaANKC4Z.js +997 -0
- package/dist/relighting-qaANKC4Z.js.map +1 -0
- package/dist/{splat-mesh-CsLOQb08.js → splat-mesh-B1KlWHvx.js} +545 -513
- package/dist/splat-mesh-B1KlWHvx.js.map +1 -0
- package/dist/splat-mesh-types-BZIko-_9.js.map +1 -1
- package/dist/static-lod.js +1 -1
- package/dist/streaming.js +17 -17
- package/dist/unified.js +17 -17
- package/package.json +1 -1
- package/dist/radix-sorter-BrbUg_CV.js +0 -178
- package/dist/radix-sorter-BrbUg_CV.js.map +0 -1
- package/dist/relighting-Tiwep8yd.js +0 -977
- package/dist/relighting-Tiwep8yd.js.map +0 -1
- package/dist/splat-mesh-CsLOQb08.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splat-mesh-B1KlWHvx.js","sources":["../src/lib/core/orientation.ts","../src/lib/core/worker-sorter.ts","../src/lib/core/splat-depth-pack.ts","../src/lib/core/splat-mesh-picking.ts","../src/lib/core/splat-query.ts","../src/lib/core/splat-mesh.ts"],"sourcesContent":["import * as THREE from 'three/webgpu';\n\n/**\n * How a loaded capture is oriented into the three.js Y-up world.\n *\n * - `'y-up'` (default): VLAM normalizes every known format to three.js Y-up -\n * the OpenCV-frame formats (PLY/`.splat`/`.ksplat`/SOG/`.rad`) are flipped\n * 180° about X, SPZ is already Y-up, and LCC carries its own Z-up→Y-up matrix.\n * \"Drop a file and it stands up\", matching engine viewers (PlayCanvas, Babylon).\n * - `'source'`: keep the native/source coordinate frame. No cosmetic 180°-X flip.\n * An application that manages orientation itself (for example swapping viewers\n * while keeping one stored per-capture rotation) uses this.\n *\n * LCC's Z-up→Y-up matrix is format semantics, not a cosmetic default: it is\n * applied in **both** modes (Spark applies it too). Only the 180°-X flip for\n * the Y-down formats is gated by this option.\n */\nexport type SplatOrientation = 'y-up' | 'source';\n\n/**\n * Formats {@link yUpTransformForFormat} understands: the self-contained scene\n * formats ({@link SplatData.format}) plus the streamed ones.\n */\nexport type OrientableFormat =\n 'ply' | 'splat' | 'ksplat' | 'sog' | 'spz' | 'rad' | 'streamed-sog' | 'lcc' | 'lcc2';\n\n/**\n * The 180°-about-X rotation that maps a 3DGS Y-down capture to three.js Y-up -\n * the same correction Spark documents as `quaternion.set(1, 0, 0, 0)`. Returned\n * as a fresh {@link THREE.Matrix4} so callers can mutate/decompose it freely.\n */\nexport function createYUpTransform(): THREE.Matrix4 {\n return new THREE.Matrix4().makeRotationX(Math.PI);\n}\n\n/**\n * The `'y-up'` correction for a format, or `null` when nothing is needed:\n * SPZ is already Y-up, and LCC self-orients via its `formatTransform`\n * (callers apply that in both modes, so this returns `null` for LCC to avoid\n * doubling it). Y-down formats (PLY/`.splat`/`.ksplat`/SOG) get the 180°-X flip.\n */\nexport function yUpTransformForFormat(format: OrientableFormat | undefined): THREE.Matrix4 | null {\n switch (format) {\n case 'ply':\n case 'splat':\n case 'ksplat':\n case 'sog':\n case 'rad':\n case 'streamed-sog':\n return createYUpTransform();\n case 'spz':\n case 'lcc':\n case 'lcc2':\n case undefined:\n return null;\n }\n}\n","import type * as THREE from 'three/webgpu';\nimport type { SplatSorter } from './sorter';\nimport type { SplatSortMetric } from './splat-mesh-types';\nimport type { SortWorkerRequest, OrderMessage } from './sort-worker-protocol';\n// Inlined worker (blob URL): survives library bundling in any consumer\n// setup, unlike an asset file referenced via `new URL(...)`.\nimport SortWorker from './sort-worker?worker&inline';\nimport { logError } from './logging';\n\n/**\n * Stable CPU radix sorter in a Web Worker. Used by the WebGL2 fallback and,\n * when explicitly selected, alongside WebGPU rendering for Spark-like sort\n * cadence. Works for static and dynamic-capacity meshes alike: the worker\n * keeps a mirror of the pool's centers and sorts only the active spans.\n *\n * One sort runs at a time; requests that arrive while the worker is busy\n * are declined so the caller retries with the then-current camera on a\n * later frame.\n */\nexport class WorkerSorter implements SplatSorter {\n readonly kind = 'worker' as const;\n private readonly worker: Worker;\n private readonly splatIndexAttribute: THREE.InstancedBufferAttribute;\n private readonly host: WorkerSorterHost;\n private readonly sortMetric: SplatSortMetric;\n private inFlight = false;\n /** Set by {@link dispose}; drops any already-delivered order message. */\n private disposed = false;\n /** The active spans the in-flight sort was computed against. */\n private sentSpans: Uint32Array | null = null;\n private submittedCount = 0;\n private completedCount = 0;\n private lastSubmittedAt = -Infinity;\n private lastCompletedAt = -Infinity;\n private lastLatencyMs = Number.NaN;\n\n constructor(host: WorkerSorterHost, sortMetric: SplatSortMetric = 'depth') {\n this.host = host;\n this.sortMetric = sortMetric;\n this.splatIndexAttribute = host.splatIndexAttribute;\n this.worker = new SortWorker();\n this.worker.onmessage = (event: MessageEvent<OrderMessage>) => {\n this.applyOrder(event.data.order);\n };\n // Without these, one worker-side exception would leave `inFlight` stuck\n // true and silently freeze depth ordering for the rest of the session.\n this.worker.onerror = (event: ErrorEvent) => {\n logError('sort worker error - retrying on a later frame.', event.message);\n this.inFlight = false;\n };\n this.worker.onmessageerror = () => {\n logError('sort worker message deserialization failed.');\n this.inFlight = false;\n };\n const init: SortWorkerRequest = { type: 'init', capacity: host.capacity };\n this.worker.postMessage(init);\n // Everything written so far is one dirty span from the mirror's view.\n this.pushCenters([{ start: 0, count: Math.ceil(host.capacity / host.rowWidth) }]);\n }\n\n sort(modelView: THREE.Matrix4, _activeCount: number, _bounds: THREE.Sphere): boolean {\n if (this.disposed || this.inFlight) return false;\n this.inFlight = true;\n this.submittedCount++;\n this.lastSubmittedAt = performance.now();\n\n this.pushCenters(this.host.takeDirtyRows());\n const spans = this.host.getActiveSpans();\n this.sentSpans = spans;\n const message: SortWorkerRequest = {\n type: 'sort',\n sortMetric: this.sortMetric,\n modelView: new Float32Array(modelView.elements),\n spans,\n matrices: this.host.perSource ? new Float32Array(this.host.perSource.matrices) : undefined,\n };\n this.worker.postMessage(message);\n return true;\n }\n\n /** Internal timing diagnostics used by the demo's opt-in XR A/B harness. */\n snapshot(): {\n submittedCount: number;\n completedCount: number;\n lastSubmittedAt: number;\n lastCompletedAt: number;\n lastLatencyMs: number;\n } {\n return {\n submittedCount: this.submittedCount,\n completedCount: this.completedCount,\n lastSubmittedAt: this.lastSubmittedAt,\n lastCompletedAt: this.lastCompletedAt,\n lastLatencyMs: this.lastLatencyMs,\n };\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.worker.terminate();\n }\n\n /** Sends written pool rows to keep the worker's centers mirror current. */\n private pushCenters(rows: readonly { start: number; count: number }[]): void {\n const width = this.host.rowWidth;\n for (const row of rows) {\n const centers = this.host.centers.slice(\n row.start * width * 4,\n (row.start + row.count) * width * 4,\n );\n const start = row.start * width;\n const count = row.count * width;\n const sourceIds = this.host.perSource?.sourceIds.slice(start, start + count);\n const message: SortWorkerRequest = { type: 'write', start, centers, sourceIds };\n this.worker.postMessage(message, [centers.buffer]);\n }\n }\n\n private applyOrder(order: Uint32Array): void {\n this.inFlight = false;\n this.completedCount++;\n this.lastCompletedAt = performance.now();\n this.lastLatencyMs = this.lastCompletedAt - this.lastSubmittedAt;\n // An order event already dispatched when dispose ran still lands here;\n // writing it would flag a post-dispose GPU upload on the dead draw list.\n if (this.disposed) return;\n // A reply computed against an outdated active set must not overwrite the\n // identity draw list `rebuildActiveList` wrote for the new one - it would\n // resurrect the pool slots of a just-removed range for several frames.\n // The caller's forced re-sort delivers a fresh order right after.\n const current = this.host.getActiveSpans();\n const sent = this.sentSpans;\n this.sentSpans = null;\n if (!sent || sent.length !== current.length) return;\n for (let i = 0; i < sent.length; i++) {\n if (sent[i] !== current[i]) return;\n }\n const indexes = this.splatIndexAttribute.array as Float32Array;\n for (let i = 0; i < order.length; i++) {\n indexes[i] = order[i] as number;\n }\n // An explicit update range covering the whole order: if the attribute\n // already carries narrow ranges from an active-list patch this frame, a\n // bare `needsUpdate` would upload only those slots and clip the new\n // permutation to a fragment - draw-list garbage until the next sort.\n this.splatIndexAttribute.addUpdateRange(0, order.length);\n this.splatIndexAttribute.needsUpdate = true;\n // The draw list now holds a depth permutation, not the identity active\n // order - the host must stop patching it incrementally (see\n // SplatMesh.commitActiveListMutation).\n this.host.onOrderApplied?.();\n }\n}\n\n/** What the sorter needs from its mesh; see SplatMesh.createSorter. */\nexport interface WorkerSorterHost {\n /** Pool capacity in splats. */\n readonly capacity: number;\n /** Splats per pool texture row. */\n readonly rowWidth: number;\n /** The pool's centers backing array (vec4 stride; xyz used). */\n readonly centers: Float32Array;\n /** Source metadata for a unified pool; omitted for a normal mesh. */\n readonly perSource?: {\n readonly sourceIds: Float32Array;\n readonly matrices: Float32Array;\n };\n readonly splatIndexAttribute: THREE.InstancedBufferAttribute;\n /** Drains the row spans written since the last call. */\n takeDirtyRows(): { start: number; count: number }[];\n /** Active ranges as (start, count) pool-index pairs, active-list order. */\n getActiveSpans(): Uint32Array;\n /**\n * Called after a worker order lands in the draw list, so the host knows the\n * list holds a sorted permutation (not identity active order) and must fully\n * resync - not patch - it on the next active-list mutation.\n */\n onOrderApplied?(): void;\n}\n","/**\n * 24-bit RGB packing for linear view-space depth used by GPU splat picking.\n *\n * Depth is stored as a normalized value in [0, 1] mapped across the camera\n * near/far range, then quantized into three 8-bit channels (R = high byte).\n * This matches an RGBA8 render target without a depth-texture readback path.\n */\nimport * as THREE from 'three/webgpu';\n\n/** Maximum integer representable in 24 bits. */\nconst DEPTH_24_MAX = (1 << 24) - 1;\n\nconst _ndc = new THREE.Vector2();\nconst _raycaster = new THREE.Raycaster();\nconst _dirView = new THREE.Vector3();\n\n/**\n * Packs a normalized depth in [0, 1] into 8-bit RGB (high → low).\n * Values outside [0, 1] are clamped.\n */\nexport function packNormalizedDepth(normalized: number): { r: number; g: number; b: number } {\n const t = Math.min(1, Math.max(0, normalized));\n const encoded = Math.round(t * DEPTH_24_MAX);\n return {\n r: (encoded >> 16) & 0xff,\n g: (encoded >> 8) & 0xff,\n b: encoded & 0xff,\n };\n}\n\n/**\n * Unpacks 8-bit RGB channels back to a normalized depth in [0, 1].\n */\nexport function unpackNormalizedDepth(r: number, g: number, b: number): number {\n const encoded = ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);\n return encoded / DEPTH_24_MAX;\n}\n\n/**\n * Maps a positive linear view-space depth (OpenGL: −z) into [0, 1] using the\n * camera near/far plane. Clamps to the range.\n */\nexport function normalizeViewDepth(viewDepth: number, near: number, far: number): number {\n if (!(far > near)) return 0;\n return Math.min(1, Math.max(0, (viewDepth - near) / (far - near)));\n}\n\n/**\n * Inverse of {@link normalizeViewDepth}.\n */\nexport function denormalizeViewDepth(normalized: number, near: number, far: number): number {\n return near + normalized * (far - near);\n}\n\n/**\n * Reconstructs a world-space hit from NDC and a positive view-space depth\n * (−z in OpenGL camera space). Writes into `outPoint` and returns camera\n * distance. The camera must have an up-to-date world matrix.\n */\nexport function unprojectViewDepth(\n ndcX: number,\n ndcY: number,\n viewDepth: number,\n camera: THREE.Camera,\n outPoint: THREE.Vector3,\n): { point: THREE.Vector3; distance: number } {\n _ndc.set(ndcX, ndcY);\n _raycaster.setFromCamera(_ndc, camera);\n // View-space Z of the hit is −viewDepth; scale the world ray so its view-Z\n // matches. Camera upper-3×3 is orthonormal (no non-uniform scale).\n _dirView.copy(_raycaster.ray.direction).transformDirection(camera.matrixWorldInverse);\n const t = viewDepth / -_dirView.z;\n outPoint.copy(_raycaster.ray.origin).addScaledVector(_raycaster.ray.direction, t);\n return { point: outPoint, distance: outPoint.distanceTo(_raycaster.ray.origin) };\n}\n","/**\n * GPU screen-space picking for `SplatMesh`.\n *\n * Picking renders the splats once more into a 1×1 target, with a\n * material that writes linear view depth instead of color; the depth comes back\n * through an async readback and unprojects to a world point. That needs a whole\n * subsystem of its own - a render target, a proxy mesh, a private scene, saved\n * renderer state - none of which the mesh itself ever touches, so it lives here\n * rather than as ten more fields on an already large class.\n *\n * The picker reaches back into the mesh through {@link SplatPickHost} rather\n * than holding the mesh itself: the four things it needs are otherwise private,\n * and widening them for the picker would put them in the published .d.ts.\n *\n * Internal. Nothing here is exported from `index.ts`.\n */\nimport * as THREE from 'three/webgpu';\nimport { uniform } from 'three/tsl';\nimport {\n denormalizeViewDepth,\n unpackNormalizedDepth,\n unprojectViewDepth,\n} from './splat-depth-pack';\nimport type { SplatPickOptions, SplatPickResult } from './splat-mesh';\nimport type { FloatUniform } from './splat-mesh-material';\nimport { isXrArrayCamera } from './xr-view';\n\n/** What the picker needs from the mesh it picks. */\nexport interface SplatPickHost {\n /** The mesh, for the transform/visibility the proxy mirrors and its geometry. */\n readonly mesh: THREE.Mesh;\n isDisposed(): boolean;\n getActiveCount(): number;\n /** The mesh's live viewport uniform value, in drawing-buffer pixels. */\n getViewportSize(): THREE.Vector2;\n /** Visibility as resolved by an owning unified renderer, when any. */\n getPickVisible(): boolean;\n /** Whether a sorter exists. A pick never creates one - see {@link prepare}. */\n hasSorter(): boolean;\n updateWorldMatrix(): void;\n /**\n * Brings the GPU to the state `update()` would leave it in: flush pending\n * uploads, refresh the projection uniforms, and refresh an existing sorter's\n * draw list. Ordering matters, so the mesh owns it.\n */\n prepare(camera: THREE.Camera, renderer: THREE.WebGPURenderer): void;\n /**\n * Writes focal / viewport / local-camera uniforms for a camera drawing into\n * a viewport of `width`×`height` pixels. The pick pass crops the frustum to\n * one source pixel and renders into a 1×1 target, so it must rewrite these\n * after the crop and restore the canvas-sized values before returning.\n */\n setView(camera: THREE.Camera, width: number, height: number): void;\n /** Builds the pick-mode TSL graph onto a freshly created material. */\n applyPickGraph(material: THREE.NodeMaterial): void;\n}\n\n/**\n * Owns the pick pass and everything it allocates. Resources are created on the\n * first pick, so a mesh that is never picked pays nothing.\n */\nexport class SplatPicker {\n /** Alpha below which a splat is transparent enough to pick through. */\n private readonly alphaThreshold = uniform(0.1);\n /** Camera planes for the pick material's depth encoding. */\n private readonly near = uniform(0.1);\n private readonly far = uniform(1000);\n private material: THREE.NodeMaterial | null = null;\n private proxy: THREE.Mesh | null = null;\n private target: THREE.RenderTarget | null = null;\n /** Reused sub-frustum camera; preserves the caller's concrete camera type. */\n private pickCamera: THREE.Camera | null = null;\n private readonly scene = new THREE.Scene();\n /** Serializes picks: they share one render target and one renderer. */\n private queue: Promise<unknown> = Promise.resolve();\n private readonly point = new THREE.Vector3();\n private readonly savedClearColor = new THREE.Color();\n\n constructor(private readonly host: SplatPickHost) {}\n\n /** The pick uniforms the material graph binds. */\n get uniforms(): { alphaThreshold: FloatUniform; near: FloatUniform; far: FloatUniform } {\n return { alphaThreshold: this.alphaThreshold, near: this.near, far: this.far };\n }\n\n pick(\n ndc: THREE.Vector2,\n camera: THREE.Camera,\n renderer: THREE.WebGPURenderer,\n options?: SplatPickOptions,\n ): Promise<SplatPickResult | null> {\n const run = this.queue.then(() => this.run(ndc, camera, renderer, options));\n // Keep the queue alive even when a pick rejects, so later calls still run.\n this.queue = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n\n /** Rebuilds the pick graph after a settings change. No-op before the first pick. */\n rebuildMaterial(): void {\n if (!this.material) return;\n this.host.applyPickGraph(this.material);\n }\n\n /** Flags the pick graph for recompile (e.g. the modifier list changed). */\n markNeedsUpdate(): void {\n if (this.material) this.material.needsUpdate = true;\n }\n\n dispose(): void {\n this.material?.dispose();\n this.material = null;\n this.scene.clear();\n this.proxy = null;\n this.target?.dispose();\n this.target = null;\n this.pickCamera = null;\n }\n\n private async run(\n ndc: THREE.Vector2,\n camera: THREE.Camera,\n renderer: THREE.WebGPURenderer,\n options?: SplatPickOptions,\n ): Promise<SplatPickResult | null> {\n if (this.host.isDisposed()) return null;\n if (this.host.getActiveCount() === 0) return null;\n if (ndc.x < -1 || ndc.x > 1 || ndc.y < -1 || ndc.y > 1) return null;\n // An XR array camera has no single frustum: no `near`/`far` to unproject\n // the encoded depth through (the fallbacks below would silently substitute\n // 0.1/1000 and return a plausible-looking but wrong world point), and the\n // pass would rasterize stereo into a mono target. Fail loudly instead.\n if (isXrArrayCamera(camera)) {\n throw new Error(\n 'SplatMesh.pick: an XR array camera has no single frustum to pick through. ' +\n 'Pass one eye (renderer.xr.getCamera().cameras[i]) or a mono camera, and ' +\n 'give `ndc` in that eye’s viewport.',\n );\n }\n\n camera.updateMatrixWorld(true);\n this.host.updateWorldMatrix();\n // Match the state `update()` establishes: appended-but-unflushed rows must\n // reach the GPU, and an existing sorter's draw list must be refreshed for\n // the current active set - or the pick pass rasterizes stale pool data\n // (garbage centers, or \"ghost\" splats from a just-removed range still in\n // the GPU-sorted order). The pick pass itself is depth-tested, so it does\n // not need a *sorted* order - only a valid one - hence no sorter is\n // created here when none exists yet (the identity draw list is valid).\n this.host.prepare(camera, renderer);\n\n const width = Math.max(1, Math.floor(this.host.getViewportSize().x));\n const height = Math.max(1, Math.floor(this.host.getViewportSize().y));\n const px = Math.floor((ndc.x * 0.5 + 0.5) * width);\n // NDC +y is up, so this row index is measured from the BOTTOM edge.\n const pyBottom = Math.floor((ndc.y * 0.5 + 0.5) * height);\n if (px < 0 || pyBottom < 0 || px >= width || pyBottom >= height) return null;\n this.ensureResources(camera);\n const pickTarget = this.target!;\n const pickProxy = this.proxy!;\n const pickCamera = this.pickCamera!;\n this.cropCameraToPixel(pickCamera, camera, width, height, px, pyBottom);\n // The crop maps one source pixel onto NDC [-1, 1]. Quad extent is\n // `pixelOffset * 2 / viewport`, so viewport must be the 1×1 pick target\n // or a splat tens of pixels wide shrinks to a sliver that never covers\n // the clicked pixel. Focal follows the cropped projection at this size\n // and matches the canvas-pixel covariance the display pass used.\n this.host.setView(pickCamera, 1, 1);\n\n const near = 'near' in camera && typeof camera.near === 'number' ? camera.near : 0.1;\n const far = 'far' in camera && typeof camera.far === 'number' ? camera.far : 1000;\n this.near.value = near;\n this.far.value = far;\n this.alphaThreshold.value =\n options?.alphaThreshold !== undefined ? options.alphaThreshold : 0.1;\n\n const mesh = this.host.mesh;\n const previousTarget = renderer.getRenderTarget();\n const previousScissorTest = renderer.getScissorTest();\n renderer.getClearColor(this.savedClearColor);\n const previousClearAlpha = renderer.getClearAlpha();\n const previousAutoClear = renderer.autoClear;\n\n pickProxy.matrix.copy(mesh.matrixWorld);\n pickProxy.matrixWorld.copy(mesh.matrixWorld);\n pickProxy.visible = this.host.getPickVisible();\n pickProxy.layers.mask = mesh.layers.mask;\n pickProxy.renderOrder = mesh.renderOrder;\n pickTarget.viewport.set(0, 0, 1, 1);\n pickTarget.scissor.set(0, 0, 1, 1);\n\n // Start readback while the target is bound, but restore shared renderer\n // state synchronously. Awaiting while mutated would corrupt normal frames.\n const readback = (() => {\n try {\n renderer.setRenderTarget(pickTarget);\n renderer.setScissorTest(false);\n renderer.setClearColor(0x000000, 0);\n renderer.autoClear = true;\n renderer.clear();\n\n renderer.setScissorTest(true);\n renderer.autoClear = false;\n renderer.render(this.scene, pickCamera);\n return renderer.readRenderTargetPixelsAsync(pickTarget, 0, 0, 1, 1);\n } finally {\n this.host.setView(camera, width, height);\n renderer.setRenderTarget(previousTarget);\n renderer.setScissorTest(previousScissorTest);\n renderer.setClearColor(this.savedClearColor, previousClearAlpha);\n renderer.autoClear = previousAutoClear;\n }\n })();\n\n let rgba: Uint8Array | Uint8ClampedArray | Float32Array;\n try {\n rgba = (await readback) as Uint8Array;\n } catch (error) {\n // A dispose while the readback was in flight tears down the render\n // target the GPU was copying from; the readback rejection is then an\n // expected consequence of dispose, not a pick failure - resolve as a\n // clean miss so hosts never need a try/catch around a cursor pick.\n if (this.host.isDisposed()) return null;\n throw error;\n }\n if (this.host.isDisposed()) return null;\n\n const r = rgba[0] as number;\n const g = rgba[1] as number;\n const b = rgba[2] as number;\n const a = rgba[3] as number;\n if (a === 0) return null;\n\n const viewDepth = denormalizeViewDepth(unpackNormalizedDepth(r, g, b), near, far);\n const { point, distance } = unprojectViewDepth(ndc.x, ndc.y, viewDepth, camera, this.point);\n return { point: point.clone(), distance };\n }\n\n private ensureResources(camera: THREE.Camera): void {\n if (this.target === null) {\n this.target = new THREE.RenderTarget(1, 1, {\n format: THREE.RGBAFormat,\n type: THREE.UnsignedByteType,\n depthBuffer: true,\n stencilBuffer: false,\n });\n }\n if (this.material === null) {\n this.material = new THREE.NodeMaterial();\n this.host.applyPickGraph(this.material);\n this.proxy = new THREE.Mesh(this.host.mesh.geometry, this.material);\n this.proxy.matrixAutoUpdate = false;\n this.proxy.frustumCulled = false;\n this.scene.add(this.proxy);\n }\n if (this.pickCamera === null || this.pickCamera.constructor !== camera.constructor) {\n this.pickCamera = camera.clone();\n }\n }\n\n /** Maps one original framebuffer pixel onto the complete 1×1 pick target. */\n private cropCameraToPixel(\n target: THREE.Camera,\n source: THREE.Camera,\n width: number,\n height: number,\n px: number,\n pyBottom: number,\n ): void {\n // The concrete subclasses have compatible `copy` overrides; ensureResources\n // keeps source and target constructors equal before this call.\n target.copy(source);\n const projection = target.projectionMatrix;\n const elements = projection.elements;\n const xOffset = 2 * px + 1 - width;\n const yOffset = 2 * pyBottom + 1 - height;\n for (let column = 0; column < 4; column++) {\n const rowW = elements[column * 4 + 3] as number;\n elements[column * 4] = (elements[column * 4] as number) * width - xOffset * rowW;\n elements[column * 4 + 1] = (elements[column * 4 + 1] as number) * height - yOffset * rowW;\n }\n target.projectionMatrixInverse.copy(projection).invert();\n }\n}\n","/**\n * A lazily built uniform spatial grid over splat centers, for the CPU spatial\n * queries `SplatMesh` exposes (M9). Pure array math - no THREE, no GPU - over\n * the pool's CPU-side centers, so it is cheap to build and to test.\n *\n * The grid indexes a set of *pool indices* into a shared centers array (the\n * pool's `backing.centers`, RGBA-strided: splat `p`'s center is\n * `centers[p*4 + 0..2]`). Only the indices handed in are indexed, so a static\n * mesh grids its whole scene and a streamed mesh grids exactly its resident\n * splats. Everything is in the mesh's **local** space; the caller converts\n * world queries in and results out.\n */\n\n/** Largest per-axis cell count, to bound the cell-start array's size. */\nconst MAX_DIM = 1024;\n/** Largest total cell count; above this the grid coarsens rather than allocate. */\nconst MAX_CELLS = 1 << 21;\n\nexport class UniformGrid {\n /** Populated-region minimum corner (local space). */\n private readonly min = new Float64Array(3);\n /** Per-axis cell size (local units). */\n private readonly cellSize = new Float64Array(3);\n /** Per-axis cell counts. */\n private readonly dims = new Int32Array(3);\n /** CSR cell offsets: cell c owns `items[start[c] .. start[c+1])`. */\n private readonly cellStart: Int32Array;\n /** Pool indices, bucketed by cell. */\n private readonly items: Uint32Array;\n /** Pool centers array this grid points into (RGBA stride 4). */\n private readonly centers: Float32Array;\n\n readonly count: number;\n\n /**\n * @param centers - The pool's CPU centers (stride 4: x,y,z,_ per splat).\n * @param poolIndices - The pool indices to index (e.g. the active list).\n * @param count - How many entries of `poolIndices` are valid.\n */\n constructor(centers: Float32Array, poolIndices: Uint32Array, count: number) {\n this.centers = centers;\n this.count = count;\n if (count === 0) {\n this.dims.set([1, 1, 1]);\n this.cellSize.set([1, 1, 1]);\n this.cellStart = new Int32Array(2);\n this.items = new Uint32Array(0);\n return;\n }\n\n // 1. Bounds of the populated region.\n const lo = [Infinity, Infinity, Infinity];\n const hi = [-Infinity, -Infinity, -Infinity];\n for (let i = 0; i < count; i++) {\n const base = (poolIndices[i] as number) * 4;\n for (let a = 0; a < 3; a++) {\n const v = centers[base + a] as number;\n if (v < (lo[a] as number)) lo[a] = v;\n if (v > (hi[a] as number)) hi[a] = v;\n }\n }\n\n // 2. Cell sizing. Target ~one splat per cell using only the populated\n // dimensions, so a planar or linear scene still resolves well.\n const size = [\n (hi[0] as number) - (lo[0] as number),\n (hi[1] as number) - (lo[1] as number),\n (hi[2] as number) - (lo[2] as number),\n ];\n const nonZero = size.filter((s) => s > 0);\n const spanProduct = nonZero.reduce((a, b) => a * b, 1);\n let cell = nonZero.length > 0 ? Math.pow(spanProduct / count, 1 / nonZero.length) : 1;\n if (!(cell > 0) || !Number.isFinite(cell)) cell = 1;\n\n const chooseDims = (cellEdge: number): void => {\n for (let a = 0; a < 3; a++) {\n const s = size[a] as number;\n this.dims[a] = s > 0 ? Math.max(1, Math.min(MAX_DIM, Math.round(s / cellEdge) || 1)) : 1;\n // A cell must span the whole axis when there is only one of them, so a\n // point exactly at the max corner still lands in-range.\n this.cellSize[a] = (this.dims[a] as number) > 0 ? s / (this.dims[a] as number) || 1 : 1;\n this.min[a] = lo[a] as number;\n }\n };\n chooseDims(cell);\n // Coarsen until the cell array fits the cap (huge, near-degenerate scenes).\n while (this.dims[0]! * this.dims[1]! * this.dims[2]! > MAX_CELLS) {\n cell *= 1.5;\n chooseDims(cell);\n }\n\n const cellCount = this.dims[0]! * this.dims[1]! * this.dims[2]!;\n // 3. Counting sort into CSR.\n const counts = new Int32Array(cellCount + 1);\n for (let i = 0; i < count; i++) counts[this.cellOf(poolIndices[i] as number) + 1]!++;\n for (let c = 0; c < cellCount; c++) counts[c + 1]! += counts[c]!;\n this.cellStart = counts;\n this.items = new Uint32Array(count);\n const cursor = Int32Array.from(counts.subarray(0, cellCount));\n for (let i = 0; i < count; i++) {\n const p = poolIndices[i] as number;\n this.items[cursor[this.cellOf(p)]!++] = p;\n }\n }\n\n /** The cell index of pool splat `p`, clamped into range. */\n private cellOf(p: number): number {\n const base = p * 4;\n const ix = this.axisCell(0, this.centers[base] as number);\n const iy = this.axisCell(1, this.centers[base + 1] as number);\n const iz = this.axisCell(2, this.centers[base + 2] as number);\n return (iz * (this.dims[1] as number) + iy) * (this.dims[0] as number) + ix;\n }\n\n private axisCell(a: number, value: number): number {\n const i = Math.floor((value - (this.min[a] as number)) / (this.cellSize[a] as number));\n return Math.max(0, Math.min((this.dims[a] as number) - 1, i));\n }\n\n /**\n * Visits every indexed splat within `radius` (local units) of the local\n * point, calling `visit(poolIndex, distanceSq)`. Cells are pruned by their\n * axis span and each candidate is distance-filtered here, so the callback\n * only ever sees splats truly within the radius.\n */\n forEachWithin(\n x: number,\n y: number,\n z: number,\n radius: number,\n visit: (poolIndex: number, distanceSq: number) => void,\n ): void {\n if (this.count === 0 || radius < 0) return;\n const r2 = radius * radius;\n const lo = [0, 0, 0];\n const hi = [0, 0, 0];\n const q = [x, y, z];\n for (let a = 0; a < 3; a++) {\n const span = Math.ceil(radius / (this.cellSize[a] as number));\n const c = this.axisCell(a, q[a] as number);\n lo[a] = Math.max(0, c - span);\n hi[a] = Math.min((this.dims[a] as number) - 1, c + span);\n }\n for (let iz = lo[2] as number; iz <= (hi[2] as number); iz++) {\n for (let iy = lo[1] as number; iy <= (hi[1] as number); iy++) {\n const rowBase = (iz * (this.dims[1] as number) + iy) * (this.dims[0] as number);\n const from = this.cellStart[rowBase + (lo[0] as number)] as number;\n const to = this.cellStart[rowBase + (hi[0] as number) + 1] as number;\n for (let k = from; k < to; k++) {\n const p = this.items[k] as number;\n const base = p * 4;\n const dx = (this.centers[base] as number) - x;\n const dy = (this.centers[base + 1] as number) - y;\n const dz = (this.centers[base + 2] as number) - z;\n const d2 = dx * dx + dy * dy + dz * dz;\n if (d2 <= r2) visit(p, d2);\n }\n }\n }\n }\n\n /**\n * The nearest indexed splat to the local point within `radius`, or null.\n * Returns its pool index and squared local distance.\n */\n nearest(\n x: number,\n y: number,\n z: number,\n radius: number,\n ): { poolIndex: number; distSq: number } | null {\n let bestIndex = -1;\n let bestSq = Infinity;\n this.forEachWithin(x, y, z, radius, (p, d2) => {\n if (d2 < bestSq) {\n bestSq = d2;\n bestIndex = p;\n }\n });\n return bestIndex < 0 ? null : { poolIndex: bestIndex, distSq: bestSq };\n }\n}\n","import {\n MAX_SH_BANDS,\n resolveSplatPerformanceProfile,\n type ProjectedFilterProfile,\n type SplatChannelOptions,\n type SplatChannelType,\n type SplatHeightResult,\n type SplatMeshOptions,\n type SplatNearestResult,\n type SplatPerformanceProfile,\n type SplatPickOptions,\n type SplatPickResult,\n type SplatRayResult,\n type SplatRange,\n type SplatSortStrategy,\n type SplatSortMetric,\n type SplatUpdateOptions,\n type UnifiedSourceView,\n resolveSplatFoveationMode,\n type SplatFoveationMode,\n} from './splat-mesh-types';\nexport * from './splat-mesh-types';\nimport * as THREE from 'three/webgpu';\nimport { uniform } from 'three/tsl';\nimport type { SplatData } from './splat-data';\nimport { type SplatOrientation, yUpTransformForFormat } from './orientation';\nimport type { SplatModifier } from './splat-modifier';\nimport type { SplatSorter } from './sorter';\nimport {\n ComputeSorter,\n releaseRendererAttributes,\n type PerSourceSortTransform,\n} from './compute-sorter';\nimport { WorkerSorter } from './worker-sorter';\nimport { WebGpuSortScheduler, validateSortIntervalMs } from './sort-scheduler';\nimport { detectSplatDeviceProfile } from './splat-budget';\nimport { encodeFloat32ToHalf } from './half-float';\nimport { SplatPicker } from './splat-mesh-picking';\nimport { clampDepthOfFieldSettings, type DepthOfFieldSettings } from './depth-of-field';\nimport {\n clampRelightingSettings,\n createPlaceholderRelightTexture,\n DEFAULT_RELIGHT_BACKGROUND,\n DEFAULT_RELIGHT_BRIGHTNESS,\n DEFAULT_RELIGHT_SOFTNESS,\n type RelightingSettings,\n type RelightingUniforms,\n} from './relighting';\nimport {\n applySplatMaterialGraph,\n shCoefficientCount,\n vec3Uniform,\n type SplatMaterialBuildInputs,\n type SplatMaterialTextures,\n type SplatShInputs,\n type Vec3Uniform,\n} from './splat-mesh-material';\nimport {\n neutralShWord as neutralShWordFor,\n packedRangesEqual,\n requantizeShWord,\n type ShRange,\n} from './sh-pack';\nimport { UniformGrid } from './splat-query';\nimport { resolveXrView } from './xr-view';\nimport {\n SPLAT_DATA_TEXTURE_WIDTH,\n SplatPool,\n addMergedUpdateRange,\n allocateRowSpan,\n createDataTexture,\n deviceMaxTextureSize,\n releaseRowSpan,\n type SplatPoolBacking,\n type SplatPoolRange,\n type SplatPoolTenant,\n} from './splat-mesh-pool';\nimport { warn } from './logging';\nimport { radialSortState } from './splat-sort-bounds';\n\ninterface ChannelRecord {\n readonly type: SplatChannelType;\n /** Default value; rows are reset to it when {@link SplatMesh.appendRange} reuses them. */\n readonly fill: number;\n readonly backing: Uint8Array | Float32Array;\n readonly texture: THREE.DataTexture;\n readonly textureType: THREE.TextureDataType;\n /** Row spans written since the last flush, awaiting GPU upload. */\n pendingRows: { start: number; count: number }[];\n}\n\n/** Reusable GPU source texture for a same-layout pool upload. */\n/** Number of exact-size upload textures retained per data channel. */\nconst UPLOAD_STAGING_CACHE_SIZE = 4;\n\ninterface RangeRecord {\n startRow: number;\n rowCount: number;\n /** First pool splat index (startRow · texture width). */\n start: number;\n count: number;\n active: boolean;\n /** When set, only the first `activePrefix` splats of the range participate in\n * the active (drawn/sorted) list - the rest stay allocated but invisible.\n * Used by the page-table slab, whose used slots are densely packed at the\n * front; drawing the full slab would sort and vertex-process every\n * degenerate tail slot each frame. Undefined = the whole range. */\n activePrefix?: number;\n}\n\n/**\n * Renders a set of 3D Gaussians with three.js's WebGPURenderer.\n *\n * Rendering technique: EWA splatting per the 3DGS paper (Kerbl et al.,\n * SIGGRAPH 2023). Each splat is an instanced quad; the vertex stage projects\n * the splat's 3D covariance to a screen-space ellipse (the same math used by\n * antimatter15/splat and PlayCanvas, both MIT) and the fragment stage applies\n * the Gaussian falloff. Shaders are written in TSL, so three.js compiles\n * them to WGSL on WebGPU and to GLSL on the automatic WebGL2 fallback.\n *\n * Splat data lives in pool data textures, indexed through one small\n * per-instance `splatIndex` attribute. Correct alpha blending needs\n * back-to-front ordering, so the indices are depth-sorted whenever the\n * camera moves - only that index buffer is rewritten, never the splat data\n * itself. On the WebGPU backend the sort runs in TSL compute passes\n * (`ComputeSorter`); the WebGL2 fallback uses a Web Worker (`WorkerSorter`).\n *\n * Two construction modes:\n *\n * - `new SplatMesh(data)` - static: capacity equals the data's count and\n * the whole scene is resident. Works on WebGPU and the WebGL2 fallback,\n * including SOG view-dependent color (shN).\n * - `new SplatMesh({ capacity })` - dynamic: an empty pool for up to\n * `capacity` splats. Content is managed with {@link appendRange} /\n * {@link removeRange} (ranges are row-aligned in the pool textures, so\n * uploads are rectangular). This mode is the substrate for LOD\n * streaming and works on both backends - the WebGL2 fallback sorts the\n * active pool spans on the CPU. shN data on appended ranges is ignored\n * (palettes are per-file and cannot be merged here).\n */\nexport class SplatMesh extends THREE.Mesh implements SplatPoolTenant {\n private static readonly DATA_TEXTURE_WIDTH = SPLAT_DATA_TEXTURE_WIDTH;\n\n /**\n * The storage this mesh draws from. Held rather than inlined because a\n * splat's draw identity is already independent of its pool slot (`splatIndex`\n * indirects every instance), so the pool is a separable concern - see\n * {@link SplatPool}.\n */\n private readonly pool: SplatPool;\n /** False when the pool was supplied by the caller, and so outlives this mesh. */\n private readonly ownsPool: boolean;\n private readonly splatIndexAttribute: THREE.StorageInstancedBufferAttribute;\n private readonly sourceIndexAttribute: THREE.StorageBufferAttribute;\n private dataTextures: readonly THREE.DataTexture[];\n\n /**\n * Pool index → this mesh's packed active-list slot. Lives on the pool: it is\n * keyed by pool index, so a per-mesh copy would span the whole pool and\n * several meshes sharing one would each pay for all of it. A row has one\n * owner at a time, so the single array is unambiguous.\n */\n private get activeSlotByPoolIndex(): Uint32Array {\n return this.pool.activeSlotByPoolIndex;\n }\n\n /** Rows in the pool backing this mesh. */\n private get poolRows(): number {\n return this.pool.rows;\n }\n private get centersTexture(): THREE.DataTexture {\n return this.pool.centersTexture;\n }\n private get backing(): SplatPoolBacking {\n return this.pool.backing;\n }\n private get freeRowSpans(): { start: number; count: number }[] {\n return this.pool.freeRowSpans;\n }\n private set freeRowSpans(spans: { start: number; count: number }[]) {\n this.pool.freeRowSpans = spans;\n }\n private get poolFloatTextures(): 'float32' | 'float16' {\n return this.pool.floatTextures;\n }\n /** Bands of per-splat (non-palette) SH this pool stores; 0 when disabled. */\n private get packedShBands(): 0 | 1 | 2 | 3 {\n return this.pool.packedShBands;\n }\n private get shPackedTextures(): readonly THREE.DataTexture[] {\n return this.pool.shPackedTextures;\n }\n\n /** True when constructed from a complete SplatData (single fixed range). */\n private readonly isStatic: boolean;\n /** Constructor-created range, retained for static in-place LOD replacement. */\n private staticRange: SplatRange | undefined;\n private readonly shEnabled: boolean;\n /**\n * Dequantization range for the packed SH, shared by every coefficient.\n * Uniforms rather than constants: the first chunk to arrive supplies it,\n * long after the material is built.\n */\n private readonly shRange: { min: Vec3Uniform; max: Vec3Uniform };\n /** Set once the first packed-SH chunk has supplied {@link shRange}. */\n private shRangeSet = false;\n /** Whether SH-less rows were neutral-filled before the scene range locked. */\n private wrotePreLockNeutralSh = false;\n\n private readonly ranges = new Map<SplatRange, RangeRecord>();\n private activeCount = 0;\n\n /**\n * Bumped whenever the resident splat set or its positions change (activate,\n * deactivate, compact) - the signal the lazy spatial-query grid rebuilds on.\n * A depth re-sort reorders the active list but changes neither, so it does\n * not bump this. See {@link queryNearest}.\n */\n private queryEpoch = 0;\n private queryGrid: UniformGrid | null = null;\n private queryGridEpoch = -1;\n\n /**\n * True when the shared depth-order buffer holds a *secondary* view's order\n * (left by {@link renderView}), so the next primary {@link update} must\n * re-sort even if its camera has not moved. See {@link renderView} (M10).\n */\n private orderIsForeign = false;\n /**\n * True while the draw list holds a CPU-worker depth permutation rather than\n * the identity active order. Active-list mutations must then resync the\n * whole drawn prefix instead of patching slots: patching a *permutation*\n * with identity active-list values creates duplicates and drops live splats\n * for every frame until the worker's next order lands (the WebGL2 streamed\n * flicker, ROADMAP L5).\n */\n private drawListSorted = false;\n /** CPU timings from the most recent render-preparation update (reset in place per frame). */\n private readonly updateTimings = {\n activeListMs: 0,\n uploadMs: 0,\n sortSubmitMs: 0,\n stagingTextureAllocations: 0,\n activeListUpdateRanges: 0,\n };\n // Protected so a unified {@link MergedSplatMesh} subclass can substitute a\n // world-space sort bound (see {@link refreshSortBounds}).\n protected readonly localBounds = new THREE.Box3().makeEmpty();\n protected readonly boundingSphereLocal = new THREE.Sphere();\n protected boundsDirty = true;\n /** Cached {@link getUnifiedSourceView} result; see the invalidation checks there. */\n private cachedUnifiedView: UnifiedSourceView | null = null;\n private readonly cachedUnifiedViewMatrixWorld = new THREE.Matrix4().makeScale(0, 0, 0);\n private readonly cachedUnifiedViewLocalBounds = new THREE.Sphere();\n private readonly cachedUnifiedViewWorldBounds = new THREE.Sphere();\n\n /** Row spans written since the last flush, awaiting GPU upload. */\n private pendingUploadRows: { start: number; count: number }[] = [];\n /** Row spans awaiting mirroring to the CPU sort worker (WebGL2 path). */\n private workerDirtyRows: { start: number; count: number }[] = [];\n /** Persistent copy sources avoid allocating four temporary textures per upload region. */\n private readonly uploadStaging = new Map<string, Map<number, THREE.DataTexture>>();\n /** Reusable float→half encode buffers keyed like {@link uploadStaging}. */\n private readonly halfEncodeBuffers = new Map<string, Uint16Array>();\n\n /** Opt-in per-splat channels by name; see {@link defineChannel}. */\n private readonly channels = new Map<string, ChannelRecord>();\n\n /** Created on the first update, when the renderer backend is known. */\n private sorter: SplatSorter | null = null;\n\n /**\n * Set by a unified {@link MergedSplatMesh} subclass before the first sort: makes\n * the WebGPU sorter transform each splat's center to world space by its\n * source's matrix before measuring depth. `null` for an ordinary mesh, whose\n * sorter is byte-identical to before. See `source-transform.ts`.\n */\n protected perSourceSort: PerSourceSortTransform | null = null;\n\n /** Effect hooks folded into the vertex graph; see {@link modifiers}. */\n private modifierList: SplatModifier[] = [];\n /** Increments when a unified gather must rebuild its source graph. */\n private graphRevision = 0;\n /** Version for unified work-buffer caching; source pool writes are observable. */\n private contentRevision = 0;\n /** Material-graph inputs kept for rebuilds when the modifier list changes. */\n private materialInputs!: {\n textures: SplatMaterialTextures;\n sh: SplatShInputs | null;\n };\n\n /** Projection focal lengths in pixels; updated every frame. */\n private readonly focal = uniform(new THREE.Vector2());\n /** Drawing-buffer size in pixels; updated every frame. */\n private readonly viewport = uniform(new THREE.Vector2());\n /** Camera position in this mesh's local space, for SH view dependence. */\n private readonly localCameraPosition = uniform(new THREE.Vector3());\n /**\n * Frontier-cut limit for `foveationMode: 'frontier'` - the maximum\n * `own_size / distance` a splat may have and still draw (Spark's\n * `pixelScaleLimit`). Set each frame to `foveationTargetPx / focalPx` so the\n * cut targets a fixed on-screen size. Unused in `'band'` mode.\n */\n private readonly pixelScaleLimit = uniform(0);\n /**\n * Core projected-2D depth of field (live uniforms). Aperture `0` disables.\n * Prefer this over the M13 `depthOfFieldPreset` modifier for camera DoF.\n */\n private readonly dofFocusDistance = uniform(10);\n private readonly dofAperture = uniform(0);\n /**\n * Proxy-mesh screen-space relighting (live uniforms + map). `blend === 0`\n * disables. Swapping the map rebuilds the material graph once.\n */\n private readonly relightPlaceholder = createPlaceholderRelightTexture();\n private relightMap: THREE.Texture = this.relightPlaceholder;\n private readonly relightBlend = uniform(0);\n private readonly relightBrightness = uniform(DEFAULT_RELIGHT_BRIGHTNESS);\n private readonly relightBackground = uniform(DEFAULT_RELIGHT_BACKGROUND);\n private readonly relightSoftness = uniform(DEFAULT_RELIGHT_SOFTNESS);\n /**\n * Live screen-radius band bounds (px), seeded from\n * {@link SplatMeshOptions.minSplatScreenRadius} / `maxSplatScreenRadius` and\n * moved by {@link setScreenRadiusBand} - so a foveated mesh can widen the band\n * as its LOD cut refines rather than culling the detail the refinement bought.\n */\n private readonly screenBandMin = uniform(0);\n private readonly screenBandMax = uniform(0);\n\n /** The pick pass and everything it allocates; see `splat-mesh-picking.ts`. */\n private readonly picker: SplatPicker = new SplatPicker({\n mesh: this,\n isDisposed: () => this.disposed,\n getActiveCount: () => this.activeCount,\n getViewportSize: () => this.viewport.value,\n getPickVisible: () => this.effectiveVisibility,\n hasSorter: () => this.sorter !== null,\n updateWorldMatrix: () => this.updateWorldMatrix(true, false),\n prepare: (camera, renderer) => {\n this.flushPendingUploads(renderer);\n this.refreshProjectionUniforms(camera, renderer);\n // Deliberately not `createSorter`: a depth-tested pick needs a valid\n // draw list, not a sorted one, and the identity list is valid.\n if (this.sorter !== null) this.requestSortIfNeeded(camera, renderer);\n },\n setView: (camera, width, height) => this.writeViewUniforms(camera, width, height),\n applyPickGraph: (material) =>\n applySplatMaterialGraph(\n material,\n 'pick',\n this.graphInputs(this.materialInputs.textures, this.materialInputs.sh),\n ),\n });\n /** Visibility supplied by an owning unified renderer for source-only picks. */\n private unifiedPickVisibility: boolean | null = null;\n /** Set by {@link dispose}; subclasses use it to drop late async results. */\n protected disposed = false;\n /** The renderer this mesh last updated with, so {@link dispose} can free\n * storage-attribute GPU buffers that never sat in a geometry. */\n private lastRenderer: THREE.WebGPURenderer | null = null;\n\n private readonly currentModelView = new THREE.Matrix4();\n /** Pose components that can actually change the selected sort key. */\n private readonly currentSortState = new THREE.Matrix4();\n /** Initialized to an impossible matrix so the first frame always sorts. */\n private readonly lastSortedState = new THREE.Matrix4().makeScale(0, 0, 0);\n private readonly sortScheduler: WebGpuSortScheduler;\n /** One-frame queue-headroom hint used before a staged atomic commit. */\n private deferSortRequestOnce = false;\n /** Bumped by every active-list mutation; identifies a draw list. */\n private activeListVersion = 0;\n /** The active list the current depth order was built from. */\n private sortedActiveListVersion = -1;\n private readonly sortStrategy: SplatSortStrategy;\n private readonly sortMetric: SplatSortMetric;\n /** Resolved only when `sortStrategy === 'radix'`; see {@link ensureRadixSorter}. */\n private RadixSorterCtor: (typeof import('./radix-sorter'))['RadixSorter'] | null = null;\n private radixSorterLoad: Promise<void> | null = null;\n private performanceProfileValue: SplatPerformanceProfile;\n /** Gaussian cutoff radius in σ; baked into the material graph. */\n private maxStdDevValue: number;\n /** Screen-space minimum splat radius in px; baked into the material graph. */\n private readonly minSplatSizePx: number;\n /** Mip-Splatting 2D antialiasing filter; baked into the material graph. */\n private readonly antialias: boolean;\n /** Format-selected low-pass and opacity-compensation policy. */\n private readonly projectedFilterProfile: ProjectedFilterProfile;\n /** Emit sRGB colors for gamma-space compositing; baked into the material graph. */\n private readonly srgbOutput: boolean;\n /** Screen-radius cull threshold in px (0 = off); baked into the material graph. */\n private readonly maxSplatScreenRadius: number;\n private readonly minSplatScreenRadius: number;\n /** `.rad` foveation cut selector; baked into the material graph. */\n private readonly foveationMode: SplatFoveationMode;\n /** Finest on-screen node size (px) the frontier cut may request. */\n private readonly foveationTargetPx: number;\n /** Target upper bound on the frontier cut's drawn-splat count. */\n private readonly foveationDrawBudget: number;\n /** Rendered major/minor axis-ratio cap (0 = off); baked into the material graph. */\n private readonly maxSplatAspect: number;\n /** Spark LOD alpha encoding + merged-node rendering; baked into the material. */\n private readonly lodAlpha: boolean;\n /** Live frontier limit in px; self-adjusts between `foveationTargetPx` (finest)\n * and coarser to hold `foveationDrawBudget`. Feeds `pixelScaleLimit` each frame. */\n private foveationLimitPx: number;\n /** Throttle timestamp for the adaptive-limit estimate (ms, `performance.now`). */\n private lastFoveationAdaptAt = -Infinity;\n /** Y-up normalization policy; drives the static self-orientation below. */\n readonly orientation: SplatOrientation;\n /** Set once the pool has been checked against the device texture limit. */\n private textureLimitChecked = false;\n\n constructor(source: SplatData | { capacity: number }, options: SplatMeshOptions = {}) {\n const sortIntervalMs = validateSortIntervalMs(options.sortIntervalMs);\n // Mobile GPUs are fragment-bound, so several defaults below trade detail\n // no one can see for the fill rate they cost. Every one is overridable.\n // The footprint floor addresses the low-resolution mobile coverage case,\n // not every device that benefits from the broader smooth/fill policy.\n // In particular, an integrated desktop remains at the reference 0 px\n // floor unless its host explicitly opts in.\n const isMobile = detectSplatDeviceProfile()?.isMobile === true;\n // Keep the reference cutoff on every device. Raising it grows every splat's\n // quad (and therefore its fragment cost), including the already-large\n // near-camera splats that dominate mobile overdraw.\n const maxStdDev = validateMaxStdDev(options.maxStdDev) ?? 3;\n // Phones need a little extra coverage only where distant splats shrink far\n // enough to leave dark gaps. The shader floor grows those undersized discs\n // without increasing fill for the rest; callers can still disable it with 0.\n const minSplatSizePx = validateMinSplatSizePx(options.minSplatSizePx) ?? (isMobile ? 1.5 : 0);\n const isStatic = !('capacity' in source);\n const capacity = isStatic ? source.count : source.capacity;\n if (capacity <= 0) throw new Error('SplatMesh capacity must be positive.');\n\n // Pool data textures (CPU backing arrays kept for partial uploads):\n // centers RGBA32F or RGBA16F x, y, z, (unused)\n // colors RGBA8 r, g, b, opacity\n // covarianceA RGBA32F or RGBA16F m00, m01, m02, m11\n // covarianceB RGBA32F m12, m22, shN palette label, frontier parent\n // shPacked[t] RGBA32UI per-splat SH coefficients 4t..4t+3, still packed\n //\n // Float16 is opt-in for centers/covA only (VRAM). CPU backing stays\n // float32; covarianceB stays float32 because it packs integer IDs.\n // Spherical harmonics a *static* mesh should actually render.\n //\n // A static mesh carries its SH in the data, and this used to read it\n // blindly: `options.shBands` and the `smooth` performance profile (the\n // mobile default) were both ignored, so no caller and no device could\n // decline it. On a 1.4M-splat band-3 capture that is four RGBA32UI pool\n // textures - 128 B/splat of GPU + CPU backing, ~180 MB - plus four texture\n // fetches and a 15-coefficient evaluation per splat *per frame*. The same\n // defect on `.rad` cost 48% of its pool.\n //\n // Resolved the way `StreamedSplatMesh.fromSource` resolves it, so both\n // paths answer the same request: an explicit `shBands` wins, otherwise the\n // performance profile decides.\n //\n // **All-or-nothing**, exactly as `buildRadScene` is: `writePackedSh` copies\n // packed words only when the counts match exactly, so asking for *fewer*\n // bands than the data carries would allocate the smaller texture set and\n // then fill it with neutral words - paying for SH and rendering flat.\n const staticShWanted =\n (options.shBands ??\n (resolveSplatPerformanceProfile(options.performanceProfile) === 'smooth'\n ? 0\n : MAX_SH_BANDS)) !== 0;\n // The dynamic branch keeps `?? 0`: a dynamic pool has no data to read bands\n // from, so defaulting it to MAX would allocate SH textures for every mesh\n // that never asked for any.\n const packedShBands: 0 | 1 | 2 | 3 = isStatic\n ? staticShWanted\n ? (source.shPacked?.bands ?? 0)\n : 0\n : (options.shBands ?? 0);\n // A supplied pool is shared: this mesh draws from it but never frees it.\n const suppliedPool = options.pool;\n const makeOwnPool = () =>\n new SplatPool({\n capacity,\n floatTextures: options.poolFloatTextures,\n packedShBands,\n packedShTextureCount:\n packedShBands === 0 ? 0 : Math.ceil(shCoefficientCount(packedShBands) / 4),\n ...(options.maxTextureSize === undefined ? {} : { maxTextureSize: options.maxTextureSize }),\n });\n // A shared pool allocates its packed-SH textures once, so it can only serve\n // tenants with its own band count. Rather than fail the load, such a mesh\n // falls back to its own pool: in a multi-mesh scene it is usually one odd\n // capture carrying SH, and sizing the shared pool for it would add\n // ~64 B/splat across storage that mostly has no SH to read.\n const shMismatch = suppliedPool !== undefined && packedShBands !== suppliedPool.packedShBands;\n if (shMismatch) {\n warn(\n `a mesh with shBands ${packedShBands} cannot share a pool built for ` +\n `${suppliedPool?.packedShBands}; it allocated its own pool instead.`,\n );\n }\n const ownsPool = suppliedPool === undefined || shMismatch;\n const pool = ownsPool ? makeOwnPool() : suppliedPool;\n // Per-mesh draw state is sized by what *this* mesh can have active, not by\n // the pool: sharing a large pool between many meshes would otherwise give\n // each of them a pool-sized draw list and active list (8 B per pool splat,\n // per mesh). Pool *indices* still range over the whole pool - only the\n // number of slots is bounded here. Identical to `pool.capacity` when the\n // mesh allocated the pool itself.\n const texelCount = Math.min(\n pool.capacity,\n Math.ceil(capacity / SplatMesh.DATA_TEXTURE_WIDTH) * SplatMesh.DATA_TEXTURE_WIDTH,\n );\n const centersTexture = pool.centersTexture;\n const colorsTexture = pool.colorsTexture;\n const covarianceATexture = pool.covarianceATexture;\n const covarianceBTexture = pool.covarianceBTexture;\n // Palette shN (SOG/`.lcc2`) takes the same gate as the packed bands above.\n // Its palette is shared rather than per-splat, so it costs little memory -\n // but the per-frame work is identical: a texture fetch per coefficient plus\n // the full evaluation, on every splat. Leaving this ungated would have made\n // `shBands: 0` silently ineffective for exactly the formats that use it.\n //\n // Gating here also stops `writeSplatRows` storing the per-splat palette\n // labels, since it keys off `shEnabled` (this texture being non-null).\n const shPaletteTexture =\n isStatic && source.sh && staticShWanted\n ? createDataTexture(\n source.sh.palette,\n source.sh.paletteWidth,\n source.sh.paletteHeight,\n THREE.FloatType,\n )\n : null;\n const shPackedTextures = pool.shPackedTextures;\n\n // One quad, instanced per splat. Corners span [-1, 1]; the vertex stage\n // scales them to ±3σ along the projected ellipse axes.\n const geometry = new THREE.InstancedBufferGeometry();\n geometry.setIndex([0, 1, 2, 0, 2, 3]);\n geometry.setAttribute(\n 'position',\n new THREE.BufferAttribute(new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0]), 3),\n );\n // A storage attribute so the GPU sorter can rewrite it in compute\n // passes; on the WebGL2 fallback it acts as a plain instanced\n // attribute that the worker sorter updates from the CPU.\n const splatIndexes = new Float32Array(texelCount);\n for (let i = 0; i < texelCount; i++) splatIndexes[i] = i;\n const splatIndexAttribute = new THREE.StorageInstancedBufferAttribute(splatIndexes, 1);\n geometry.setAttribute('splatIndex', splatIndexAttribute);\n geometry.instanceCount = 0;\n\n super(geometry, new THREE.NodeMaterial());\n this.pool = pool;\n this.ownsPool = ownsPool;\n pool.register(this);\n this.sortScheduler = new WebGpuSortScheduler(sortIntervalMs, isMobile);\n this.sortStrategy = options.sortStrategy ?? 'counting';\n this.sortMetric = options.sortMetric ?? 'depth';\n if (this.sortStrategy === 'radix' || this.sortStrategy === 'exact') this.ensureRadixSorter();\n this.performanceProfileValue = resolveSplatPerformanceProfile(options.performanceProfile);\n this.maxStdDevValue = maxStdDev;\n this.minSplatSizePx = minSplatSizePx;\n // Explicit option wins; otherwise honor the source scene's flag (SOG meta).\n this.antialias = options.antialias ?? (isStatic ? (source.antialias ?? false) : false);\n this.projectedFilterProfile = options.projectedFilterProfile ?? 'default';\n this.srgbOutput = options.srgbOutput ?? false;\n this.maxSplatScreenRadius = validateMaxSplatScreenRadius(options.maxSplatScreenRadius);\n this.minSplatScreenRadius = validateMaxSplatScreenRadius(options.minSplatScreenRadius);\n this.screenBandMin.value = this.minSplatScreenRadius;\n this.screenBandMax.value = this.maxSplatScreenRadius;\n this.foveationMode = resolveSplatFoveationMode(options.foveationMode);\n this.foveationTargetPx = validateFoveationTargetPx(options.foveationTargetPx);\n this.foveationDrawBudget = validateFoveationDrawBudget(options.foveationDrawBudget);\n this.foveationLimitPx = this.foveationTargetPx;\n this.maxSplatAspect = validateMaxSplatScreenRadius(options.maxSplatAspect); // finite ≥ 0\n this.lodAlpha = options.lodAlpha ?? false;\n this.orientation = options.orientation ?? 'y-up';\n this.splatIndexAttribute = splatIndexAttribute;\n this.sourceIndexAttribute = new THREE.StorageBufferAttribute(new Uint32Array(texelCount), 1);\n this.dataTextures = pool.coreTextures;\n this.isStatic = isStatic;\n this.shEnabled = shPaletteTexture !== null;\n this.shRange = { min: vec3Uniform(), max: vec3Uniform() };\n this.frustumCulled = false; // Culling happens per splat in the shader.\n if (shPaletteTexture) this.dataTextures = [...this.dataTextures, shPaletteTexture];\n if (shPackedTextures.length > 0)\n this.dataTextures = [...this.dataTextures, ...shPackedTextures];\n\n this.materialInputs = {\n textures: { centersTexture, colorsTexture, covarianceATexture, covarianceBTexture },\n sh:\n isStatic && source.sh && shPaletteTexture\n ? { mode: 'palette', bands: source.sh.bands, paletteTexture: shPaletteTexture }\n : packedShBands !== 0\n ? {\n mode: 'packed',\n bands: packedShBands,\n textures: shPackedTextures,\n range: this.shRange,\n }\n : null,\n };\n this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh);\n\n if (isStatic) {\n this.staticRange = this.appendRange(source);\n // Constructor-time writes are covered by the textures' initial\n // `needsUpdate` upload - the GPU cannot have seen them earlier. Any\n // append after construction must go through the staging-copy path,\n // because the backend may already have uploaded the textures by then.\n this.pendingUploadRows = [];\n // Float16 GPU images are separate from the float32 backing: pack the\n // constructor write into the texture image before the initial upload.\n if (this.poolFloatTextures === 'float16') this.syncHalfFloatPoolImages();\n // Orient a known-format scene to Y-up (unless in 'source' mode). The\n // correction is a rigid object-level transform, so the GPU rotates each\n // Gaussian's covariance and view-dependent SH consistently - nothing is\n // baked into the splat data. A dynamic pool has no source format, so it\n // is never auto-oriented (its host applies yUpTransformForFormat itself).\n const correction = this.orientation === 'y-up' ? yUpTransformForFormat(source.format) : null;\n if (correction) {\n this.matrix.copy(correction);\n this.matrix.decompose(this.position, this.quaternion, this.scale);\n this.matrixWorldNeedsUpdate = true;\n }\n }\n }\n\n /**\n * Higher-order SH bands this mesh actually renders (0 when it has none),\n * whatever the source: a static mesh's palette shN, or per-splat SH in a\n * dynamic pool. Reflects what was resolved at construction, not what was\n * asked for - useful for a debug readout.\n */\n get shBands(): number {\n return this.materialInputs.sh?.bands ?? 0;\n }\n\n /**\n * The contribution-culling profile currently in effect (resolved at\n * construction, or the last {@link setPerformanceProfile} value).\n */\n get performanceProfile(): SplatPerformanceProfile {\n return this.performanceProfileValue;\n }\n\n /**\n * Changes contribution culling without changing scene data or persisted\n * settings.\n *\n * Mutator convention: state that is plain data is a property (get/set pair);\n * a `setX` method exists where the write has behavior - this one rebuilds the\n * material graph, {@link StreamedSplatMesh.setBudget} returns its clamp.\n * Every mutator has a matching readable property.\n */\n setPerformanceProfile(profile: SplatPerformanceProfile): void {\n if (profile === this.performanceProfileValue) return;\n this.performanceProfileValue = profile;\n this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh);\n }\n\n /**\n * Gaussian cutoff radius currently in effect, in standard deviations.\n * Resolved at construction, or the last {@link setMaxStdDev} value.\n */\n get maxStdDev(): number {\n return this.maxStdDevValue;\n }\n\n /**\n * Changes the Gaussian cutoff without changing scene data.\n *\n * Lowering it shrinks every quad and is the main fill-rate lever in a busy\n * view; raising it restores the faint outer tail. Rebuilds the material\n * graph, same convention as {@link setPerformanceProfile}.\n */\n setMaxStdDev(value: number): void {\n const next = validateMaxStdDev(value);\n if (next === undefined || next === this.maxStdDevValue) return;\n this.maxStdDevValue = next;\n this.cachedUnifiedView = null;\n this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh);\n }\n\n /**\n * Copies a decoded scene (or chunk) into the pool and activates it.\n * Ranges are row-aligned in the pool textures, so each allocation may\n * round up to the next multiple of the texture width internally.\n *\n * @returns A handle to pass to {@link removeRange}.\n * @throws {Error} when the remaining pool capacity cannot fit the range.\n */\n appendRange(data: SplatData): SplatRange {\n return this.appendRangeWithState(data, true);\n }\n\n /** Appends uploaded data without exposing it to draw/sort until activated. */\n protected appendInactiveRange(data: SplatData): SplatRange {\n return this.appendRangeWithState(data, false);\n }\n\n /** Reserves an inactive pool range whose data can be filled over multiple frames. */\n protected reserveInactiveRange(count: number): SplatRange {\n if (!Number.isInteger(count) || count < 0) {\n throw new RangeError('SplatMesh.reserveInactiveRange: count must be a non-negative integer.');\n }\n if (count === 0) {\n const empty: SplatRange = Object.freeze({ count: 0 });\n this.ranges.set(empty, { startRow: 0, rowCount: 0, start: 0, count: 0, active: false });\n return empty;\n }\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n const rowCount = Math.ceil(count / width);\n const startRow = allocateRowSpan(this.freeRowSpans, rowCount, this.poolRows);\n const start = startRow * width;\n const handle: SplatRange = Object.freeze({ count });\n this.ranges.set(handle, { startRow, rowCount, start, count, active: false });\n\n // A reused row may retain channel values from its previous occupant.\n for (const channel of this.channels.values()) {\n channel.backing.fill(channel.fill, start, start + rowCount * width);\n channel.pendingRows.push({ start: startRow, count: rowCount });\n }\n return handle;\n }\n\n /** Writes one contiguous segment of a reserved inactive range. */\n protected writeInactiveRange(handle: SplatRange, data: SplatData, offset: number): void {\n const record = this.ranges.get(handle);\n if (!record) throw new Error('SplatMesh.writeInactiveRange: unknown range handle.');\n if (record.active) throw new Error('SplatMesh.writeInactiveRange: range is already active.');\n if (!Number.isInteger(offset) || offset < 0 || offset + data.count > record.count) {\n throw new RangeError('SplatMesh.writeInactiveRange: write exceeds the reserved range.');\n }\n if (data.count === 0) return;\n this.warnOnIgnoredSh(data, 'writeInactiveRange');\n\n const destination = record.start + offset;\n this.writeSplatRows(destination, data);\n\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n const firstRow = Math.floor(destination / width);\n const lastRow = Math.floor((destination + data.count - 1) / width);\n this.markRowsWritten(firstRow, lastRow - firstRow + 1);\n _appendBox.setFromArray(data.positions);\n this.localBounds.union(_appendBox);\n this.boundsDirty = true;\n }\n\n /**\n * Overwrites splats at `offset` within a range **in place** - unlike\n * {@link writeInactiveRange} this allows an *active* range, so the frontier\n * page table can page individual slots of its always-active slab. Queues the\n * touched rows for upload; the caller must {@link invalidateSort} once per\n * batch since splat depths changed.\n */\n protected overwriteRangeData(handle: SplatRange, data: SplatData, offset: number): void {\n const record = this.ranges.get(handle);\n if (!record) throw new Error('SplatMesh.overwriteRangeData: unknown range handle.');\n if (!Number.isInteger(offset) || offset < 0 || offset + data.count > record.count) {\n throw new RangeError('SplatMesh.overwriteRangeData: write exceeds the range.');\n }\n if (data.count === 0) return;\n this.warnOnIgnoredSh(data, 'overwriteRangeData');\n const destination = record.start + offset;\n this.writeSplatRows(destination, data);\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n const firstRow = Math.floor(destination / width);\n const lastRow = Math.floor((destination + data.count - 1) / width);\n this.markRowsWritten(firstRow, lastRow - firstRow + 1);\n _appendBox.setFromArray(data.positions);\n this.localBounds.union(_appendBox);\n this.boundsDirty = true;\n // The unified renderer reuses its gathered work buffer while this is\n // unchanged. A paging plan that only relocates survivors leaves the resident\n // count alone, so without this bump the gather (and the sort that follows\n // it) would be skipped and the frame would keep the previous frontier.\n this.contentRevision++;\n }\n\n /**\n * Zeros splats `[offset, offset + count)` of a range so they draw nothing\n * (zero covariance → degenerate quad, zero color). Used to free frontier slab\n * slots that leave the frontier. Queues the rows for upload.\n */\n protected degenerateRange(handle: SplatRange, offset: number, count: number): void {\n const record = this.ranges.get(handle);\n if (!record) throw new Error('SplatMesh.degenerateRange: unknown range handle.');\n if (count <= 0) return;\n if (!Number.isInteger(offset) || offset < 0 || offset + count > record.count) {\n throw new RangeError('SplatMesh.degenerateRange: range out of bounds.');\n }\n const start = record.start + offset;\n const { centers, colors, covarianceA, covarianceB } = this.backing;\n centers.fill(0, start * 4, (start + count) * 4);\n colors.fill(0, start * 4, (start + count) * 4);\n covarianceA.fill(0, start * 4, (start + count) * 4);\n covarianceB.fill(0, start * 4, (start + count) * 4);\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n const firstRow = Math.floor(start / width);\n const lastRow = Math.floor((start + count - 1) / width);\n this.markRowsWritten(firstRow, lastRow - firstRow + 1);\n this.contentRevision++;\n }\n\n /**\n * Copies one chunk's splats into the pool's backing arrays at `destination`.\n * Shared by the append and staged-write paths, which differ only in where\n * the rows come from and when they are activated.\n */\n private writeSplatRows(destination: number, data: SplatData): void {\n const { centers, colors, covarianceA, covarianceB } = this.backing;\n colors.set(data.colors, destination * 4);\n // Everything loop-invariant is hoisted into locals, including the two\n // optional arrays. `data` reaches here from several construction sites with\n // different shapes (sliced chunks, worker paging plans, whole SplatData), so\n // reading `data.positions` / `data.frontierParent` *inside* the loop makes\n // those megamorphic property loads - measured at ~5k splats/ms, where a\n // 600k-splat paging plan cost ~139 ms of one frame. The body below touches\n // only locals and typed arrays.\n const count = data.count;\n const positions = data.positions;\n const covariances = data.covariances;\n const labels = this.shEnabled && data.sh ? data.sh.labels : null;\n // covarianceB.w is otherwise unused; the frontier cut packs each splat's\n // signed `parent_size` here (0 = unwritten, treated as a root).\n const frontierParent = data.frontierParent ?? null;\n for (let i = 0; i < count; i++) {\n const p = (destination + i) * 4;\n const p3 = i * 3;\n const p6 = i * 6;\n centers[p + 0] = positions[p3 + 0] as number;\n centers[p + 1] = positions[p3 + 1] as number;\n centers[p + 2] = positions[p3 + 2] as number;\n covarianceA[p + 0] = covariances[p6 + 0] as number;\n covarianceA[p + 1] = covariances[p6 + 1] as number;\n covarianceA[p + 2] = covariances[p6 + 2] as number;\n covarianceA[p + 3] = covariances[p6 + 3] as number;\n covarianceB[p + 0] = covariances[p6 + 4] as number;\n covarianceB[p + 1] = covariances[p6 + 5] as number;\n covarianceB[p + 2] = labels ? (labels[i] as number) : 0;\n covarianceB[p + 3] = frontierParent ? (frontierParent[i] as number) : 0;\n }\n this.writePackedSh(destination, data);\n }\n\n /**\n * Scatters a chunk's packed SH words into the per-group pool textures.\n *\n * A chunk without SH still writes: pool rows are reused, so leaving the\n * previous occupant's words behind would give a DC-only chunk somebody\n * else's view-dependent color. Zero is not neutral (the range is signed and\n * rarely symmetric), so the code for \"0.0\" in this scene's range is.\n */\n private writePackedSh(destination: number, data: SplatData): void {\n if (this.packedShBands === 0) return;\n const groups = this.backing.shPacked;\n const wanted = shCoefficientCount(this.packedShBands);\n const source = data.shPacked;\n\n if (source && source.bands === this.packedShBands) {\n this.applyShRange(source);\n // A chunk quantized against a different range than the scene's (a SOG\n // chunk measures its own extent - M11) is requantized into the scene\n // range word-by-word, so every splat decodes through the one pool\n // uniform. When the ranges already match (LCC/`.rad`, or the range-setting\n // first chunk) this is a verbatim copy.\n const target = this.currentShRange();\n const requantize = target !== null && !packedRangesEqual(source.range, target);\n for (let i = 0; i < data.count; i++) {\n for (let c = 0; c < wanted; c++) {\n const word = source.packed[i * wanted + c] as number;\n (groups[c >> 2] as Uint32Array)[(destination + i) * 4 + (c & 3)] = requantize\n ? requantizeShWord(word, source.range, target)\n : word;\n }\n }\n return;\n }\n // Before the range locks, the neutral word is unknowable (word 0 decodes\n // to `range.min` once a range exists - not 0.0). Write 0 for now and\n // remember to backfill every pre-lock row when the first SH chunk arrives.\n if (!this.shRangeSet) this.wrotePreLockNeutralSh = true;\n const neutral = this.neutralShWord();\n for (let i = 0; i < data.count; i++) {\n for (let c = 0; c < wanted; c++) {\n (groups[c >> 2] as Uint32Array)[(destination + i) * 4 + (c & 3)] = neutral;\n }\n }\n }\n\n /**\n * Adopts the first packed-SH chunk's dequantization range as the scene's one\n * pool uniform. LCC/`.rad` chunks already share one range; a streamed SOG\n * chunk measures its own extent, so later chunks are requantized into this\n * one at write time ({@link writePackedSh}) rather than ignored.\n */\n private applyShRange(source: NonNullable<SplatData['shPacked']>): void {\n if (this.shRangeSet) return;\n this.shRange.min.value.set(source.range.min[0], source.range.min[1], source.range.min[2]);\n this.shRange.max.value.set(source.range.max[0], source.range.max[1], source.range.max[2]);\n this.shRangeSet = true;\n\n // SH-less chunks appended before this lock were filled with word 0, which\n // now decodes to `range.min` in every channel - garbage view-dependent\n // color. Every pre-lock write was such a fill (an SH chunk would have\n // locked the range itself), so refilling the whole pool with the real\n // neutral word is correct even across compactions; the range-setting\n // chunk overwrites its own rows right after this. One-time, and only in\n // mixed captures where an SH-less chunk lands first.\n if (this.wrotePreLockNeutralSh) {\n const neutral = this.neutralShWord();\n for (const group of this.backing.shPacked) group.fill(neutral);\n this.markRowsWritten(0, this.poolRows);\n this.wrotePreLockNeutralSh = false;\n }\n }\n\n /** The scene's locked packed-SH range as a plain tuple, or null if unset. */\n private currentShRange(): ShRange | null {\n if (!this.shRangeSet) return null;\n const { min, max } = this.shRange;\n return {\n min: [min.value.x, min.value.y, min.value.z],\n max: [max.value.x, max.value.y, max.value.z],\n };\n }\n\n /** The packed word decoding to 0 in every channel under the scene's range. */\n private neutralShWord(): number {\n const range = this.currentShRange();\n if (!range) return 0;\n return neutralShWordFor(range);\n }\n\n /** Warns once per call site when a source's SH cannot be stored. */\n private warnOnIgnoredSh(data: SplatData, method: string): void {\n if (data.sh && !this.isStatic) {\n warn(\n `SplatMesh.${method}: palette shN data on appended ranges is ignored in dynamic-capacity mode ` +\n '(per-file palettes cannot be merged into a shared pool).',\n );\n }\n if (data.shPacked && this.packedShBands === 0) {\n warn(\n `SplatMesh.${method}: per-splat SH was supplied but the pool has none allocated ` +\n (this.isStatic\n ? '(the static source had no `shPacked` at construction).'\n : '(construct the mesh with `shBands` to store it).'),\n );\n }\n }\n\n /** Atomically includes or excludes a resident range on the next active-list rebuild. */\n protected setRangeActive(handle: SplatRange, active: boolean): void {\n const record = this.ranges.get(handle);\n if (!record) throw new Error('SplatMesh.setRangeActive: unknown range handle.');\n if (record.active === active) return;\n record.active = active;\n if (active) this.activateRecord(record);\n else this.deactivateRecord(record);\n this.contentRevision++;\n }\n\n /**\n * Activates only the first `prefix` splats of a range (see\n * {@link RangeRecord.activePrefix}). The page-table slab keeps its used slots\n * densely packed at the front, so this bounds per-frame sorting and vertex\n * work to the *drawn* frontier instead of the whole pool-sized slab. Write\n * APIs (`overwriteRangeData` / `degenerateRange`) still address the full range.\n */\n protected setRangeActivePrefix(handle: SplatRange, prefix: number): void {\n const record = this.ranges.get(handle);\n if (!record) throw new Error('SplatMesh.setRangeActivePrefix: unknown range handle.');\n const next = Math.max(0, Math.min(record.count, Math.floor(prefix)));\n const current = record.active ? (record.activePrefix ?? record.count) : 0;\n if (next === current) return;\n // Remove the old prefix from the active list, then re-add at the new length.\n if (record.active) {\n this.deactivateRecord(record);\n record.active = false;\n }\n record.activePrefix = next;\n if (next > 0) {\n record.active = true;\n this.activateRecord(record);\n }\n this.contentRevision++;\n }\n\n /**\n * Replaces the drawn pool indices for an immutable static hierarchy.\n *\n * This is intentionally narrower than the range API: subclasses may select\n * an arbitrary hierarchy frontier, but the referenced pool rows must remain\n * resident for the lifetime of the mesh.\n */\n protected replaceActiveIndices(indices: Uint32Array): void {\n const source = this.sourceIndexAttribute.array as Uint32Array;\n if (indices.length > source.length) {\n throw new RangeError('SplatMesh.replaceActiveIndices: frontier exceeds pool capacity.');\n }\n\n this.activeSlotByPoolIndex.fill(0xffffffff);\n for (let slot = 0; slot < indices.length; slot++) {\n const poolIndex = indices[slot] as number;\n if (poolIndex >= source.length) {\n throw new RangeError(\n 'SplatMesh.replaceActiveIndices: frontier contains an invalid pool index.',\n );\n }\n if (this.activeSlotByPoolIndex[poolIndex] !== 0xffffffff) {\n throw new Error(\n 'SplatMesh.replaceActiveIndices: frontier contains duplicate pool indices.',\n );\n }\n source[slot] = poolIndex;\n this.activeSlotByPoolIndex[poolIndex] = slot;\n }\n\n const previousCount = this.activeCount;\n this.activeCount = indices.length;\n this.commitActiveListMutation(0, Math.max(previousCount, this.activeCount));\n this.queryEpoch++;\n this.contentRevision++;\n }\n\n /** Fast identity-frontier variant that avoids allocating a large index array. */\n protected replaceActivePrefix(count: number): void {\n const source = this.sourceIndexAttribute.array as Uint32Array;\n const next = Math.max(0, Math.min(source.length, Math.floor(count)));\n this.activeSlotByPoolIndex.fill(0xffffffff);\n for (let index = 0; index < next; index++) {\n source[index] = index;\n this.activeSlotByPoolIndex[index] = index;\n }\n const previousCount = this.activeCount;\n this.activeCount = next;\n this.commitActiveListMutation(0, Math.max(previousCount, next));\n this.queryEpoch++;\n this.contentRevision++;\n }\n\n /** Replaces a static mesh's resident cut without increasing its fixed pool allocation. */\n protected replaceStaticData(data: SplatData): void {\n if (!this.isStatic || !this.staticRange) {\n throw new Error('SplatMesh.replaceStaticData: mesh was not constructed from static data.');\n }\n if (data.count > this.capacity) {\n throw new RangeError('SplatMesh.replaceStaticData: cut exceeds pool capacity.');\n }\n this.overwriteRangeData(this.staticRange, data, 0);\n this.setRangeActivePrefix(this.staticRange, data.count);\n this.invalidateSort();\n }\n\n private appendRangeWithState(data: SplatData, active: boolean): SplatRange {\n if (data.count === 0) {\n // Zero rows must not touch the free list: allocateRows(0) would return\n // a span start without consuming it, and the matching removeRange would\n // push a degenerate zero-count span.\n const empty: SplatRange = Object.freeze({ count: 0 });\n this.ranges.set(empty, { startRow: 0, rowCount: 0, start: 0, count: 0, active });\n return empty;\n }\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n const rowCount = Math.ceil(data.count / width);\n const startRow = allocateRowSpan(this.freeRowSpans, rowCount, this.poolRows);\n const start = startRow * width;\n\n this.warnOnIgnoredSh(data, 'appendRange');\n this.writeSplatRows(start, data);\n // Rows shared with removed ranges may hold stale splats past\n // data.count; they are inactive (not in sourceIndex), so harmless.\n\n const handle: SplatRange = Object.freeze({ count: data.count });\n const record: RangeRecord = { startRow, rowCount, start, count: data.count, active };\n this.ranges.set(handle, record);\n this.markRowsWritten(startRow, rowCount);\n\n // Reset per-splat channels for the allocated rows. Rows reused from a\n // removed range still hold the previous occupant's channel values, and\n // nothing else clears them - without this, a new chunk landing on old rows\n // renders wearing the old chunk's mask (\"ghost paint\").\n for (const channel of this.channels.values()) {\n channel.backing.fill(channel.fill, start, start + rowCount * width);\n channel.pendingRows.push({ start: startRow, count: rowCount });\n }\n\n _appendBox.setFromArray(data.positions);\n this.localBounds.union(_appendBox);\n this.boundsDirty = true;\n\n if (active) this.activateRecord(record);\n this.contentRevision++;\n return handle;\n }\n\n /**\n * Deactivates a previously appended range and frees its pool rows for\n * reuse. The bounding sphere used for depth quantization stays a\n * conservative superset until new ranges grow it again.\n */\n removeRange(handle: SplatRange): void {\n const record = this.ranges.get(handle);\n if (!record) throw new Error('SplatMesh.removeRange: unknown range handle.');\n if (record.active) this.deactivateRecord(record);\n this.ranges.delete(handle);\n if (record.rowCount > 0) {\n this.freeRowSpans = releaseRowSpan(this.freeRowSpans, record.startRow, record.rowCount);\n }\n this.contentRevision++;\n }\n\n /** Maximum number of splats the pool can hold (row-aligned internally). */\n get capacity(): number {\n return this.poolRows * SplatMesh.DATA_TEXTURE_WIDTH;\n }\n\n /** Number of splats currently active (drawn and depth-sorted). */\n get activeSplatCount(): number {\n return this.activeCount;\n }\n\n /**\n * Returns this mesh's current pool state for an internal unified gather.\n * Call {@link update} first for streamed sources so the active list reflects\n * the current LOD cut. Consumers must treat the returned GPU resources as\n * read-only; range lifecycle remains owned by this mesh.\n */\n getUnifiedSourceView(): UnifiedSourceView {\n this.updateWorldMatrix(true, false);\n this.refreshSortBounds();\n // The view is rebuilt only when something it reflects actually changed;\n // a steady frame returns the cached object (and its world-bounds sphere)\n // instead of re-deriving both per source per frame. Identity checks on the\n // GPU resources keep the cache safe against texture/graph replacement even\n // if a future mutation path forgets to bump a revision.\n const cached = this.cachedUnifiedView;\n if (\n cached !== null &&\n cached.contentRevision === this.contentRevision &&\n cached.graphRevision === this.graphRevision &&\n cached.activeCount === this.activeCount &&\n cached.sh === this.materialInputs.sh &&\n cached.modifiers === this.modifierList &&\n cached.hasSourcePlacement === (this.perSourceSort !== null) &&\n cached.centersTexture === this.centersTexture &&\n cached.colorsTexture === this.materialInputs.textures.colorsTexture &&\n this.cachedUnifiedViewMatrixWorld.equals(this.matrixWorld) &&\n this.cachedUnifiedViewLocalBounds.equals(this.boundingSphereLocal)\n ) {\n return cached;\n }\n this.cachedUnifiedViewMatrixWorld.copy(this.matrixWorld);\n this.cachedUnifiedViewLocalBounds.copy(this.boundingSphereLocal);\n this.cachedUnifiedViewWorldBounds.copy(this.boundingSphereLocal).applyMatrix4(this.matrixWorld);\n this.cachedUnifiedView = {\n capacity: this.capacity,\n sourceIndex: this.sourceIndexAttribute,\n activeCount: this.activeCount,\n centersTexture: this.centersTexture,\n colorsTexture: this.materialInputs.textures.colorsTexture,\n covarianceATexture: this.materialInputs.textures.covarianceATexture,\n covarianceBTexture: this.materialInputs.textures.covarianceBTexture,\n dataTextureWidth: SplatMesh.DATA_TEXTURE_WIDTH,\n matrixWorld: this.matrixWorld,\n worldBounds: this.cachedUnifiedViewWorldBounds,\n sh: this.materialInputs.sh,\n modifiers: this.modifierList,\n hasSourcePlacement: this.perSourceSort !== null,\n channels: this.channels,\n localCameraPosition: this.localCameraPosition,\n graphRevision: this.graphRevision,\n srgbOutput: this.srgbOutput,\n maxStdDev: this.maxStdDev,\n minSplatSizePx: this.minSplatSizePx,\n antialias: this.antialias,\n projectedFilterProfile: this.projectedFilterProfile,\n // Fixed at construction, so it needs no cache-invalidation key.\n lodAlpha: this.lodAlpha,\n contentRevision: this.contentRevision,\n };\n return this.cachedUnifiedView;\n }\n\n /**\n * Marks this mesh as a source drawn by {@link UnifiedSplatMesh}.\n * The source stays invisible to the regular scene draw, while its own picker\n * mirrors this resolved visibility so existing per-source hit testing works.\n * Internal consumers should clear the state with `null` before disposing.\n */\n setUnifiedPickVisibility(visible: boolean | null): void {\n this.unifiedPickVisibility = visible;\n }\n\n /**\n * The visibility that actually decides whether this mesh's splats reach the\n * screen: the owning {@link UnifiedSplatMesh}'s per-source visibility\n * while one owns the draw, else `Object3D.visible`. Consumers that gate on\n * \"is this mesh showing\" - the picker, `CameraBudgetGovernor` - must read\n * this rather than `visible`, which a unified renderer forces to `false` on\n * every source it owns purely to keep the regular scene draw from\n * double-drawing them.\n */\n get effectiveVisibility(): boolean {\n return this.unifiedPickVisibility ?? this.visible;\n }\n\n /**\n * Pool splats still allocatable, in whole rows. Because allocation is\n * row-aligned, an append of n splats fits when\n * `ceil(n / rowWidth) · rowWidth ≤ freeSplatCapacity` *and* a contiguous\n * span exists; callers use this for conservative pre-checks before\n * falling back to {@link compact}.\n */\n get freeSplatCapacity(): number {\n let rows = 0;\n for (const span of this.freeRowSpans) rows += span.count;\n return rows * SplatMesh.DATA_TEXTURE_WIDTH;\n }\n\n /**\n * Declares a named per-splat data channel - one extra value per pool slot,\n * in its own pool-aligned data texture. Channels are opt-in: nothing is\n * allocated until you call this. Read a channel from a modifier with\n * `ctx.channel(name)` and write values per range with {@link writeChannel}.\n *\n * Because a splat keeps its pool row for its whole residency, a channel\n * value follows the splat across depth re-sorts and pool {@link compact}ion\n * - the persistent per-splat label the SDF/selection effects build on. Call\n * this **before** assigning a modifier that reads the channel; a modifier\n * that reads an undeclared channel is a material-build error.\n *\n * @throws {Error} if a channel of this name already exists.\n */\n defineChannel(name: string, options: SplatChannelOptions = {}): void {\n if (this.channels.has(name)) {\n throw new Error(`SplatMesh.defineChannel: channel \"${name}\" already defined.`);\n }\n const type = options.type ?? 'float';\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n const texelCount = width * this.poolRows;\n const backing = type === 'byte' ? new Uint8Array(texelCount) : new Float32Array(texelCount);\n const fill = options.fill ?? 0;\n if (fill) backing.fill(fill);\n const textureType = type === 'byte' ? THREE.UnsignedByteType : THREE.FloatType;\n const texture = new THREE.DataTexture(\n backing,\n width,\n this.poolRows,\n THREE.RedFormat,\n textureType,\n );\n texture.needsUpdate = true;\n this.channels.set(name, { type, fill, backing, texture, textureType, pendingRows: [] });\n // No material rebuild here: a modifier that reads this channel cannot have\n // been assigned yet (assigning one before its channel exists throws at\n // build time), so no live graph references the new texture.\n }\n\n /**\n * Writes channel values for a resident range, at `[offset, offset + data.length)`\n * splats within it (default `offset` 0). Values ride the same staging-upload\n * path as pool data, flushed on the next {@link update}. `byte` channels take\n * raw `0..255`; `float` channels take the value verbatim.\n *\n * @throws {Error} for an unknown channel or range, or a write past the range.\n */\n writeChannel(range: SplatRange, name: string, data: ArrayLike<number>, offset = 0): void {\n const channel = this.channels.get(name);\n if (!channel) throw new Error(`SplatMesh.writeChannel: channel \"${name}\" is not defined.`);\n const record = this.ranges.get(range);\n if (!record) throw new Error('SplatMesh.writeChannel: unknown range handle.');\n if (offset < 0 || offset + data.length > record.count) {\n throw new Error(\n `SplatMesh.writeChannel: write of ${data.length} at offset ${offset} exceeds ` +\n `range count ${record.count}.`,\n );\n }\n if (data.length === 0) return;\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n const first = record.start + offset;\n // Both Uint8Array and Float32Array `set` accept any ArrayLike<number>;\n // values are coerced to the backing type (bytes are truncated to 0..255).\n (channel.backing as { set(a: ArrayLike<number>, o: number): void }).set(data, first);\n const startRow = Math.floor(first / width);\n const endRow = Math.floor((first + data.length - 1) / width);\n channel.pendingRows.push({ start: startRow, count: endRow - startRow + 1 });\n this.contentRevision++;\n }\n\n /**\n * Effect hooks, folded into the vertex stage in array order - each\n * modifier sees the running result of the ones before it. Assigning a\n * changed list rebuilds the material (a pipeline recompile); animating a\n * modifier's own uniforms or storage buffers never does. With an empty\n * list the material is exactly the unhooked renderer.\n * See `docs/guide/effects-and-modifiers.md`.\n */\n get modifiers(): readonly SplatModifier[] {\n return this.modifierList;\n }\n\n set modifiers(value: readonly SplatModifier[]) {\n const unchanged =\n value.length === this.modifierList.length &&\n value.every((modifier, i) => modifier === this.modifierList[i]);\n if (unchanged) return;\n const previous = this.modifierList;\n this.modifierList = [...value];\n try {\n this.rebuildGraph();\n } catch (error) {\n // A modifier threw at build time (e.g. reading an undeclared channel).\n // Roll back so the same list can be re-assigned after the caller fixes\n // the cause - otherwise the identity diff above would short-circuit it.\n // Deliberately `buildMaterial`, not `rebuildGraph`: restoring the graph\n // that was already compiled is not a structural change, so it must not\n // bump `graphRevision` (see modifier-slots.test.ts).\n this.modifierList = previous;\n this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh);\n throw error;\n }\n }\n\n /**\n * Recompiles the material graph from the mesh's current inputs and publishes\n * the rebuild (`needsUpdate`, `graphRevision`, picker invalidation).\n *\n * A seam rather than inline code because a subclass can change a *build\n * input* without changing the modifier list - `MergedSplatMesh` installs its\n * per-source placement in the constructor, after the base class has already\n * built a placement-free graph. Note `defineChannel` deliberately does *not*\n * rebuild; only structural graph changes come through here.\n *\n * @internal\n */\n protected rebuildGraph(): void {\n this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh);\n (this.material as THREE.Material).needsUpdate = true;\n this.graphRevision++;\n this.picker.markNeedsUpdate();\n }\n\n /**\n * Core projected-2D depth of field. Adds an isotropic screen-space CoC disc\n * after EWA projection (not the stylized M13 scale modifier). Live uniforms\n * - no material rebuild. Pass `aperture: 0` to disable.\n */\n setDepthOfField(settings: Partial<DepthOfFieldSettings>): void {\n const next = clampDepthOfFieldSettings(settings, this.getDepthOfField());\n this.dofFocusDistance.value = next.focusDistance;\n this.dofAperture.value = next.aperture;\n }\n\n /**\n * PlayCanvas-style proxy-mesh relighting. Multiplies baked splat color in the\n * **display** fragment by a screen-space sample of `map` (RGB = lit proxy,\n * A = coverage). Pass `null` to disable (`blend → 0`, placeholder map).\n *\n * Blend / brightness / background are live uniforms (no rebuild). Changing\n * the map texture identity rebuilds the material once. Does not affect the\n * pick pass. Does not invalidate a unified gather cache.\n */\n setRelighting(options: RelightingSettings | null): void {\n if (options === null) {\n this.relightBlend.value = 0;\n if (this.relightMap !== this.relightPlaceholder) {\n this.relightMap = this.relightPlaceholder;\n this.rebuildGraph();\n }\n return;\n }\n const next = clampRelightingSettings(options, this.getRelighting());\n this.relightBlend.value = next.blend;\n this.relightBrightness.value = next.brightness;\n this.relightBackground.value = next.background;\n this.relightSoftness.value = next.softness;\n if (options.map !== this.relightMap) {\n this.relightMap = options.map;\n this.rebuildGraph();\n }\n }\n\n /** Current relight numeric uniforms (`blend === 0` means off). */\n getRelighting(): RelightingUniforms {\n return {\n blend: this.relightBlend.value,\n brightness: this.relightBrightness.value,\n background: this.relightBackground.value,\n softness: this.relightSoftness.value,\n };\n }\n\n /**\n * Moves the screen-radius band (px) without rebuilding the material.\n *\n * Only meaningful on a mesh constructed *with* a band - the graph decides at\n * build time whether to cull on radius at all, from\n * {@link SplatMeshOptions.minSplatScreenRadius} / `maxSplatScreenRadius`.\n *\n * A foveated mesh uses this to keep the band aligned with its LOD cut: the\n * band spans roughly one level, so refining the cut to spend spare budget\n * selects smaller splats, and a band left where it was would cull precisely\n * the detail that refinement bought.\n */\n protected setScreenRadiusBand(minPx: number, maxPx: number): void {\n this.screenBandMin.value = Math.max(0, minPx);\n this.screenBandMax.value = Math.max(0, maxPx);\n }\n\n /** Current core DoF uniforms (`aperture === 0` means off). */\n getDepthOfField(): DepthOfFieldSettings {\n return {\n focusDistance: this.dofFocusDistance.value,\n aperture: this.dofAperture.value,\n };\n }\n\n /**\n * Packs the resident ranges toward the start of the pool, removing the\n * gaps that add/remove churn leaves behind and restoring a single\n * contiguous free span. Use this when {@link appendRange} throws despite\n * enough total free rows (row-alignment fragmentation).\n *\n * The CPU backing arrays are authoritative, so no data is re-fetched;\n * moved rows are re-uploaded to the GPU on the next {@link update}.\n */\n compact(): void {\n this.pool.compact();\n }\n\n /** {@link SplatPoolTenant}: the ranges this mesh holds in the pool. */\n poolRanges(): Iterable<SplatPoolRange> {\n return this.ranges.values();\n }\n\n /**\n * {@link SplatPoolTenant}: follow one range to its new rows. The pool has\n * already moved the splat data; this moves what the mesh keys by pool row.\n */\n relocatePoolRange(range: SplatPoolRange, targetRow: number): void {\n const record = range as RangeRecord;\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n // Channels are single-component and pool-row-aligned, so a range's channel\n // data relocates alongside its splats - this is what keeps a painted mask\n // attached to the splat across compaction.\n for (const channel of this.channels.values()) {\n const cFrom = record.startRow * width;\n const cTo = targetRow * width;\n const cLength = record.rowCount * width;\n channel.backing.copyWithin(cTo, cFrom, cFrom + cLength);\n channel.pendingRows.push({ start: targetRow, count: record.rowCount });\n }\n record.startRow = targetRow;\n record.start = targetRow * width;\n this.markRowsWritten(targetRow, record.rowCount);\n }\n\n /** {@link SplatPoolTenant}: rebuild everything keyed by pool index. */\n onPoolCompacted(): void {\n this.queryEpoch++; // rows moved, so pool-index → position changed\n // Pool indices changed, so rebuild immediately before another public pool\n // mutation can consult the reverse active-slot map.\n this.rebuildActiveList();\n this.contentRevision++;\n }\n\n /**\n * Per-frame update: uploads pending pool writes, refreshes the projection\n * uniforms and requests a depth re-sort when the camera or the content\n * has changed. Call this every frame, before `renderer.render`.\n */\n update(\n camera: THREE.PerspectiveCamera,\n renderer: THREE.WebGPURenderer,\n options: SplatUpdateOptions = {},\n ): void {\n // A render loop can outlive the mesh by a frame; updating after dispose\n // would recreate a sorter and upload into disposed textures.\n if (this.disposed) return;\n this.lastRenderer = renderer;\n this.assertPoolFitsDevice(renderer);\n camera.updateMatrixWorld();\n this.updateWorldMatrix(true, false);\n this.updateTimings.activeListMs = 0;\n this.updateTimings.uploadMs = 0;\n this.updateTimings.sortSubmitMs = 0;\n this.updateTimings.stagingTextureAllocations = 0;\n this.updateTimings.activeListUpdateRanges = 0;\n const uploadStartedAt = performance.now();\n this.flushPendingUploads(renderer);\n this.updateTimings.uploadMs = performance.now() - uploadStartedAt;\n // Resolve the drawn view once: XR gives a per-eye viewport and a separate\n // head pose, everything else the whole canvas. Both consumers below must\n // agree on the size - `adaptFoveationLimit` and `writeViewUniforms` share\n // `foveationLimitPx` through a px→normalized conversion that each does\n // with its own focal length, so a size mismatch makes that loop diverge.\n const xrView = resolveXrView(camera, renderer);\n let projectionCamera: THREE.Camera = camera;\n let sortCamera: THREE.Camera = camera;\n let viewWidth: number;\n let viewHeight: number;\n if (xrView) {\n // Per-eye projection reaches the shader through three's per-render-view\n // TSL nodes; the hand-managed uniforms take the eye's focal/viewport and\n // the head's position (cyclopean - at a ~63 mm IPD the per-eye SH/order\n // difference is imperceptible). One sort from the head serves both eyes;\n // a per-eye re-sort would double the frame's dominant cost.\n projectionCamera = xrView.eye;\n sortCamera = xrView.head;\n viewWidth = xrView.width;\n viewHeight = xrView.height;\n } else {\n renderer.getDrawingBufferSize(_viewSize);\n viewWidth = _viewSize.x;\n viewHeight = _viewSize.y;\n }\n this.adaptFoveationLimit(projectionCamera, viewHeight);\n this.writeViewUniforms(projectionCamera, viewWidth, viewHeight, sortCamera);\n this.updateTimings.activeListUpdateRanges = this.sourceIndexAttribute.updateRanges.length;\n if (options.sort !== false) {\n const sortStartedAt = performance.now();\n this.requestSortIfNeeded(sortCamera, renderer);\n this.updateTimings.sortSubmitMs = performance.now() - sortStartedAt;\n }\n }\n\n /** Returns the render-preparation CPU timings for the current update. */\n protected getUpdateTimings(): Readonly<{\n activeListMs: number;\n uploadMs: number;\n sortSubmitMs: number;\n stagingTextureAllocations: number;\n activeListUpdateRanges: number;\n }> {\n return this.updateTimings;\n }\n\n /**\n * Skips one otherwise ordinary sort request, but only while the active list\n * is unchanged since the last sort. Streamed staging uses this immediately\n * before a forced commit sort so the GPU queue has a frame to drain; a\n * concurrent swap group that mutates the active list revokes the request,\n * because the depth order must always describe the list being drawn.\n */\n protected deferNextSortRequest(): void {\n this.deferSortRequestOnce = true;\n }\n\n /**\n * Once, on the first update (when the backend is known), fails loudly if the\n * pool's `2048 × poolRows` data textures exceed the device's maximum texture\n * dimension - otherwise the upload fails with a cryptic backend error and a\n * frozen canvas. Streamed scenes stay under the limit (budget-bounded); this\n * guards very large *static* scenes, especially on mobile (≈8192 max → about\n * 16.7 M splats). If the limit can't be read, the check is skipped rather\n * than risk a false rejection.\n */\n private assertPoolFitsDevice(renderer: THREE.WebGPURenderer): void {\n if (this.textureLimitChecked) return;\n this.textureLimitChecked = true;\n const maxSize = deviceMaxTextureSize(renderer);\n if (maxSize > 0 && this.poolRows > maxSize) {\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n throw new Error(\n `SplatMesh: this scene needs a ${width}×${this.poolRows} data texture, but this ` +\n `device caps texture dimensions at ${maxSize} (about ` +\n `${(maxSize * width).toLocaleString('en-US')} splats). Stream it with ` +\n `StreamedSplatMesh, or reduce the splat count.`,\n );\n }\n }\n\n /** Bounding box of the appended splats, in this mesh's local space. */\n computeSplatBounds(): THREE.Box3 {\n return this.localBounds.clone();\n }\n\n /**\n * Asynchronously picks the frontmost visible splat under an NDC coordinate.\n *\n * Renders a one-pixel GPU depth pass (shared projection/Gaussian math with\n * the display material), reads the encoded view depth, and reconstructs a\n * world-space point on the splat's rendered center plane. Concurrent calls\n * on this mesh are serialized. Returns `null` for misses, empty meshes,\n * out-of-canvas coordinates, or after {@link dispose}.\n *\n * Does not return a persistent splat id - LOD streaming and pool reuse make\n * identity unstable across frames.\n */\n pick(\n ndc: THREE.Vector2,\n camera: THREE.Camera,\n renderer: THREE.WebGPURenderer,\n options?: SplatPickOptions,\n ): Promise<SplatPickResult | null> {\n return this.picker.pick(ndc, camera, renderer, options);\n }\n\n /**\n * The resident splat center nearest a world point, within `radius` (world\n * units), or `null` if none. A synchronous CPU query over the pool's decoded\n * centers - no GPU round-trip - backed by a uniform grid rebuilt only when\n * the resident set changes (M9). The primitive behind measurement markers and\n * proximity tests.\n *\n * **Resident-only:** a {@link StreamedSplatMesh} searches only the splats\n * currently in the pool (the LOD the camera has resolved), so the answer is\n * the nearest *loaded* splat - coarser far from the camera, absent where no\n * chunk has streamed in. A static mesh searches its whole scene.\n *\n * World-correct under any rotation + per-axis (including non-uniform) scale:\n * candidates are gathered in local space with a conservative radius\n * (`radius / min axis scale`) and then ranked by **world** distance, so the\n * nearest-in-world splat wins even when the axes stretch differently. Shear\n * in an ancestor transform is not supported. Splats displaced by GPU\n * modifiers are queried at their undisplaced CPU positions.\n */\n queryNearest(worldPoint: THREE.Vector3, radius: number): SplatNearestResult | null {\n if (this.activeCount === 0 || !(radius >= 0)) return null;\n this.updateWorldMatrix(true, false);\n _queryLocal.copy(worldPoint);\n this.worldToLocal(_queryLocal);\n const grid = this.ensureQueryGrid();\n // A world sphere of `radius` maps into local space within\n // radius / minAxisScale of the local query point; gather that superset,\n // then rank each candidate by its true world distance.\n const gather = radius / this.queryWorldMinScale();\n const r2 = radius * radius;\n let bestIndex = -1;\n let bestSq = Infinity;\n grid.forEachWithin(_queryLocal.x, _queryLocal.y, _queryLocal.z, gather, (poolIndex) => {\n this.splatWorldPosition(poolIndex, _queryWorld);\n const d2 = _queryWorld.distanceToSquared(worldPoint);\n if (d2 <= r2 && d2 < bestSq) {\n bestSq = d2;\n bestIndex = poolIndex;\n }\n });\n if (bestIndex < 0) return null;\n const point = this.splatWorldPosition(bestIndex, new THREE.Vector3());\n return { point, distance: Math.sqrt(bestSq) };\n }\n\n /**\n * Returns the first resident splat center inside a world-space ray cone.\n * This is a synchronous CPU query, intended for interactions that cannot\n * wait for (or rely on) a GPU readback. `radiusAtUnitDistance` is the cone's\n * world-space radius one unit from the origin; `minimumRadius` keeps nearby\n * point-like splats practical to target.\n *\n * Like {@link queryNearest}, this searches resident, undisplaced CPU centers.\n */\n queryRay(\n ray: THREE.Ray,\n radiusAtUnitDistance = 0.025,\n minimumRadius = 0.05,\n ): SplatRayResult | null {\n if (\n this.activeCount === 0 ||\n !(radiusAtUnitDistance >= 0) ||\n !(minimumRadius >= 0) ||\n ray.direction.lengthSq() === 0\n ) {\n return null;\n }\n this.updateWorldMatrix(true, false);\n const active = (this.sourceIndexAttribute.array as Uint32Array).subarray(0, this.activeCount);\n let bestIndex = -1;\n let bestDistance = Infinity;\n for (const poolIndex of active) {\n this.splatWorldPosition(poolIndex, _queryWorld);\n _queryLocal.subVectors(_queryWorld, ray.origin);\n const distance = _queryLocal.dot(ray.direction);\n if (distance < 0 || distance >= bestDistance) continue;\n _queryLocal.addScaledVector(ray.direction, -distance);\n const radius = Math.max(minimumRadius, distance * radiusAtUnitDistance);\n if (_queryLocal.lengthSq() <= radius * radius) {\n bestIndex = poolIndex;\n bestDistance = distance;\n }\n }\n if (bestIndex < 0) return null;\n return {\n point: this.splatWorldPosition(bestIndex, new THREE.Vector3()),\n distance: bestDistance,\n };\n }\n\n /**\n * The supporting surface beneath a world point: the highest resident splat\n * that lies no more than `maxDrop` below it (world −Y) and within `radius`\n * horizontally, or `null` if none. A downward probe over splat centers - the\n * primitive behind floor-following and teleport validation - without a GPU\n * pick or a collision mesh (M9), so it works for every format, not only the\n * `.lcc2` captures that ship collision geometry.\n *\n * `radius` (default `maxDrop / 2`) is the horizontal tolerance: splats are\n * points, so an exact vertical hit is unlikely and a small disc is searched.\n * Resident-only semantics and the world-correctness contract (rotation +\n * per-axis scale supported, shear not) are the same as {@link queryNearest};\n * every candidate is judged in world space, where the −Y probe direction is\n * defined, so the vertical test never assumes local axis alignment.\n */\n queryHeight(\n worldPoint: THREE.Vector3,\n maxDrop: number,\n radius = maxDrop / 2,\n ): SplatHeightResult | null {\n if (this.activeCount === 0 || !(maxDrop >= 0) || !(radius >= 0)) return null;\n this.updateWorldMatrix(true, false);\n _queryLocal.copy(worldPoint);\n this.worldToLocal(_queryLocal);\n const grid = this.ensureQueryGrid();\n // A supporting splat is at most `maxDrop` below and `radius` aside, so it\n // lies within (maxDrop + radius) of the query in world units - gather that\n // sphere mapped conservatively to local space (divide by the smallest axis\n // scale), then judge each candidate in world space where \"down\" is\n // unambiguous.\n const gatherLocal = (maxDrop + radius) / this.queryWorldMinScale();\n const r2 = radius * radius;\n let bestY = -Infinity;\n let bestIndex = -1;\n grid.forEachWithin(_queryLocal.x, _queryLocal.y, _queryLocal.z, gatherLocal, (poolIndex) => {\n this.splatWorldPosition(poolIndex, _queryWorld);\n const drop = worldPoint.y - _queryWorld.y;\n if (drop < 0 || drop > maxDrop) return; // above the point, or too far below\n const dx = _queryWorld.x - worldPoint.x;\n const dz = _queryWorld.z - worldPoint.z;\n if (dx * dx + dz * dz > r2) return; // outside the horizontal disc\n if (_queryWorld.y > bestY) {\n bestY = _queryWorld.y;\n bestIndex = poolIndex;\n }\n });\n if (bestIndex < 0) return null;\n const point = this.splatWorldPosition(bestIndex, new THREE.Vector3());\n return { point, drop: worldPoint.y - point.y };\n }\n\n /**\n * Renders this mesh from a second camera - into `target`, or the canvas when\n * omitted - with depth order **and** projection correct for *that* camera\n * (M10). The primitive behind mirrors, portals, split panes, and thumbnails.\n *\n * Depth order is view-dependent, but a mesh keeps one sorted order buffer:\n * `update()` sorts it for the single camera it is given, so a second view\n * drawn with that order shows transparency/pop errors. `renderView` re-sorts\n * for `camera` into the shared buffer, sets the view-dependent uniforms\n * (viewport from `target`), draws, and marks the primary order stale so the\n * next `update()` re-sorts for the main camera. GPU submissions execute in\n * order, so each view's draw reads the order and uniforms it just wrote.\n *\n * Call once per extra view per frame, before or after the primary\n * `update()` + render - both are correct. On the WebGL2 fallback the sorter\n * is an asynchronous worker owned by the primary view, so `renderView` does\n * not sort at all there: the secondary view draws with the primary view's\n * order (projection is still per-camera correct) - a documented single-view\n * ordering limitation; WebGPU gets exact per-view order.\n *\n * @param target - Destination render target, or `null`/omitted for the canvas.\n */\n renderView(\n camera: THREE.PerspectiveCamera,\n renderer: THREE.WebGPURenderer,\n target: THREE.RenderTarget | null = null,\n ): void {\n if (this.disposed) return;\n this.lastRenderer = renderer;\n camera.updateMatrixWorld();\n this.updateWorldMatrix(true, false);\n this.flushPendingUploads(renderer);\n if (target) _viewSize.set(target.width, target.height);\n else renderer.getDrawingBufferSize(_viewSize);\n this.writeViewUniforms(camera, _viewSize.x, _viewSize.y);\n const sorted = this.sortForView(camera, renderer);\n\n const previousTarget = renderer.getRenderTarget();\n try {\n renderer.setRenderTarget(target);\n renderer.render(this, camera);\n } finally {\n renderer.setRenderTarget(previousTarget);\n // The shared order buffer now holds this view's order; force the primary\n // view to re-sort even when the secondary draw throws. Only when a sort\n // actually ran: WebGL2 still holds the primary order and must not fight\n // its asynchronous worker for a redundant re-sort.\n if (sorted) this.orderIsForeign = true;\n }\n }\n\n /**\n * Sorts the shared order buffer for a secondary view's camera, bypassing the\n * primary view's sort scheduler and its last-sorted pose record (that\n * state belongs to `update()`'s camera). WebGPU dispatches synchronously into\n * the render queue, so the following draw reads this order.\n */\n private sortForView(camera: THREE.Camera, renderer: THREE.WebGPURenderer): boolean {\n if (this.activeCount === 0) return false;\n // The WebGL2 worker sorter is asynchronous and shared with the primary\n // view: submitting the secondary camera here would land the *secondary*\n // order between frames and claim the worker every frame ahead of the\n // primary's request - permanently starving the main view of its own sort.\n // Skip instead; the secondary view draws with the primary order (the\n // documented WebGL2 limitation).\n const isWebGPU = (renderer.backend as { isWebGPUBackend?: boolean }).isWebGPUBackend === true;\n if (!isWebGPU) return false;\n this.currentModelView.multiplyMatrices(camera.matrixWorldInverse, this.matrixWorld);\n this.refreshSortBounds();\n this.sorter ??= this.createSorter(renderer);\n if (!this.sorter) return false;\n this.sorter.sort(this.currentModelView, this.activeCount, this.boundingSphereLocal);\n return true;\n }\n\n /** Rebuilds the query grid if the resident set changed since it was built. */\n private ensureQueryGrid(): UniformGrid {\n if (this.queryGrid && this.queryGridEpoch === this.queryEpoch) return this.queryGrid;\n const active = (this.sourceIndexAttribute.array as Uint32Array).subarray(0, this.activeCount);\n this.queryGrid = new UniformGrid(this.backing.centers, active, this.activeCount);\n this.queryGridEpoch = this.queryEpoch;\n return this.queryGrid;\n }\n\n /** World-space position of pool splat `poolIndex`, written into `out`. */\n private splatWorldPosition(poolIndex: number, out: THREE.Vector3): THREE.Vector3 {\n const base = poolIndex * 4;\n out.set(\n this.backing.centers[base] as number,\n this.backing.centers[base + 1] as number,\n this.backing.centers[base + 2],\n );\n return out.applyMatrix4(this.matrixWorld);\n }\n\n /**\n * The smallest world axis scale, for conservatively mapping a world radius\n * into local space: a world sphere of radius `r` fits inside a local sphere\n * of `r / minAxisScale`, for any per-axis (non-uniform) scale.\n */\n private queryWorldMinScale(): number {\n this.getWorldScale(_queryScale);\n // decompose() negates scale.x for mirrored (negative-determinant)\n // transforms; a mirror preserves distances, but a negative radius would\n // silently null every query.\n return Math.min(Math.abs(_queryScale.x), Math.abs(_queryScale.y), Math.abs(_queryScale.z)) || 1;\n }\n\n /**\n * Releases every GPU resource and worker this mesh owns. Idempotent: a\n * second call is a no-op, and a render loop that outlives the mesh by a\n * frame is safe - {@link update}, {@link renderView} and {@link pick} all\n * become no-ops after dispose.\n */\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.sorter?.dispose();\n this.sorter = null;\n this.geometry.dispose();\n (this.material as THREE.Material).dispose();\n this.picker.dispose();\n this.relightPlaceholder.dispose();\n // Leaving the pool releases this mesh's rows: `compact` accounts for every\n // row against a registered tenant, so a departing one must take its\n // allocations with it.\n for (const record of this.ranges.values())\n this.pool.releaseRows(record.startRow, record.rowCount);\n this.pool.unregister(this);\n // The pool's textures are disposed only by whoever owns the pool. A mesh\n // that built its own pool owns it; one handed a shared pool does not.\n if (this.ownsPool) this.pool.dispose();\n for (const texture of this.dataTextures) {\n if (!this.ownsPool && this.pool.isPoolTexture(texture)) continue;\n texture.dispose();\n }\n for (const channel of this.channels.values()) channel.texture.dispose();\n this.channels.clear();\n for (const cache of this.uploadStaging.values()) {\n for (const texture of cache.values()) texture.dispose();\n }\n this.uploadStaging.clear();\n this.halfEncodeBuffers.clear();\n // `sourceIndex` never sits in a geometry, so `geometry.dispose()` cannot\n // free its GPU buffer - release it through the renderer that uploaded it\n // (4 B/splat leaked per scene swap otherwise).\n if (this.lastRenderer) {\n releaseRendererAttributes(this.lastRenderer, [this.sourceIndexAttribute]);\n this.lastRenderer = null;\n }\n // Drop queued CPU work and cached references so nothing uploads or\n // rebuilds after teardown, and large arrays are unreachable promptly.\n this.pendingUploadRows = [];\n this.workerDirtyRows = [];\n this.queryGrid = null;\n this.ranges.clear();\n }\n\n /** Matches the viewport / focal / local-camera uniforms written by {@link update}. */\n private refreshProjectionUniforms(camera: THREE.Camera, renderer: THREE.WebGPURenderer): void {\n renderer.getDrawingBufferSize(_viewSize);\n this.writeViewUniforms(camera, _viewSize.x, _viewSize.y);\n }\n\n /**\n * Writes the three view-dependent uniforms - viewport, focal (splat screen\n * size), and the camera position in mesh-local space (SH view direction +\n * screen-radius math) - for a camera drawing into a viewport of the given\n * pixel size. {@link update} passes the canvas size (or, while an XR session\n * presents, the per-eye viewport); {@link renderView} passes its render\n * target's size.\n *\n * @param positionCamera - Camera whose world position seeds the SH view\n * direction and screen-radius math. Defaults to `camera`; in XR it is the\n * head, so both eyes shade from one cyclopean point while each still\n * projects through its own eye.\n */\n private writeViewUniforms(\n camera: THREE.Camera,\n viewportX: number,\n viewportY: number,\n positionCamera: THREE.Camera = camera,\n ): void {\n this.viewport.value.set(viewportX, viewportY);\n const projection = camera.projectionMatrix.elements;\n const focalY = (projection[5] * viewportY) / 2;\n this.focal.value.set((projection[0] * viewportX) / 2, focalY);\n positionCamera.getWorldPosition(this.localCameraPosition.value);\n this.worldToLocal(this.localCameraPosition.value);\n // Frontier cut: a splat draws while its projected node size ≈ target px, i.e.\n // own_size · focalY / distance ≤ targetPx ⇔ own_size / distance ≤ targetPx / focalY.\n // focalY is the vertical focal length in px, matching the view-space depth the\n // material uses as `distance`.\n if (this.foveationMode === 'frontier' && focalY > 0) {\n this.pixelScaleLimit.value = this.foveationLimitPx / focalY;\n }\n }\n\n /**\n * Self-adjusts {@link foveationLimitPx} so the frontier cut's drawn-splat count\n * tracks {@link foveationDrawBudget} (Spark's `maxSplats` feedback). Estimates\n * the drawn count by replaying the cut on a strided sample of the pool, then\n * coarsens (grows the limit) when over budget and refines (shrinks toward the\n * finest {@link foveationTargetPx}) when comfortably under. Throttled; a no-op\n * outside `'frontier'` mode.\n *\n * `viewportY` must be the **same** height {@link writeViewUniforms} is given\n * for this frame - the two share `foveationLimitPx` in pixels and each\n * converts it with its own `focalY`, so a mismatch (the full drawing buffer\n * here against a per-eye viewport there) makes the estimator judge a cut the\n * shader is not applying, and the ratchet runs away toward the maximum.\n */\n private adaptFoveationLimit(camera: THREE.Camera, viewportY: number): void {\n if (this.foveationMode !== 'frontier') return;\n const now = performance.now();\n if (now - this.lastFoveationAdaptAt < FOVEATION_ADAPT_MS) return;\n this.lastFoveationAdaptAt = now;\n\n const focalY = (camera.projectionMatrix.elements[5] * viewportY) / 2;\n if (!(focalY > 0)) return;\n const limit = this.foveationLimitPx / focalY;\n camera.getWorldPosition(_camLocal);\n this.worldToLocal(_camLocal);\n // model-view-projection into mesh-local space, so the estimate can frustum-\n // cull exactly like the material's `isVisible` - the budget is about splats\n // actually *on screen*, not the whole resident set (most of which sits behind\n // or beside the camera). Without this the limit over-coarsens ~6× and blurs.\n _adaptView.copy(camera.matrixWorld).invert();\n _adaptMvp.multiplyMatrices(_adaptView, this.matrixWorld).premultiply(camera.projectionMatrix);\n const m = _adaptMvp.elements;\n\n // Replay the material's frontier test (own_size from covariance trace,\n // signed parent_size in covarianceB.w) on every Nth in-frustum slot.\n const { covarianceA: cA, covarianceB: cB, centers } = this.backing;\n const slots = cB.length / 4;\n let sampled = 0;\n let drawn = 0;\n for (let i = 0; i < slots; i += FOVEATION_ADAPT_STRIDE) {\n const base = i * 4;\n const packedParent = cB[base + 3] as number;\n if (packedParent === 0) continue; // empty slot or non-frontier splat\n sampled++;\n const cx = centers[base] as number;\n const cy = centers[base + 1] as number;\n const cz = centers[base + 2] as number;\n // Frustum cull (clip-space, margin 1.2·w to match the material).\n const clipW = m[3] * cx + m[7] * cy + m[11] * cz + m[15];\n const margin = clipW * 1.2;\n const clipZ = m[2] * cx + m[6] * cy + m[10] * cz + m[14];\n if (clipZ <= -margin) continue;\n const clipX = m[0] * cx + m[4] * cy + m[8] * cz + m[12];\n if (clipX > margin || clipX < -margin) continue;\n const clipY = m[1] * cx + m[5] * cy + m[9] * cz + m[13];\n if (clipY > margin || clipY < -margin) continue;\n\n const trace = (cA[base] as number) + (cA[base + 3] as number) + (cB[base + 1] as number);\n const ownSize = 2 * Math.sqrt(Math.max(trace, 0) / 3);\n const isLeaf = packedParent < 0;\n const parentSize = Math.abs(packedParent);\n const dx = cx - _camLocal.x;\n const dy = cy - _camLocal.y;\n const dz = cz - _camLocal.z;\n const limitDist = limit * Math.sqrt(dx * dx + dy * dy + dz * dz);\n const ownCut = isLeaf ? 0 : ownSize;\n if (parentSize > limitDist && ownCut <= limitDist) drawn++;\n }\n if (sampled === 0) return;\n\n const estimatedDrawn = drawn * FOVEATION_ADAPT_STRIDE;\n const budget = this.foveationDrawBudget;\n if (estimatedDrawn > budget * 1.1) {\n this.foveationLimitPx = Math.min(this.foveationLimitPx * 1.15, FOVEATION_LIMIT_MAX_PX);\n } else if (estimatedDrawn < budget * 0.7) {\n this.foveationLimitPx = Math.max(this.foveationLimitPx / 1.12, this.foveationTargetPx);\n }\n }\n\n /** Records a written row span for GPU upload and the sort-worker mirror. */\n private markRowsWritten(start: number, count: number): void {\n this.pendingUploadRows.push({ start, count });\n // The worker mirror only needs deltas once a WorkerSorter exists; it\n // snapshots the whole pool at creation time.\n if (this.sorter?.kind === 'worker') this.workerDirtyRows.push({ start, count });\n }\n\n /** Appends one newly active pool range to the packed source-index list. */\n private activateRecord(record: RangeRecord): void {\n const count = record.activePrefix ?? record.count;\n if (count === 0) return;\n this.queryEpoch++;\n const source = this.sourceIndexAttribute.array as Uint32Array;\n const identity = this.getPoolIndexTemplate();\n const activeStart = this.activeCount;\n source.set(identity.subarray(record.start, record.start + count), activeStart);\n this.activeSlotByPoolIndex.set(\n identity.subarray(activeStart, activeStart + count),\n record.start,\n );\n this.activeCount += count;\n this.commitActiveListMutation(activeStart, count);\n }\n\n /**\n * Removes one active range and backfills its holes from the packed tail.\n * The common contiguous case uses one native block copy; the fallback\n * handles a range split by earlier tail backfills in O(record.count).\n */\n private deactivateRecord(record: RangeRecord): void {\n const activeLen = record.activePrefix ?? record.count;\n if (activeLen === 0) return;\n this.queryEpoch++;\n const source = this.sourceIndexAttribute.array as Uint32Array;\n const firstSlot = this.activeSlotByPoolIndex[record.start] as number;\n let contiguous = true;\n for (let index = 1; index < activeLen; index++) {\n if (this.activeSlotByPoolIndex[record.start + index] !== firstSlot + index) {\n contiguous = false;\n break;\n }\n }\n\n let dirtyStart = this.activeCount;\n let dirtyEnd = 0;\n if (contiguous) {\n const nextActiveCount = this.activeCount - activeLen;\n const copyCount = Math.min(activeLen, Math.max(0, nextActiveCount - firstSlot));\n if (copyCount > 0) {\n source.copyWithin(firstSlot, this.activeCount - copyCount, this.activeCount);\n for (let index = 0; index < copyCount; index++) {\n const movedPoolIndex = source[firstSlot + index] as number;\n this.activeSlotByPoolIndex[movedPoolIndex] = firstSlot + index;\n }\n dirtyStart = firstSlot;\n dirtyEnd = firstSlot + copyCount;\n }\n this.activeCount = nextActiveCount;\n } else {\n for (let poolIndex = record.start; poolIndex < record.start + activeLen; poolIndex++) {\n const slot = this.activeSlotByPoolIndex[poolIndex] as number;\n const lastSlot = this.activeCount - 1;\n if (slot !== lastSlot) {\n const movedPoolIndex = source[lastSlot] as number;\n source[slot] = movedPoolIndex;\n this.activeSlotByPoolIndex[movedPoolIndex] = slot;\n dirtyStart = Math.min(dirtyStart, slot);\n dirtyEnd = Math.max(dirtyEnd, slot + 1);\n }\n this.activeCount--;\n }\n dirtyEnd = Math.min(dirtyEnd, this.activeCount);\n }\n\n this.commitActiveListMutation(dirtyStart, Math.max(0, dirtyEnd - dirtyStart));\n }\n\n /** Uploads only the changed packed slots and invalidates the current depth order. */\n private commitActiveListMutation(start: number, count: number): void {\n if (count > 0) {\n addMergedUpdateRange(this.sourceIndexAttribute, start, count);\n this.sourceIndexAttribute.needsUpdate = true;\n }\n\n // Until the asynchronous WebGL worker returns, keep its draw list on a\n // valid unsorted active permutation. WebGPU compute sorters overwrite\n // the draw storage themselves and do not need this CPU mirror.\n if (this.sorter?.kind === 'worker' || this.sorter === null) {\n const source = this.sourceIndexAttribute.array as Uint32Array;\n const draw = this.splatIndexAttribute.array as Float32Array;\n if (this.drawListSorted) {\n // The draw list holds a depth permutation; a slot-wise patch (or a\n // bare instanceCount truncation on removal, count === 0 here) would\n // draw removed splats twice and drop live ones until the worker's\n // next order arrives. Resync the whole drawn prefix to the identity\n // active order instead - one frame unsorted beats frames of garbage.\n // Later mutations in the same tick take the cheap patch path below.\n draw.set(source.subarray(0, this.activeCount));\n if (this.activeCount > 0) {\n addMergedUpdateRange(this.splatIndexAttribute, 0, this.activeCount);\n }\n this.splatIndexAttribute.needsUpdate = true;\n this.drawListSorted = false;\n } else if (count > 0) {\n draw.set(source.subarray(start, start + count), start);\n addMergedUpdateRange(this.splatIndexAttribute, start, count);\n this.splatIndexAttribute.needsUpdate = true;\n }\n }\n (this.geometry as THREE.InstancedBufferGeometry).instanceCount = this.activeCount;\n this.activeListVersion++;\n this.sortScheduler.invalidateContent();\n }\n\n /** Rewrites the active-splat list (pool indices, range by range). */\n private rebuildActiveList(): void {\n const source = this.sourceIndexAttribute.array as Uint32Array;\n const identity = this.getPoolIndexTemplate();\n let cursor = 0;\n for (const record of this.ranges.values()) {\n if (!record.active) continue;\n // Honor a partial activation: only the used prefix of a page-table slab\n // participates (matching activateRecord), never the whole allocation.\n const count = record.activePrefix ?? record.count;\n source.set(identity.subarray(record.start, record.start + count), cursor);\n this.activeSlotByPoolIndex.set(identity.subarray(cursor, cursor + count), record.start);\n cursor += count;\n }\n this.activeCount = cursor;\n this.sourceIndexAttribute.clearUpdateRanges();\n if (cursor > 0) this.sourceIndexAttribute.addUpdateRange(0, cursor);\n this.sourceIndexAttribute.needsUpdate = true;\n\n // Without a GPU sorter the draw list must hold the active pool indices\n // itself, or the first instances would render pool slots 0..n-1\n // regardless of where the active ranges live. The CPU sorter then\n // replaces this identity order asynchronously.\n if (this.sorter?.kind === 'worker' || this.sorter === null) {\n const draw = this.splatIndexAttribute.array as Float32Array;\n draw.set(source.subarray(0, cursor));\n this.splatIndexAttribute.clearUpdateRanges();\n if (cursor > 0) this.splatIndexAttribute.addUpdateRange(0, cursor);\n this.splatIndexAttribute.needsUpdate = true;\n this.drawListSorted = false;\n }\n (this.geometry as THREE.InstancedBufferGeometry).instanceCount = cursor;\n\n // Pool-index changes invalidate the current draw order. Force the next\n // sort instead of displaying a stale permutation during a streaming swap.\n this.activeListVersion++;\n this.sortScheduler.invalidateContent();\n }\n\n /** The pool's reusable index ramp; shared by every mesh drawing from it. */\n private getPoolIndexTemplate(): Uint32Array {\n return this.pool.indexTemplate();\n }\n\n /**\n * Uploads rows written since the last flush by copying only those rows\n * through a staging texture. (Constructor-time writes never appear here;\n * they ride the textures' initial full upload instead.)\n */\n private flushPendingUploads(renderer: THREE.WebGPURenderer): void {\n // The four core pool textures share one dirty-row set (they are written\n // together), each RGBA (4 components).\n if (this.pendingUploadRows.length > 0) {\n const floatType =\n this.poolFloatTextures === 'float16' ? THREE.HalfFloatType : THREE.FloatType;\n this.uploadRows(renderer, this.pendingUploadRows, THREE.RGBAFormat, 4, [\n {\n key: 'centers',\n texture: this.dataTextures[0] as THREE.DataTexture,\n data: this.backing.centers,\n type: floatType,\n encodeHalf: this.poolFloatTextures === 'float16',\n },\n {\n key: 'colors',\n texture: this.dataTextures[1] as THREE.DataTexture,\n data: this.backing.colors,\n type: THREE.UnsignedByteType,\n },\n {\n key: 'covarianceA',\n texture: this.dataTextures[2] as THREE.DataTexture,\n data: this.backing.covarianceA,\n type: floatType,\n encodeHalf: this.poolFloatTextures === 'float16',\n },\n {\n key: 'covarianceB',\n texture: this.dataTextures[3] as THREE.DataTexture,\n data: this.backing.covarianceB,\n type: THREE.FloatType,\n },\n ]);\n // Packed SH is written by the same calls and so shares those dirty\n // rows, but it is an integer format and cannot ride the same copy.\n if (this.shPackedTextures.length > 0) {\n this.uploadRows(\n renderer,\n this.pendingUploadRows,\n THREE.RGBAIntegerFormat,\n 4,\n this.shPackedTextures.map((texture, group) => ({\n key: `shPacked${group}`,\n texture,\n data: this.backing.shPacked[group] as Uint32Array,\n type: THREE.UnsignedIntType,\n })),\n );\n }\n this.pendingUploadRows = [];\n }\n // Each channel is single-component (Red) and tracks its own dirty rows.\n for (const [name, channel] of this.channels.entries()) {\n if (channel.pendingRows.length === 0) continue;\n this.uploadRows(renderer, channel.pendingRows, THREE.RedFormat, 1, [\n {\n key: `channel:${name}`,\n texture: channel.texture,\n data: channel.backing,\n type: channel.textureType,\n },\n ]);\n channel.pendingRows = [];\n }\n }\n\n /**\n * Packs float32 CPU backing into the half GPU images for centers/covA.\n * Used once after a static constructor write so the initial `needsUpdate`\n * upload carries half bits (staging is skipped for that path).\n */\n private syncHalfFloatPoolImages(): void {\n const centersTex = this.dataTextures[0] as THREE.DataTexture;\n const covATex = this.dataTextures[2] as THREE.DataTexture;\n const centersImg = centersTex.image.data as Uint16Array;\n const covAImg = covATex.image.data as Uint16Array;\n encodeFloat32ToHalf(this.backing.centers, centersImg);\n encodeFloat32ToHalf(this.backing.covarianceA, covAImg);\n centersTex.needsUpdate = true;\n covATex.needsUpdate = true;\n }\n\n /**\n * Uploads the given row spans of one or more same-layout pool textures via\n * per-region staging copies. Spans are merged first so consecutive appends\n * upload as one rectangle each - the copyTextureToTexture call count, not\n * the pixel volume, dominates.\n */\n private uploadRows(\n renderer: THREE.WebGPURenderer,\n rows: { start: number; count: number }[],\n format: THREE.PixelFormat,\n components: number,\n entries: {\n key: string;\n texture: THREE.DataTexture;\n data: Float32Array | Uint8Array | Uint32Array;\n type: THREE.TextureDataType;\n /** When set, `data` is float32 backing encoded to half bits for staging. */\n encodeHalf?: boolean;\n }[],\n ): void {\n const width = SplatMesh.DATA_TEXTURE_WIDTH;\n // Sorting in place is safe: every caller discards its pending-rows list\n // right after the flush, and re-passing an already-sorted list is a no-op.\n const regions = rows.sort((a, b) => a.start - b.start);\n const merged: { start: number; count: number }[] = [];\n for (const region of regions) {\n const last = merged[merged.length - 1];\n if (last && region.start <= last.start + last.count) {\n last.count = Math.max(last.count, region.start + region.count - last.start);\n } else {\n merged.push({ start: region.start, count: region.count });\n }\n }\n for (const region of merged) {\n for (const { key, texture, data, type, encodeHalf } of entries) {\n const view = data.subarray(\n region.start * width * components,\n (region.start + region.count) * width * components,\n );\n let stagingData: Float32Array | Uint8Array | Uint32Array | Uint16Array = view;\n if (encodeHalf) {\n const half = this.acquireHalfEncodeBuffer(key, view.length);\n encodeFloat32ToHalf(view as Float32Array, half, 0, view.length);\n stagingData = half;\n }\n const staging = this.acquireUploadStaging(\n key,\n stagingData,\n width,\n region.count,\n format,\n type,\n );\n renderer.copyTextureToTexture(staging, texture, null, _uploadPosition.set(0, region.start));\n }\n }\n }\n\n /** Reuses a same-length half encode buffer for one staging key. */\n private acquireHalfEncodeBuffer(key: string, length: number): Uint16Array {\n const existing = this.halfEncodeBuffers.get(key);\n if (existing && existing.length === length) return existing;\n const buffer = new Uint16Array(length);\n this.halfEncodeBuffers.set(key, buffer);\n return buffer;\n }\n\n /**\n * Reuses one of the recent same-sized staging textures for this upload. WebGPU\n * texture dimensions are immutable, so each cached entry remains exact-sized. Keeping\n * a small LRU per channel avoids recreating all core/SH staging resources when\n * a stream alternates among a few chunk heights, while bounding GPU memory.\n */\n private acquireUploadStaging(\n key: string,\n data: Float32Array | Uint8Array | Uint32Array | Uint16Array,\n width: number,\n height: number,\n format: THREE.PixelFormat,\n type: THREE.TextureDataType,\n ): THREE.DataTexture {\n let cache = this.uploadStaging.get(key);\n if (!cache) {\n cache = new Map();\n this.uploadStaging.set(key, cache);\n }\n const existing = cache.get(height);\n if (existing) {\n existing.image = { data, width, height };\n existing.needsUpdate = true;\n // Map insertion order supplies a tiny LRU without another allocation.\n cache.delete(height);\n cache.set(height, existing);\n return existing;\n }\n const texture = new THREE.DataTexture(data, width, height, format, type);\n // An integer texture cannot be filtered; a staging texture that says\n // otherwise is rejected when its GPU descriptor is built.\n if (format === THREE.RGBAIntegerFormat) {\n texture.magFilter = THREE.NearestFilter;\n texture.minFilter = THREE.NearestFilter;\n }\n texture.needsUpdate = true;\n cache.set(height, texture);\n if (cache.size > UPLOAD_STAGING_CACHE_SIZE) {\n const oldestHeight = cache.keys().next().value as number;\n cache.get(oldestHeight)?.dispose();\n cache.delete(oldestHeight);\n }\n this.updateTimings.stagingTextureAllocations++;\n return texture;\n }\n\n /** Gathers everything the material graph reads. See `splat-mesh-material.ts`. */\n private graphInputs(\n textures: SplatMaterialTextures,\n sh: SplatShInputs | null,\n ): SplatMaterialBuildInputs {\n return {\n textures,\n sh,\n sourcePlacement: this.perSourceSort,\n // The uniform node instances, shared with the pick graph on purpose: one\n // per-frame write then reaches both.\n uniforms: {\n focal: this.focal,\n viewport: this.viewport,\n localCameraPosition: this.localCameraPosition,\n pixelScaleLimit: this.pixelScaleLimit,\n dofFocusDistance: this.dofFocusDistance,\n dofAperture: this.dofAperture,\n screenBandMin: this.screenBandMin,\n screenBandMax: this.screenBandMax,\n relightMap: this.relightMap,\n relightBlend: this.relightBlend,\n relightBrightness: this.relightBrightness,\n relightBackground: this.relightBackground,\n relightSoftness: this.relightSoftness,\n },\n pick: this.picker.uniforms,\n settings: {\n maxStdDev: this.maxStdDev,\n minSplatSizePx: this.minSplatSizePx,\n antialias: this.antialias,\n projectedFilterProfile: this.projectedFilterProfile,\n srgbOutput: this.srgbOutput,\n performanceProfile: this.performanceProfileValue,\n maxScreenRadiusPx: this.maxSplatScreenRadius,\n minScreenRadiusPx: this.minSplatScreenRadius,\n foveationMode: this.foveationMode,\n maxAspect: this.maxSplatAspect,\n lodAlpha: this.lodAlpha,\n },\n // The live map: a rebuild after defineChannel must see the new entry.\n channels: this.channels,\n modifiers: this.modifierList,\n };\n }\n\n private buildMaterial(textures: SplatMaterialTextures, sh: SplatShInputs | null): void {\n applySplatMaterialGraph(\n this.material as THREE.NodeMaterial,\n 'display',\n this.graphInputs(textures, sh),\n );\n // Keeps the two graphs in step; a no-op until the first pick builds one.\n this.picker.rebuildMaterial();\n }\n\n private requestSortIfNeeded(camera: THREE.Camera, renderer: THREE.WebGPURenderer): void {\n if (this.deferSortRequestOnce) {\n this.deferSortRequestOnce = false;\n // Only a frame whose draw list the current order still describes can be\n // skipped. A staged group asks for this drain frame before it commits,\n // but other swap groups apply within the same tick - and a sort skipped\n // over their mutation renders the new instance count against the old\n // permutation: removed splats linger and live ones vanish for a frame.\n // A foreign order (a secondary renderView's) never describes the primary\n // draw, so it can't be skipped over either.\n if (this.activeListVersion === this.sortedActiveListVersion && !this.orderIsForeign) return;\n }\n if (this.activeCount === 0) return;\n this.currentModelView.multiplyMatrices(camera.matrixWorldInverse, this.matrixWorld);\n this.writeSortState(camera);\n\n const isWebGPU = (renderer.backend as { isWebGPUBackend?: boolean }).isWebGPUBackend === true;\n const now = isWebGPU ? performance.now() : 0;\n // A secondary renderView left its own order in the shared buffer, so the\n // primary view must re-sort this frame however little its camera moved.\n if (!this.orderIsForeign) {\n if (isWebGPU) {\n if (\n !this.sortScheduler.shouldSubmit(\n this.currentSortState,\n this.lastSortedState,\n this.activeCount,\n now,\n )\n ) {\n return;\n }\n } else if (\n // WebGL2 has no cadence, but a content swap under a stationary camera\n // still invalidated the draw order (the swap reset it to unsorted\n // active order) - skipping here would leave the scene blend-order\n // broken until the camera next moved.\n !this.sortScheduler.hasPendingForce() &&\n this.currentSortState.equals(this.lastSortedState)\n ) {\n return;\n }\n }\n\n this.refreshSortBounds();\n\n this.sorter ??= this.createSorter(renderer);\n if (!this.sorter) return;\n if (this.sorter.sort(this.currentModelView, this.activeCount, this.boundingSphereLocal)) {\n this.lastSortedState.copy(this.currentSortState);\n this.sortedActiveListVersion = this.activeListVersion;\n this.orderIsForeign = false; // the buffer now holds the primary order again\n // On WebGL2 `now` is 0 - harmless, cadence timing is WebGPU-only; the\n // call still clears the pending-force flag consumed above.\n this.sortScheduler.markAccepted(now);\n }\n }\n\n /**\n * Refreshes {@link boundingSphereLocal} - the sphere the sorter quantizes\n * depth over - when {@link boundsDirty}. The base mesh uses its local splat\n * bounds; a unified {@link MergedSplatMesh} overrides this to supply a world-space\n * bound spanning all its sources (whose transforms live in the shader).\n */\n protected refreshSortBounds(): void {\n if (!this.boundsDirty) return;\n this.localBounds.getBoundingSphere(this.boundingSphereLocal);\n this.boundsDirty = false;\n }\n\n /** The data texture backing a channel defined with {@link defineChannel}. */\n protected channelTexture(name: string): THREE.DataTexture | undefined {\n return this.channels.get(name)?.texture;\n }\n\n /** CPU backing storage of a float channel, for internal CPU-side consumers. */\n protected channelBacking(name: string): Float32Array {\n const channel = this.channels.get(name);\n if (!channel || !(channel.backing instanceof Float32Array)) {\n throw new Error(`SplatMesh: float channel \"${name}\" is missing.`);\n }\n return channel.backing;\n }\n\n /**\n * Forces the next {@link update} to re-sort even if the camera has not moved\n * - used by a unified pool when a source's transform changes, since the depth\n * order then changes without any camera motion.\n */\n protected invalidateSort(): void {\n this.sortScheduler.invalidate();\n this.boundsDirty = true;\n }\n\n /**\n * Writes the camera/mesh state that can change the selected ordering key.\n * Radial distance is invariant under camera rotation, so its state contains\n * the mesh's world linear transform and camera-relative translation only.\n */\n private writeSortState(camera: THREE.Camera): void {\n if (this.sortMetric === 'depth') {\n this.currentSortState.copy(this.currentModelView);\n return;\n }\n radialSortState(this.matrixWorld, camera.matrixWorld, this.currentSortState);\n }\n\n private createSorter(renderer: THREE.WebGPURenderer): SplatSorter | null {\n const isWebGPU = (renderer.backend as { isWebGPUBackend?: boolean }).isWebGPUBackend === true;\n if (!isWebGPU || this.sortStrategy === 'worker') {\n return new WorkerSorter(\n {\n capacity: this.capacity,\n rowWidth: SplatMesh.DATA_TEXTURE_WIDTH,\n centers: this.backing.centers,\n perSource: this.perSourceSort\n ? {\n sourceIds: this.perSourceSort.sourceIds,\n matrices: this.perSourceSort.matrices,\n }\n : undefined,\n splatIndexAttribute: this.splatIndexAttribute,\n takeDirtyRows: () => {\n const rows = this.workerDirtyRows;\n this.workerDirtyRows = [];\n return rows;\n },\n getActiveSpans: () => {\n const spans = new Uint32Array(this.ranges.size * 2);\n let cursor = 0;\n for (const record of this.ranges.values()) {\n if (!record.active) continue;\n // The used prefix only (matching the active list): the full slab\n // count would make the worker sort - and the draw list render -\n // the inactive page-table tail in place of live splats.\n const count = record.activePrefix ?? record.count;\n if (count === 0) continue;\n spans[cursor++] = record.start;\n spans[cursor++] = count;\n }\n return spans.subarray(0, cursor);\n },\n onOrderApplied: () => {\n this.drawListSorted = true;\n },\n },\n this.sortMetric,\n );\n }\n const options = {\n renderer,\n capacity: this.poolRows * SplatMesh.DATA_TEXTURE_WIDTH,\n centersTexture: this.centersTexture,\n dataTextureWidth: SplatMesh.DATA_TEXTURE_WIDTH,\n splatIndexAttribute: this.splatIndexAttribute,\n sourceIndexAttribute: this.sourceIndexAttribute,\n };\n // A per-source world transform (unified pool) needs the counting sorter's\n // world-depth path; radix has no equivalent, so it is not offered there.\n if (this.perSourceSort) {\n return new ComputeSorter({\n ...options,\n perSource: this.perSourceSort,\n sortMetric: this.sortMetric,\n });\n }\n if (this.sortStrategy === 'radix' || this.sortStrategy === 'exact') {\n this.ensureRadixSorter();\n if (!this.RadixSorterCtor) return null; // skip until the module resolves\n return new this.RadixSorterCtor({\n ...options,\n exactDepth: this.sortStrategy === 'exact',\n sortMetric: this.sortMetric,\n });\n }\n return new ComputeSorter({ ...options, sortMetric: this.sortMetric });\n }\n\n /** Prefetches the experimental radix sorter; safe to call repeatedly. */\n private ensureRadixSorter(): void {\n if (this.RadixSorterCtor || this.radixSorterLoad) return;\n this.radixSorterLoad = import('./radix-sorter')\n .then((mod) => {\n this.RadixSorterCtor = mod.RadixSorter;\n })\n .finally(() => {\n this.radixSorterLoad = null;\n });\n }\n}\n\nconst _appendBox = new THREE.Box3();\nconst _uploadPosition = new THREE.Vector2();\nconst _queryLocal = new THREE.Vector3();\nconst _queryWorld = new THREE.Vector3();\nconst _queryScale = new THREE.Vector3();\nconst _viewSize = new THREE.Vector2();\nconst _camLocal = new THREE.Vector3();\nconst _adaptView = new THREE.Matrix4();\nconst _adaptMvp = new THREE.Matrix4();\n\n/** How often the adaptive frontier limit re-estimates the drawn count (ms). */\nconst FOVEATION_ADAPT_MS = 180;\n/** Sample every Nth pool slot when estimating the drawn count (a prime avoids\n * aliasing with the texture width). ~1/31 of the pool, throttled - a few ms. */\nconst FOVEATION_ADAPT_STRIDE = 31;\n/** Coarsest the adaptive limit may grow to (px), so a pathological view can't\n * drive the whole scene to a single blob. */\nconst FOVEATION_LIMIT_MAX_PX = 64;\n\n/**\n * Validates the public Gaussian cutoff override. `undefined` means \"no\n * override\", so the caller applies the device-aware default.\n */\nfunction validateMaxStdDev(value: number | undefined): number | undefined {\n if (value !== undefined && (!Number.isFinite(value) || value <= 0)) {\n throw new RangeError('SplatMesh maxStdDev must be a finite number greater than 0.');\n }\n return value;\n}\n\n/** A pixel floor of `0` disables it; negatives and non-finite values are errors. */\nfunction validateMinSplatSizePx(value: number | undefined): number | undefined {\n if (value !== undefined && (!Number.isFinite(value) || value < 0)) {\n throw new RangeError('SplatMesh minSplatSizePx must be a finite number >= 0.');\n }\n return value;\n}\n\n/** Validates a screen-radius cull override; `0`/unset both mean \"off\". */\nfunction validateMaxSplatScreenRadius(value: number | undefined): number {\n if (value === undefined) return 0;\n if (!Number.isFinite(value) || value < 0) {\n throw new RangeError('SplatMesh screen-radius cull must be a finite number ≥ 0.');\n }\n return value;\n}\n\n/** Default frontier-cut target size (px). Matches Spark's `lodRenderScale`\n * default of 1 - nodes refine until ~1 px on screen, so the draw budget (not a\n * coarser fixed cut) is what bounds detail. At the old value of 4 the cut\n * stopped ~2 LOD levels early everywhere the tree doesn't bottom out at\n * leaves, which made large-scale scenes visibly coarser than Spark. */\nexport const DEFAULT_FOVEATION_TARGET_PX = 1;\n\nfunction validateFoveationTargetPx(value: number | undefined): number {\n if (value === undefined) return DEFAULT_FOVEATION_TARGET_PX;\n if (!Number.isFinite(value) || value <= 0) {\n throw new RangeError('SplatMesh foveationTargetPx must be a finite number > 0.');\n }\n return value;\n}\n\n/** Default target for the frontier cut's drawn-splat count (Spark's `maxSplats`).\n * Coarsens the cut once the estimate exceeds it, keeping frame cost bounded. */\nexport const DEFAULT_FOVEATION_DRAW_BUDGET = 900_000;\n\nfunction validateFoveationDrawBudget(value: number | undefined): number {\n if (value === undefined) return DEFAULT_FOVEATION_DRAW_BUDGET;\n if (!Number.isFinite(value) || value <= 0) {\n throw new RangeError('SplatMesh foveationDrawBudget must be a finite number > 0.');\n }\n return value;\n}\n"],"names":["createYUpTransform","THREE","yUpTransformForFormat","format","WorkerSorter","host","sortMetric","__publicField","SortWorker","event","logError","init","modelView","_activeCount","_bounds","spans","message","rows","width","row","centers","start","count","sourceIds","_a","order","current","sent","i","indexes","_b","DEPTH_24_MAX","_ndc","_raycaster","_dirView","unpackNormalizedDepth","r","g","b","denormalizeViewDepth","normalized","near","far","unprojectViewDepth","ndcX","ndcY","viewDepth","camera","outPoint","t","SplatPicker","uniform","ndc","renderer","options","run","isXrArrayCamera","height","px","pyBottom","pickTarget","pickProxy","pickCamera","mesh","previousTarget","previousScissorTest","previousClearAlpha","previousAutoClear","readback","rgba","error","point","distance","target","source","projection","elements","xOffset","yOffset","column","rowW","MAX_DIM","MAX_CELLS","UniformGrid","poolIndices","lo","hi","base","a","v","size","nonZero","s","spanProduct","cell","chooseDims","cellEdge","cellCount","counts","c","cursor","p","ix","iy","value","x","y","z","radius","visit","r2","q","span","iz","rowBase","from","to","k","dx","dy","dz","d2","bestIndex","bestSq","UPLOAD_STAGING_CACHE_SIZE","_SplatMesh","sortIntervalMs","validateSortIntervalMs","isMobile","detectSplatDeviceProfile","maxStdDev","validateMaxStdDev","minSplatSizePx","validateMinSplatSizePx","isStatic","capacity","staticShWanted","resolveSplatPerformanceProfile","MAX_SH_BANDS","packedShBands","suppliedPool","makeOwnPool","SplatPool","shCoefficientCount","shMismatch","warn","ownsPool","pool","texelCount","centersTexture","colorsTexture","covarianceATexture","covarianceBTexture","shPaletteTexture","createDataTexture","shPackedTextures","geometry","splatIndexes","splatIndexAttribute","createPlaceholderRelightTexture","DEFAULT_RELIGHT_BRIGHTNESS","DEFAULT_RELIGHT_BACKGROUND","DEFAULT_RELIGHT_SOFTNESS","material","applySplatMaterialGraph","WebGpuSortScheduler","validateMaxSplatScreenRadius","resolveSplatFoveationMode","validateFoveationTargetPx","validateFoveationDrawBudget","vec3Uniform","correction","profile","next","data","empty","rowCount","startRow","allocateRowSpan","handle","channel","offset","record","destination","firstRow","lastRow","_appendBox","colors","covarianceA","covarianceB","positions","covariances","labels","frontierParent","p3","p6","groups","wanted","requantize","packedRangesEqual","word","requantizeShWord","neutral","group","min","max","range","neutralShWordFor","method","active","prefix","indices","slot","poolIndex","previousCount","index","releaseRowSpan","cached","visible","name","type","backing","fill","textureType","texture","first","endRow","modifier","previous","settings","clampDepthOfFieldSettings","clampRelightingSettings","minPx","maxPx","targetRow","cFrom","cTo","cLength","uploadStartedAt","xrView","resolveXrView","projectionCamera","sortCamera","viewWidth","viewHeight","_viewSize","sortStartedAt","maxSize","deviceMaxTextureSize","worldPoint","_queryLocal","grid","gather","_queryWorld","ray","radiusAtUnitDistance","minimumRadius","bestDistance","maxDrop","gatherLocal","bestY","drop","sorted","out","_queryScale","cache","releaseRendererAttributes","viewportX","viewportY","positionCamera","focalY","now","FOVEATION_ADAPT_MS","limit","_camLocal","_adaptView","_adaptMvp","m","cA","cB","slots","sampled","drawn","FOVEATION_ADAPT_STRIDE","packedParent","cx","cy","cz","margin","clipX","clipY","trace","ownSize","isLeaf","parentSize","limitDist","ownCut","estimatedDrawn","budget","FOVEATION_LIMIT_MAX_PX","identity","activeStart","activeLen","firstSlot","contiguous","dirtyStart","dirtyEnd","nextActiveCount","copyCount","movedPoolIndex","lastSlot","addMergedUpdateRange","draw","floatType","centersTex","covATex","centersImg","covAImg","encodeFloat32ToHalf","components","entries","regions","merged","region","last","key","encodeHalf","view","stagingData","half","staging","_uploadPosition","length","existing","buffer","oldestHeight","textures","sh","isWebGPU","radialSortState","ComputeSorter","mod","SPLAT_DATA_TEXTURE_WIDTH","SplatMesh","DEFAULT_FOVEATION_TARGET_PX","DEFAULT_FOVEATION_DRAW_BUDGET"],"mappings":"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"}
|