@voluma/vlam 0.2.4 → 0.3.2
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/README.md +3 -4
- package/dist/chunk-loader-DlNwggfG.js +1859 -0
- package/dist/chunk-loader-DlNwggfG.js.map +1 -0
- package/dist/{compute-sorter.d.ts → core/compute-sorter.d.ts} +1 -1
- package/dist/core/index.d.ts +45 -0
- package/dist/{splat-scene.d.ts → core/merged-splat-mesh.d.ts} +14 -15
- package/dist/{orientation.d.ts → core/orientation.d.ts} +7 -7
- package/dist/{relighting.d.ts → core/relighting.d.ts} +1 -1
- package/dist/{source-transform.d.ts → core/source-transform.d.ts} +4 -4
- package/dist/{splat-budget.d.ts → core/splat-budget.d.ts} +2 -2
- package/dist/{splat-data.d.ts → core/splat-data.d.ts} +4 -4
- package/dist/{splat-mesh-material.d.ts → core/splat-mesh-material.d.ts} +2 -2
- package/dist/{splat-mesh-types.d.ts → core/splat-mesh-types.d.ts} +19 -10
- package/dist/{splat-mesh.d.ts → core/splat-mesh.d.ts} +4 -4
- package/dist/{splat-modifier.d.ts → core/splat-modifier.d.ts} +5 -5
- package/dist/{webgpu-limits.d.ts → core/webgpu-limits.d.ts} +0 -59
- package/dist/{effects.d.ts → effects/index.d.ts} +14 -13
- package/dist/effects.js.map +1 -1
- package/dist/formats/ksplat/index.d.ts +1 -1
- package/dist/formats/ksplat/parse-ksplat.d.ts +1 -1
- package/dist/formats/ksplat.js.map +1 -1
- package/dist/formats/lcc/collision-mesh.d.ts +3 -3
- package/dist/formats/lcc/collision-partition.d.ts +1 -1
- package/dist/formats/lcc/lcc.d.ts +3 -3
- package/dist/formats/lcc/lcc2.d.ts +2 -2
- package/dist/formats/lcc/parse-lcc.d.ts +1 -1
- package/dist/formats/lcc.js +17 -16
- package/dist/formats/lcc.js.map +1 -1
- package/dist/formats/ply/index.d.ts +1 -1
- package/dist/formats/ply/parse-compressed-ply.d.ts +2 -2
- package/dist/formats/ply/parse-splat-ply.d.ts +4 -4
- package/dist/formats/ply.js +1 -1
- package/dist/formats/ply.js.map +1 -1
- package/dist/formats/rad/frontier-worker-protocol.d.ts +8 -1
- package/dist/formats/rad/index.d.ts +2 -2
- package/dist/formats/rad/parse-rad.d.ts +2 -2
- package/dist/formats/rad/rad-foveated-source.d.ts +3 -3
- package/dist/formats/rad/rad.d.ts +7 -7
- package/dist/formats/rad.js +3 -3
- package/dist/formats/rad.js.map +1 -1
- package/dist/formats/sog/index.d.ts +1 -1
- package/dist/formats/sog/parse-sog.d.ts +6 -6
- package/dist/formats/sog.js.map +1 -1
- package/dist/formats/splat/index.d.ts +1 -1
- package/dist/formats/splat/parse-splat.d.ts +1 -1
- package/dist/formats/splat.js.map +1 -1
- package/dist/formats/spz/index.d.ts +1 -1
- package/dist/formats/spz/parse-spz.d.ts +1 -1
- package/dist/formats/spz.js.map +1 -1
- package/dist/half-float-Cs4FDq8Q.js.map +1 -1
- package/dist/index.js +253 -9047
- package/dist/index.js.map +1 -1
- package/dist/{chunk-loader.d.ts → loaders/chunk-loader.d.ts} +4 -4
- package/dist/loaders/index.d.ts +15 -0
- package/dist/{load-scene.d.ts → loaders/load-splat-data.d.ts} +16 -14
- package/dist/{load-worker-protocol.d.ts → loaders/load-worker-protocol.d.ts} +2 -2
- package/dist/{loading.d.ts → loaders/loading.d.ts} +8 -8
- package/dist/loaders.js +26 -0
- package/dist/loaders.js.map +1 -0
- package/dist/loading-wLo8vRbA.js.map +1 -1
- package/dist/{splat-mesh-types-CTN_duw2.js → lod-scheduler-B0a_uBlv.js} +133 -140
- package/dist/lod-scheduler-B0a_uBlv.js.map +1 -0
- package/dist/logging-BfPdd7NJ.js.map +1 -1
- package/dist/{ply-header-BwgExCn-.js → ply-header-B9WllbPg.js} +3 -3
- package/dist/ply-header-B9WllbPg.js.map +1 -0
- package/dist/radix-sorter-BrbUg_CV.js +178 -0
- package/dist/radix-sorter-BrbUg_CV.js.map +1 -0
- package/dist/relighting-Tiwep8yd.js +977 -0
- package/dist/relighting-Tiwep8yd.js.map +1 -0
- package/dist/selection/index.d.ts +13 -0
- package/dist/{selection-volume.d.ts → selection/selection-volume.d.ts} +1 -1
- package/dist/{splat-partition.d.ts → selection/splat-partition.d.ts} +2 -2
- package/dist/selection.js +137 -0
- package/dist/selection.js.map +1 -0
- package/dist/sh-pack-D5wAe5gg.js.map +1 -1
- package/dist/{splat-budget-DXew_86c.js → splat-budget-DuVZspPQ.js} +7 -7
- package/dist/splat-budget-DuVZspPQ.js.map +1 -0
- package/dist/splat-data-BZM5dhhx.js.map +1 -1
- package/dist/splat-mesh-CsLOQb08.js +1942 -0
- package/dist/splat-mesh-CsLOQb08.js.map +1 -0
- package/dist/splat-mesh-types-BZIko-_9.js +18 -0
- package/dist/splat-mesh-types-BZIko-_9.js.map +1 -0
- package/dist/static-lod/index.d.ts +12 -0
- package/dist/{static-lod-splat-mesh.d.ts → static-lod/static-lod-splat-mesh.d.ts} +3 -3
- package/dist/{static-lod-worker-protocol.d.ts → static-lod/static-lod-worker-protocol.d.ts} +1 -1
- package/dist/{static-lod.d.ts → static-lod/static-lod.d.ts} +1 -1
- package/dist/{static-lod-worker-D2fyqQZO.js → static-lod-worker-DktKnJkR.js} +46 -46
- package/dist/{static-lod-worker-D2fyqQZO.js.map → static-lod-worker-DktKnJkR.js.map} +1 -1
- package/dist/static-lod.js +148 -0
- package/dist/static-lod.js.map +1 -0
- package/dist/{budget-governor.d.ts → streaming/budget-governor.d.ts} +4 -4
- package/dist/{camera-budget-governor.d.ts → streaming/camera-budget-governor.d.ts} +11 -11
- package/dist/{chunk-cache-budget.d.ts → streaming/chunk-cache-budget.d.ts} +5 -5
- package/dist/{chunk-fetch-scheduler.d.ts → streaming/chunk-fetch-scheduler.d.ts} +4 -4
- package/dist/{dataset-source.d.ts → streaming/dataset-source.d.ts} +1 -1
- package/dist/streaming/index.d.ts +23 -0
- package/dist/{lod-scheduler.d.ts → streaming/lod-scheduler.d.ts} +1 -1
- package/dist/{lod-source.d.ts → streaming/lod-source.d.ts} +9 -9
- package/dist/{streamed-splat-mesh-utils.d.ts → streaming/streamed-splat-mesh-utils.d.ts} +2 -2
- package/dist/{streamed-splat-mesh.d.ts → streaming/streamed-splat-mesh.d.ts} +66 -32
- package/dist/streaming.js +2911 -0
- package/dist/streaming.js.map +1 -0
- package/dist/unified/index.d.ts +11 -0
- package/dist/{unified-splat-renderer.d.ts → unified/unified-splat-mesh.d.ts} +23 -16
- package/dist/unified/unified-work-buffer.d.ts +66 -0
- package/dist/{work-buffer-gather.d.ts → unified/work-buffer-gather.d.ts} +6 -6
- package/dist/{work-buffer-material.d.ts → unified/work-buffer-material.d.ts} +1 -1
- package/dist/unified.js +746 -0
- package/dist/unified.js.map +1 -0
- package/dist/webgpu-limits-Y3CI_6_6.js +43 -0
- package/dist/webgpu-limits-Y3CI_6_6.js.map +1 -0
- package/package.json +27 -7
- package/dist/index.d.ts +0 -54
- package/dist/ply-header-BwgExCn-.js.map +0 -1
- package/dist/splat-budget-DXew_86c.js.map +0 -1
- package/dist/splat-mesh-types-CTN_duw2.js.map +0 -1
- /package/dist/{create-splat-renderer.d.ts → core/create-splat-renderer.d.ts} +0 -0
- /package/dist/{depth-of-field.d.ts → core/depth-of-field.d.ts} +0 -0
- /package/dist/{half-float.d.ts → core/half-float.d.ts} +0 -0
- /package/dist/{logging.d.ts → core/logging.d.ts} +0 -0
- /package/dist/{radix-sort.d.ts → core/radix-sort.d.ts} +0 -0
- /package/dist/{radix-sorter.d.ts → core/radix-sorter.d.ts} +0 -0
- /package/dist/{relighting-pass.d.ts → core/relighting-pass.d.ts} +0 -0
- /package/dist/{sh-pack.d.ts → core/sh-pack.d.ts} +0 -0
- /package/dist/{sort-scheduler.d.ts → core/sort-scheduler.d.ts} +0 -0
- /package/dist/{sort-worker-protocol.d.ts → core/sort-worker-protocol.d.ts} +0 -0
- /package/dist/{sorter.d.ts → core/sorter.d.ts} +0 -0
- /package/dist/{splat-depth-pack.d.ts → core/splat-depth-pack.d.ts} +0 -0
- /package/dist/{splat-mesh-picking.d.ts → core/splat-mesh-picking.d.ts} +0 -0
- /package/dist/{splat-mesh-pool.d.ts → core/splat-mesh-pool.d.ts} +0 -0
- /package/dist/{splat-modifier-stack.d.ts → core/splat-modifier-stack.d.ts} +0 -0
- /package/dist/{splat-query.d.ts → core/splat-query.d.ts} +0 -0
- /package/dist/{splat-sort-bounds.d.ts → core/splat-sort-bounds.d.ts} +0 -0
- /package/dist/{storage-attribute-mirror.d.ts → core/storage-attribute-mirror.d.ts} +0 -0
- /package/dist/{worker-sorter.d.ts → core/worker-sorter.d.ts} +0 -0
- /package/dist/{xr-view.d.ts → core/xr-view.d.ts} +0 -0
- /package/dist/{ply-header.d.ts → loaders/ply-header.d.ts} +0 -0
- /package/dist/{lod-manifest.d.ts → streaming/lod-manifest.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-loader-DlNwggfG.js","sources":["../src/lib/loaders/chunk-loader.ts"],"sourcesContent":["import type { SplatData } from '../core/splat-data';\nimport type {\n LoadWorkerRequest,\n LoadWorkerResponse,\n LoadWorkerSource,\n RadChunkRangeRequest,\n} from './load-worker-protocol';\nimport type { LccChunkParams } from '../formats/lcc/parse-lcc';\nimport {\n createAbortError,\n deserializeSplatLoadError,\n resolveSplatUrl,\n SplatLoadError,\n splatFormatForExtension,\n splatNameExtension,\n splatUrlExtension,\n type ChunkFileFormat,\n type SplatDataFileLoadOptions,\n type SplatFormat,\n type SplatInputOptions,\n type SplatDataFormat,\n type SplatProgressCallback,\n} from './loading';\n// Inlined worker (blob URL): survives library bundling in any consumer\n// setup, unlike an asset file referenced via `new URL(...)`.\nimport LoadWorker from './load-worker?worker&inline';\n\n/**\n * Formats served by the one-shot worker rather than the streaming one.\n *\n * Both workers are inlined, so their parsers are string literals no bundler can\n * tree-shake. Keeping these three behind a dynamic import is what moves SPZ's\n * ~39 KB ZSTD wasm blob out of the main entry and into a chunk that loads only\n * when one of these formats is actually opened.\n */\nconst ONE_SHOT_FORMATS = new Set<ChunkFileFormat>(['spz', 'splat', 'ksplat']);\n\n/**\n * One worker plus the requests in flight on it.\n *\n * `ChunkLoader` runs two of these - see {@link ChunkLoader} - so the request\n * bookkeeping, cancellation and terminal-failure handling live here once.\n */\nclass WorkerClient {\n private nextRequestId = 0;\n private readonly pending = new Map<\n number,\n {\n resolve: (data: SplatData) => void;\n reject: (error: Error) => void;\n removeAbortListener?: () => void;\n onProgress?: SplatProgressCallback;\n }\n >();\n private disposed = false;\n /** Terminal worker failure; subsequent loads reject instead of hanging. */\n private workerFailure: SplatLoadError | null = null;\n\n constructor(private readonly worker: Worker) {\n this.worker.onmessage = (event: MessageEvent<LoadWorkerResponse>) => {\n const request = this.pending.get(event.data.id);\n if (!request) return;\n if (event.data.type === 'progress') {\n // Progress does not settle the request; the result still follows.\n request.onProgress?.(event.data.loaded, event.data.total);\n return;\n }\n this.pending.delete(event.data.id);\n request.removeAbortListener?.();\n if (event.data.ok) {\n request.resolve(event.data.data);\n } else if (event.data.cancelled) {\n request.reject(createAbortError('Chunk load was cancelled.'));\n } else {\n request.reject(deserializeSplatLoadError(event.data.error));\n }\n };\n // A worker-level failure (a CSP that blocks blob: workers is the common\n // one in real deployments) must still honour the documented contract:\n // every rejection is a SplatLoadError or an AbortError, never a bare Error.\n // There is no per-request URL here - the worker itself died - so `url` is\n // empty and the failure is not retryable: retrying constructs the same\n // worker under the same policy.\n this.worker.onerror = (event?: ErrorEvent | Event) => {\n if (this.workerFailure) return;\n const detail =\n event &&\n typeof event === 'object' &&\n 'message' in event &&\n typeof event.message === 'string'\n ? event.message\n : '';\n const failure = new SplatLoadError(\n detail ? `Chunk loading worker failed. ${detail}` : 'Chunk loading worker failed.',\n { phase: 'worker', url: '', retryable: false },\n );\n this.workerFailure = failure;\n this.worker.terminate();\n this.rejectAll(failure);\n };\n }\n\n /** Posts one load to this worker and tracks its pending promise. */\n request(\n message: Omit<Extract<LoadWorkerRequest, { type: 'load' }>, 'id'>,\n signal: AbortSignal | undefined,\n onProgress?: SplatProgressCallback,\n ): Promise<SplatData> {\n if (this.disposed) return Promise.reject(createAbortError('ChunkLoader has been disposed.'));\n if (signal?.aborted) return Promise.reject(createAbortError('Chunk load was cancelled.'));\n if (this.workerFailure) return Promise.reject(this.workerFailure);\n\n const id = this.nextRequestId++;\n const promise = new Promise<SplatData>((resolve, reject) => {\n this.pending.set(id, { resolve, reject, ...(onProgress ? { onProgress } : {}) });\n });\n if (signal) {\n // Settle immediately on abort rather than waiting for the worker's\n // acknowledgement: the worker may be deep in a decode (or may already\n // have posted a success that is still in the message queue), and a\n // caller that cancelled must neither receive that stale result nor see\n // further progress callbacks. The late reply finds no pending entry and\n // is dropped in `onmessage`.\n const onAbort = () => {\n const pending = this.pending.get(id);\n if (!pending) return;\n this.pending.delete(id);\n const cancel: LoadWorkerRequest = { type: 'cancel', id };\n if (!this.disposed) this.worker.postMessage(cancel);\n pending.reject(createAbortError('Chunk load was cancelled.'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n const pending = this.pending.get(id);\n if (pending) pending.removeAbortListener = () => signal.removeEventListener('abort', onAbort);\n }\n\n const request: LoadWorkerRequest = { ...message, id };\n this.worker.postMessage(request);\n return promise;\n }\n\n /** Terminates this worker and rejects its in-flight requests. */\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.worker.terminate();\n this.rejectAll(createAbortError('ChunkLoader has been disposed.'));\n }\n\n private rejectAll(error: Error): void {\n for (const request of this.pending.values()) {\n request.removeAbortListener?.();\n request.reject(error);\n }\n this.pending.clear();\n }\n}\n\n/**\n * Client for the persistent scene/chunk loading workers. Multiple requests\n * may be in flight; each can be cancelled through an `AbortSignal`, which\n * aborts the worker-side fetches (useful when the camera has moved on\n * before a chunk arrived).\n *\n * There are two workers behind this one class. The streaming worker is\n * constructed eagerly and handles everything the LOD paths need; the one-shot\n * worker ({@link ONE_SHOT_FORMATS}) is constructed the first time a `.spz`,\n * `.splat` or `.ksplat` is requested. Both decode off the main thread - the\n * split exists only to keep the one-shot parsers out of the published entry.\n *\n * @example\n * const loader = new ChunkLoader();\n * const chunk = await loader.load('/scene/0_0/', { kind: 'directory' });\n */\nexport class ChunkLoader {\n private readonly streaming = new WorkerClient(new LoadWorker());\n /** The in-flight construction; `null` until a one-shot format is requested. */\n private oneShot: Promise<WorkerClient> | null = null;\n /** The constructed one-shot client, so `dispose` does not have to await. */\n private oneShotClient: WorkerClient | null = null;\n private disposed = false;\n\n /**\n * Fetches and decodes one scene file or chunk directory.\n *\n * @param url - Scene URL, absolute or relative to the page.\n * @param options.kind - 'file' (default) selects a parser by extension;\n * 'directory' decodes an unbundled SOG chunk directory.\n * @param options.format - Explicit parser; `lcc-bin` additionally needs\n * `options.lcc` to say which byte range of the file to fetch.\n * @param options.signal - Abort signal for cancellation; the returned\n * promise then rejects with a `DOMException` named `AbortError`.\n * @param options.lcc - Byte-range plumbing for `lcc-bin`. This path exists\n * for {@link StreamedSplatMesh} and is **not** part of the stable surface;\n * the type is nameable as `LccChunkParams` on `@voluma/vlam/formats/lcc`.\n * @param options.rad - Byte-range plumbing for `rad-chunk`, on the same\n * footing; the type is `RadChunkRangeRequest` on `@voluma/vlam/formats/rad`.\n * @throws Rejects only with {@link SplatLoadError} (resolve, fetch, decode or\n * worker failures - `error.phase` says which; a worker that cannot start at\n * all, e.g. under a CSP that blocks `blob:` workers, reports\n * `phase: 'worker'`) or an `Error` named `AbortError` (cancellation or\n * {@link dispose}).\n */\n // `async` so a URL or format that will not resolve rejects the returned\n // promise rather than throwing synchronously into the caller.\n async load(\n url: string,\n options: SplatInputOptions & {\n kind?: 'file' | 'directory';\n format?: SplatFormat | 'lcc-bin' | 'rad-chunk';\n lcc?: LccChunkParams;\n rad?: RadChunkRangeRequest;\n sog?: { packShBands: 1 | 2 | 3 };\n files?: Readonly<Record<string, string>>;\n } = {},\n ): Promise<SplatData> {\n const kind = options.kind ?? 'file';\n // The worker runs from an inlined blob/data URL, where relative and\n // root-relative URLs cannot be resolved - make the URL absolute here.\n const absoluteUrl = resolveSplatUrl(url, options.baseUrl).href;\n const format = resolveFileFormat(absoluteUrl, kind, options.format ?? 'auto');\n const data = await this.request(\n {\n from: 'url',\n url: absoluteUrl,\n kind,\n ...(options.request ? { request: options.request } : {}),\n },\n format,\n options.signal,\n options.lcc,\n options.rad,\n options.files,\n options.sog,\n options.onProgress,\n );\n return withSourceFormat(data, format);\n }\n\n /**\n * Decodes a local file (from a file input or a drop) in the worker - the\n * bytes are read worker-side, so a multi-million-splat decode still never\n * blocks the main thread.\n *\n * Only self-contained files are supported: `.ply`, `.spz`, `.splat`,\n * `.ksplat` and bundled `.sog`. An unbundled SOG directory needs sibling\n * fetches and so requires {@link load} with `kind: 'directory'`.\n *\n * @param file - The file; its name selects the parser unless `format` is given.\n * @throws Rejects only with {@link SplatLoadError} (unknown extension, read\n * or decode failures) or an `Error` named `AbortError` (cancellation or\n * {@link dispose}).\n */\n // `async` so an unknown extension rejects the returned promise rather than\n // throwing synchronously into the caller.\n async loadFile(file: File, options: SplatDataFileLoadOptions = {}): Promise<SplatData> {\n const requested = options.format ?? 'auto';\n const format: Exclude<SplatFormat, 'auto'> =\n requested === 'auto'\n ? splatFormatForExtension(splatNameExtension(file.name), file.name)\n : requested;\n const data = await this.request(\n { from: 'file', file },\n format,\n options.signal,\n undefined,\n undefined,\n undefined,\n undefined,\n options.onProgress,\n );\n return withSourceFormat(data, format);\n }\n\n /** Routes one load to the worker that owns its format. */\n private request(\n source: LoadWorkerSource,\n format: ChunkFileFormat,\n signal: AbortSignal | undefined,\n lcc?: LccChunkParams,\n rad?: RadChunkRangeRequest,\n files?: Readonly<Record<string, string>>,\n sog?: { packShBands: 1 | 2 | 3 },\n onProgress?: SplatProgressCallback,\n ): Promise<SplatData> {\n if (this.disposed) return Promise.reject(createAbortError('ChunkLoader has been disposed.'));\n if (signal?.aborted) return Promise.reject(createAbortError('Chunk load was cancelled.'));\n\n const message: Omit<Extract<LoadWorkerRequest, { type: 'load' }>, 'id'> = {\n type: 'load',\n source,\n format,\n ...(lcc ? { lcc } : {}),\n ...(rad ? { rad } : {}),\n ...(sog ? { sog } : {}),\n ...(files ? { files } : {}),\n ...(onProgress ? { progress: true } : {}),\n };\n\n const client = this.clientFor(format);\n // Deliberately not `async`: for a streaming format the client is already\n // there, and the request must reach the worker in the same task the caller\n // made it - a chunk scheduler that posts and then aborts within one frame\n // depends on that ordering. Only the one-shot path, which cannot avoid\n // awaiting its chunk, defers.\n if (!(client instanceof Promise)) return client.request(message, signal, onProgress);\n return client.then((resolved) => {\n // Re-checked because disposal or abort may have happened while the\n // one-shot chunk was in flight, before any listener was registered.\n if (this.disposed) throw createAbortError('ChunkLoader has been disposed.');\n return resolved.request(message, signal, onProgress);\n });\n }\n\n /**\n * The worker for `format`, constructing the one-shot worker on first need.\n *\n * The in-flight promise is cached, not just the resolved client, so two\n * concurrent `.spz` loads share one worker instead of racing to build two.\n */\n private clientFor(format: ChunkFileFormat): WorkerClient | Promise<WorkerClient> {\n if (!ONE_SHOT_FORMATS.has(format)) return this.streaming;\n if (this.oneShotClient) return this.oneShotClient;\n this.oneShot ??= import('./one-shot-worker?worker&inline').then(\n ({ default: OneShotWorker }) => {\n const client = new WorkerClient(new OneShotWorker());\n this.oneShotClient = client;\n // `dispose()` may have run while the chunk was in flight; it could not\n // terminate a worker that did not exist yet, so honour it here.\n if (this.disposed) client.dispose();\n return client;\n },\n );\n return this.oneShot;\n }\n\n /** Terminates both workers and rejects all in-flight requests. */\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.streaming.dispose();\n // A one-shot worker still being imported is terminated in `clientFor`,\n // which sees `disposed` when it finally constructs it.\n this.oneShotClient?.dispose();\n }\n}\n\n/** Self-contained scene formats {@link SplatData.format} can hold. */\nconst SOURCE_FORMATS: readonly SplatDataFormat[] = ['ply', 'spz', 'splat', 'ksplat', 'sog', 'rad'];\n\n/**\n * Stamps the resolved format onto decoded scene data so {@link SplatMesh} can\n * pick its `orientation: 'y-up'` correction. Chunk-only formats (`lcc-bin`,\n * `rad-chunk`) carry no self-contained frame, so they are left unstamped.\n */\nfunction withSourceFormat(data: SplatData, format: ChunkFileFormat): SplatData {\n return (SOURCE_FORMATS as readonly string[]).includes(format)\n ? { ...data, format: format as SplatDataFormat }\n : data;\n}\n\nfunction resolveFileFormat(\n url: string,\n kind: 'file' | 'directory',\n format: SplatFormat | 'lcc-bin' | 'rad-chunk',\n): ChunkFileFormat {\n // An LCC or RAD chunk is a byte range of a shared file, so its extension says\n // nothing about the parser - the caller's choice is authoritative.\n if (format === 'lcc-bin' || format === 'rad-chunk') return format;\n if (kind === 'directory') return 'sog';\n if (format !== 'auto') return format;\n return splatFormatForExtension(splatUrlExtension(new URL(url)), url);\n}\n"],"names":["ONE_SHOT_FORMATS","WorkerClient","worker","__publicField","event","request","_a","_b","createAbortError","deserializeSplatLoadError","detail","failure","SplatLoadError","message","signal","onProgress","id","promise","resolve","reject","onAbort","pending","cancel","error","ChunkLoader","LoadWorker","url","options","kind","absoluteUrl","resolveSplatUrl","format","resolveFileFormat","data","withSourceFormat","file","requested","splatFormatForExtension","splatNameExtension","source","lcc","rad","files","sog","client","resolved","OneShotWorker","SOURCE_FORMATS","splatUrlExtension"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
|
|
@@ -2,7 +2,7 @@ import * as THREE from 'three/webgpu';
|
|
|
2
2
|
import type { SplatSorter } from './sorter';
|
|
3
3
|
import type { uniformArray } from 'three/tsl';
|
|
4
4
|
/**
|
|
5
|
-
* Optional per-source world transform for a unified {@link
|
|
5
|
+
* Optional per-source world transform for a unified {@link MergedSplatMesh} pool.
|
|
6
6
|
* When present, each splat's center is transformed to world space by its
|
|
7
7
|
* source's matrix (selected by a per-splat id read from `sourceIdTexture`)
|
|
8
8
|
* before its depth is computed, so clouds with different world transforms sort
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VLAM! | a WebGPU-first 3D Gaussian Splatting renderer for three.js.
|
|
3
|
+
*
|
|
4
|
+
* Public API surface. Everything else under `src/lib/` is internal and may
|
|
5
|
+
* change without notice.
|
|
6
|
+
*
|
|
7
|
+
* Optional systems live on dedicated subpaths so an application that only draws a
|
|
8
|
+
* fully loaded mesh does not pay for workers, schedulers, or work buffers:
|
|
9
|
+
* - `@voluma/vlam/loaders` - {@link loadSplatData}, {@link ChunkLoader}
|
|
10
|
+
* - `@voluma/vlam/static-lod` - {@link StaticLodSplatMesh}
|
|
11
|
+
* - `@voluma/vlam/streaming` - {@link StreamedSplatMesh}, budget governors
|
|
12
|
+
* - `@voluma/vlam/unified` - {@link UnifiedSplatMesh}
|
|
13
|
+
* - `@voluma/vlam/selection` - volume select and partition
|
|
14
|
+
* - `@voluma/vlam/effects` - tree-shakeable modifier presets
|
|
15
|
+
* - `@voluma/vlam/formats/ply` - 3DGS `.ply`, raw and compressed
|
|
16
|
+
* - `@voluma/vlam/formats/sog` - PlayCanvas SOG, bundled and unbundled
|
|
17
|
+
* - `@voluma/vlam/formats/rad` - Spark `.rad`/`.radc`
|
|
18
|
+
* - `@voluma/vlam/formats/lcc` - XGRIDS LCC / `.lcc2` + collision helpers
|
|
19
|
+
* - `@voluma/vlam/formats/spz` - Niantic `.spz`
|
|
20
|
+
* - `@voluma/vlam/formats/splat` - antimatter15 `.splat`
|
|
21
|
+
* - `@voluma/vlam/formats/ksplat` - mkkellogg `.ksplat`
|
|
22
|
+
*
|
|
23
|
+
* {@link loadSplatData} / {@link StreamedSplatMesh.load} still accept those formats
|
|
24
|
+
* without importing a format subpath; the library loads format code on demand.
|
|
25
|
+
*
|
|
26
|
+
* @module core
|
|
27
|
+
*/
|
|
28
|
+
export { SplatMesh, MAX_SH_BANDS, DEFAULT_FOVEATION_TARGET_PX, DEFAULT_FOVEATION_DRAW_BUDGET, resolveSplatPerformanceProfile, type UnifiedSourceView, type SplatMeshOptions, type SplatUpdateOptions, type SplatSortStrategy, type SplatPerformanceProfile, type SplatFoveationMode, type SplatRange, type SplatPickOptions, type SplatPickResult, type SplatNearestResult, type SplatRayResult, type SplatHeightResult, type SplatChannelType, type SplatChannelOptions, } from './splat-mesh';
|
|
29
|
+
export { SplatPool, type SplatPoolOptions } from './splat-mesh-pool';
|
|
30
|
+
export { SPLAT_DATA_TEXTURE_WIDTH, deviceMaxTextureSize, assertPoolRowsFitDevice, } from './splat-mesh-pool';
|
|
31
|
+
export { MAX_DOF_RADIUS_PX, MAX_DOF_VARIANCE, apertureAngleFromSize, computeDofCocVariancePx2, computeDofOpacityFade, clampDepthOfFieldSettings, type DepthOfFieldSettings, } from './depth-of-field';
|
|
32
|
+
export { DEFAULT_RELIGHT_BLEND, DEFAULT_RELIGHT_BRIGHTNESS, DEFAULT_RELIGHT_BACKGROUND, DEFAULT_RELIGHT_SOFTNESS, clampRelightingSettings, createPlaceholderRelightTexture, type RelightingSettings, type RelightingUniforms, } from './relighting';
|
|
33
|
+
export { type SplatOrientation, type OrientableFormat, createYUpTransform, yUpTransformForFormat, } from './orientation';
|
|
34
|
+
export { MergedSplatMesh, type MergedSplatMeshOptions, type MergedSplatSourceOptions, } from './merged-splat-mesh';
|
|
35
|
+
export { MAX_MERGED_SPLAT_SOURCES } from './source-transform';
|
|
36
|
+
export type { SplatShInputs, Vec3Uniform } from './splat-mesh-material';
|
|
37
|
+
export { resolveSplatBudget, detectSplatDeviceProfile, classifySplatGpuClass, probeSplatGpuClass, isFillConstrainedSplatDevice, recommendedMaxPixelRatio, recommendedRadMaxStdDev, recommendedXrFramebufferScale, resolveXrSplatBudget, suggestAdaptivePixelRatio, ADAPTIVE_PIXEL_RATIO_WARMUP_FRAMES, estimateSplatPoolBytes, type SplatBudgetOptions, type SplatCostClass, type SplatDeviceProfile, type SplatGpuClass, type SplatGpuAdapterInfo, type AdaptivePixelRatioInput, type AdaptivePixelRatioResult, type SplatPoolBytesOptions, } from './splat-budget';
|
|
38
|
+
export { xrSessionInit } from './xr-view';
|
|
39
|
+
export { createSplatRenderer, type CreateSplatRendererOptions, type SplatRendererGpu, type SplatRendererGpuAdapter, type SplatRendererGpuDevice, } from './create-splat-renderer';
|
|
40
|
+
export { recommendedWebGpuRequiredLimits, supportsWebGpuPowerPreference, webGpuPowerPreferenceOptions, deviceMaxStorageBufferBindingSize, assertStorageBufferFitsDevice, WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE, type WebGpuRequiredLimits, type WebGpuPowerPreference, } from './webgpu-limits';
|
|
41
|
+
export type { SplatData, SplatShData, SplatPackedShData } from './splat-data';
|
|
42
|
+
export type { SplatDataFormat, StreamedSplatFormat } from '../loaders/loading';
|
|
43
|
+
export type { SplatModifier, SplatContext, SplatOutputs, ModifierStackTarget, } from './splat-modifier';
|
|
44
|
+
export { ModifierSlots } from './splat-modifier';
|
|
45
|
+
export { setVlamLogHandler, type VlamLogHandler, type VlamLogLevel } from './logging';
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* transparent draw calls, each depth-sorted only within itself, so where the
|
|
7
7
|
* clouds overlap one is painted wholesale in front of the other ("pasted over")
|
|
8
8
|
* - the same artifact PlayCanvas's unified rendering and Spark's accumulator
|
|
9
|
-
* exist to fix. `
|
|
9
|
+
* exist to fix. `MergedSplatMesh` concatenates every cloud into **one pool** and
|
|
10
10
|
* runs **one global depth sort**, so splats from different clouds interleave
|
|
11
11
|
* correctly, from any angle.
|
|
12
12
|
*
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* is a handful of uniform writes - a source can be dragged or animated every
|
|
18
18
|
* frame at full rate, at any splat count, with no data re-upload.
|
|
19
19
|
*
|
|
20
|
-
* The placement runs **before** the modifier stack, so
|
|
20
|
+
* The placement runs **before** the modifier stack, so an application effect sees each
|
|
21
21
|
* splat where it visually is: an SDF light shape spanning two sources paints
|
|
22
22
|
* one continuous shape, and a reveal sweeps them together. A modifier that
|
|
23
23
|
* wants to travel *with* a moved source reads `ctx.sourceCenter` instead of
|
|
@@ -30,27 +30,26 @@
|
|
|
30
30
|
* Limitations, all inherited from the dynamic pool: sources may not carry
|
|
31
31
|
* palette (SOG `shN`) view-dependent color - per-file palettes cannot be merged
|
|
32
32
|
* - but DC color and per-splat (LCC) SH are fine; all sources share one
|
|
33
|
-
* antialias setting (from the
|
|
33
|
+
* antialias setting (from the mesh options).
|
|
34
34
|
*
|
|
35
|
-
* Sources are
|
|
36
|
-
* {@link
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* the static sources. Streamed sources are ROADMAP M15.4.
|
|
35
|
+
* Sources are fully decoded {@link SplatData} copied once into the pool.
|
|
36
|
+
* {@link StreamedSplatMesh} swaps its resident LOD cut every frame, so it cannot
|
|
37
|
+
* be a merged source. Compose streamed meshes with fully loaded meshes through
|
|
38
|
+
* {@link UnifiedSplatMesh} instead.
|
|
40
39
|
*/
|
|
41
40
|
import * as THREE from 'three/webgpu';
|
|
42
41
|
import { SplatMesh, type SplatMeshOptions } from './splat-mesh';
|
|
43
42
|
import type { SplatData } from './splat-data';
|
|
44
43
|
import { type SplatOrientation } from './orientation';
|
|
45
|
-
/** Construction options for a {@link
|
|
46
|
-
export interface
|
|
44
|
+
/** Construction options for a {@link MergedSplatMesh}. */
|
|
45
|
+
export interface MergedSplatMeshOptions extends SplatMeshOptions {
|
|
47
46
|
/** Total pool size in splats - must cover the sum of every source added. */
|
|
48
47
|
capacity: number;
|
|
49
|
-
/** Maximum number of sources (default {@link
|
|
48
|
+
/** Maximum number of sources (default {@link MAX_MERGED_SPLAT_SOURCES}). */
|
|
50
49
|
maxSources?: number;
|
|
51
50
|
}
|
|
52
51
|
/** Per-source placement options. */
|
|
53
|
-
export interface
|
|
52
|
+
export interface MergedSplatSourceOptions {
|
|
54
53
|
/**
|
|
55
54
|
* Y-up normalization for this source's data frame, like {@link SplatMesh}'s
|
|
56
55
|
* `orientation`. `'y-up'` (default) applies the format's stand-up correction
|
|
@@ -64,13 +63,13 @@ export interface AddSourceOptions {
|
|
|
64
63
|
*
|
|
65
64
|
* @experimental May change in a minor release.
|
|
66
65
|
*/
|
|
67
|
-
export declare class
|
|
66
|
+
export declare class MergedSplatMesh extends SplatMesh {
|
|
68
67
|
private readonly matrices;
|
|
69
68
|
private readonly maxSources;
|
|
70
69
|
/** Indexed by source id; holes are left by {@link removeSource}. */
|
|
71
70
|
private readonly sources;
|
|
72
71
|
private nextId;
|
|
73
|
-
constructor(options:
|
|
72
|
+
constructor(options: MergedSplatMeshOptions);
|
|
74
73
|
/** Number of live sources. */
|
|
75
74
|
get sourceCount(): number;
|
|
76
75
|
/**
|
|
@@ -81,7 +80,7 @@ export declare class SplatScene extends SplatMesh {
|
|
|
81
80
|
*
|
|
82
81
|
* @throws if the pool cannot fit the cloud, or the source limit is reached.
|
|
83
82
|
*/
|
|
84
|
-
addSource(data: SplatData, placement?: THREE.Matrix4, options?:
|
|
83
|
+
addSource(data: SplatData, placement?: THREE.Matrix4, options?: MergedSplatSourceOptions): number;
|
|
85
84
|
/**
|
|
86
85
|
* Re-places a source. Cheap by design: only the shared matrix uniform and the
|
|
87
86
|
* sort bound change, so it is safe to call every frame while dragging.
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import * as THREE from 'three/webgpu';
|
|
2
2
|
/**
|
|
3
|
-
* How a loaded
|
|
3
|
+
* How a loaded capture is oriented into the three.js Y-up world.
|
|
4
4
|
*
|
|
5
5
|
* - `'y-up'` (default): VLAM normalizes every known format to three.js Y-up -
|
|
6
6
|
* the OpenCV-frame formats (PLY/`.splat`/`.ksplat`/SOG/`.rad`) are flipped
|
|
7
7
|
* 180° about X, SPZ is already Y-up, and LCC carries its own Z-up→Y-up matrix.
|
|
8
8
|
* "Drop a file and it stands up", matching engine viewers (PlayCanvas, Babylon).
|
|
9
|
-
* - `'source'`:
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* - `'source'`: keep the native/source coordinate frame. No cosmetic 180°-X flip.
|
|
10
|
+
* An application that manages orientation itself (for example swapping viewers
|
|
11
|
+
* while keeping one stored per-capture rotation) uses this.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* LCC's Z-up→Y-up matrix is format semantics, not a cosmetic default: it is
|
|
14
|
+
* applied in **both** modes (Spark applies it too). Only the 180°-X flip for
|
|
15
15
|
* the Y-down formats is gated by this option.
|
|
16
16
|
*/
|
|
17
17
|
export type SplatOrientation = 'y-up' | 'source';
|
|
18
18
|
/**
|
|
19
19
|
* Formats {@link yUpTransformForFormat} understands: the self-contained scene
|
|
20
|
-
* formats ({@link SplatData.
|
|
20
|
+
* formats ({@link SplatData.format}) plus the streamed ones.
|
|
21
21
|
*/
|
|
22
22
|
export type OrientableFormat = 'ply' | 'splat' | 'ksplat' | 'sog' | 'spz' | 'rad' | 'streamed-sog' | 'lcc' | 'lcc2';
|
|
23
23
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Host lights a proxy mesh into an RGBA render target (RGB = lit color,
|
|
5
5
|
* A = coverage), then {@link SplatMesh.setRelighting} /
|
|
6
|
-
* {@link
|
|
6
|
+
* {@link UnifiedSplatMesh.setRelighting} multiplies baked splat color in
|
|
7
7
|
* the display fragment. Not a `SplatModifier` - coverage is per-pixel.
|
|
8
8
|
*
|
|
9
9
|
* See `docs/guide/relighting.md`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Per-source world transforms for a unified {@link
|
|
2
|
+
* Per-source world transforms for a unified {@link MergedSplatMesh} pool.
|
|
3
3
|
*
|
|
4
4
|
* Multiple splat clouds are concatenated into one pool in their own local
|
|
5
5
|
* space; each cloud ("source") then carries a world matrix applied **in the
|
|
@@ -20,10 +20,10 @@ import * as THREE from 'three/webgpu';
|
|
|
20
20
|
import { uniformArray } from 'three/tsl';
|
|
21
21
|
/**
|
|
22
22
|
* Maximum number of sources a unified pool can hold. Sized generously - the
|
|
23
|
-
* uniform array costs `4 ·
|
|
23
|
+
* uniform array costs `4 · MAX_MERGED_SPLAT_SOURCES` vec4s (16 KB at 256), well under the
|
|
24
24
|
* uniform-buffer limit - while bounding the per-splat index range.
|
|
25
25
|
*/
|
|
26
|
-
export declare const
|
|
26
|
+
export declare const MAX_MERGED_SPLAT_SOURCES = 256;
|
|
27
27
|
/** The channel both the material graph and the sorter read as a source id. */
|
|
28
28
|
export declare const SOURCE_ID_CHANNEL = "sourceId";
|
|
29
29
|
/**
|
|
@@ -33,7 +33,7 @@ export declare const SOURCE_ID_CHANNEL = "sourceId";
|
|
|
33
33
|
* the frame's uniforms - no material or pipeline rebuild.
|
|
34
34
|
*/
|
|
35
35
|
export declare class SourceMatrixArray {
|
|
36
|
-
/** `4 ·
|
|
36
|
+
/** `4 · MAX_MERGED_SPLAT_SOURCES` vec4 columns; the TSL node both consumers index. */
|
|
37
37
|
readonly node: ReturnType<typeof uniformArray>;
|
|
38
38
|
/** CPU mirror of the same column-major matrices, for the WebGL2 sorter. */
|
|
39
39
|
readonly matrices: Float32Array;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* pool capacity. Capping the active splat count therefore caps memory
|
|
11
11
|
* directly, which is what matters on mobile GPUs.
|
|
12
12
|
*/
|
|
13
|
-
import type { StreamedSplatFormat } from '
|
|
13
|
+
import type { StreamedSplatFormat } from '../loaders/loading';
|
|
14
14
|
/**
|
|
15
15
|
* Desktop GPU capability class for budget / quality defaults.
|
|
16
16
|
*
|
|
@@ -256,7 +256,7 @@ export interface SplatPoolBytesOptions {
|
|
|
256
256
|
* that envelope, it does not shrink it. Price the ceilings before choosing them:
|
|
257
257
|
*
|
|
258
258
|
* ```js
|
|
259
|
-
* // 1 main + 4
|
|
259
|
+
* // 1 main + 4 additional meshes, each able to reach 1.5M splats
|
|
260
260
|
* const bytes = estimateSplatPoolBytes(4_000_000) + 4 * estimateSplatPoolBytes(1_500_000);
|
|
261
261
|
* ```
|
|
262
262
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SplatDataFormat } from '../loaders/loading';
|
|
2
2
|
/**
|
|
3
3
|
* CPU-side representation of a set of 3D Gaussians, ready for GPU upload.
|
|
4
4
|
*
|
|
@@ -36,7 +36,7 @@ export interface SplatData {
|
|
|
36
36
|
* Per-splat LOD-tree links for a streamed `.rad` chunk (the merged coarse
|
|
37
37
|
* nodes and leaves are all present in {@link positions} etc.). The streamed
|
|
38
38
|
* reader uses this to pick the rendered cut across chunks; other formats and
|
|
39
|
-
* the
|
|
39
|
+
* the whole-file path leave it undefined. See `parse-rad.ts` and `rad.ts`.
|
|
40
40
|
*/
|
|
41
41
|
readonly radTree?: RadTreeData;
|
|
42
42
|
/**
|
|
@@ -52,11 +52,11 @@ export interface SplatData {
|
|
|
52
52
|
readonly radShCodebook?: RadShCodebook;
|
|
53
53
|
/**
|
|
54
54
|
* The self-contained format this scene was decoded from, stamped by the
|
|
55
|
-
* loaders ({@link
|
|
55
|
+
* loaders ({@link loadSplatData}/{@link loadSplatDataFile}). {@link SplatMesh} reads
|
|
56
56
|
* it to pick the `orientation: 'y-up'` correction. Absent on hand-built data
|
|
57
57
|
* and streamed chunks, in which case no orientation is ever inferred.
|
|
58
58
|
*/
|
|
59
|
-
readonly
|
|
59
|
+
readonly format?: SplatDataFormat;
|
|
60
60
|
}
|
|
61
61
|
/** Palette emitted once in chunk zero by Spark's clustered RAD SH encoding. */
|
|
62
62
|
export interface RadShCodebook {
|
|
@@ -92,7 +92,7 @@ export type SplatShInputs = {
|
|
|
92
92
|
};
|
|
93
93
|
};
|
|
94
94
|
/**
|
|
95
|
-
* Per-source placement inputs for a unified pool ({@link
|
|
95
|
+
* Per-source placement inputs for a unified pool ({@link MergedSplatMesh}): the
|
|
96
96
|
* splat's source id plus the shared array of source matrices. Drives two things
|
|
97
97
|
* at once - the splat's mesh-local position (`M · poolCenter`, applied before
|
|
98
98
|
* the modifier stack) and the frame view-dependent SH is evaluated in.
|
|
@@ -220,7 +220,7 @@ export interface SplatMaterialBuildInputs {
|
|
|
220
220
|
* `own_size` (from the covariance) and the `parent_size` packed in
|
|
221
221
|
* `covarianceB.w`. See `docs/formats/rad-notes.md` M14.6.
|
|
222
222
|
*/
|
|
223
|
-
foveationMode?: 'band' | 'frontier' | '
|
|
223
|
+
foveationMode?: 'band' | 'frontier' | 'page-table';
|
|
224
224
|
/**
|
|
225
225
|
* Cap on a rendered splat's major/minor axis ratio (0/undefined = off). Tames
|
|
226
226
|
* far-field needle/spike artifacts from very anisotropic Gaussians and
|
|
@@ -7,6 +7,12 @@ import type { SplatPool } from './splat-mesh-pool';
|
|
|
7
7
|
import type { SplatShInputs, Vec3Uniform } from './splat-mesh-material';
|
|
8
8
|
/** Construction-time projected-footprint policy selected by a streamed format. */
|
|
9
9
|
export type ProjectedFilterProfile = 'default' | 'lcc';
|
|
10
|
+
/** Canonical `.rad` foveation modes. */
|
|
11
|
+
export type SplatFoveationMode = 'band' | 'frontier' | 'page-table';
|
|
12
|
+
/** Resolve a caller-supplied foveation mode, defaulting when unset. */
|
|
13
|
+
export declare function resolveSplatFoveationMode(mode: SplatFoveationMode | undefined, fallback?: SplatFoveationMode): SplatFoveationMode;
|
|
14
|
+
/** True when the mode is the `.rad` page-table pager. */
|
|
15
|
+
export declare function isPageTableFoveation(mode: string | undefined): boolean;
|
|
10
16
|
/**
|
|
11
17
|
* Opaque handle for a range of splats appended to a {@link SplatMesh},
|
|
12
18
|
* used to remove the range again.
|
|
@@ -162,7 +168,7 @@ export interface SplatMeshOptions {
|
|
|
162
168
|
* too big and it is small enough (`parentPixelScale > limit ≥ ownPixelScale`),
|
|
163
169
|
* using per-splat `own_size`/`parent_size`. Full coverage by construction, no
|
|
164
170
|
* band leapfrogging. Baked into the material graph. See `docs/formats/rad-notes.md`.
|
|
165
|
-
* - `'
|
|
171
|
+
* - `'page-table'`: the {@link StreamedSplatMesh} default for `.rad` - a worker
|
|
166
172
|
* owns the tree traversal and pages only the *selected* frontier into the
|
|
167
173
|
* pool (Spark's selected-index model), so the whole splat budget buys
|
|
168
174
|
* on-screen detail. Requires the streamed `.rad` machinery; on a plain
|
|
@@ -170,7 +176,7 @@ export interface SplatMeshOptions {
|
|
|
170
176
|
*
|
|
171
177
|
* @experimental `.rad` foveation option; may change in a minor release.
|
|
172
178
|
*/
|
|
173
|
-
foveationMode?:
|
|
179
|
+
foveationMode?: SplatFoveationMode;
|
|
174
180
|
/**
|
|
175
181
|
* Target on-screen size (px) for the frontier / page-table cut: it keeps one
|
|
176
182
|
* LOD level per view ray whose projected node size is about this. Larger =
|
|
@@ -205,8 +211,11 @@ export interface SplatMeshOptions {
|
|
|
205
211
|
maxSplatAspect?: number;
|
|
206
212
|
/**
|
|
207
213
|
* Spark's LOD alpha encoding (`.rad`): the stored opacity is `alpha/2` so the
|
|
208
|
-
* shader recovers `alpha ∈ [0,2]
|
|
209
|
-
* with a grown σ-cutoff +
|
|
214
|
+
* shader recovers `alpha ∈ [0,2]` from the original texture channel, and
|
|
215
|
+
* `alpha > 1` marks a merged node rendered with a grown σ-cutoff +
|
|
216
|
+
* super-Gaussian falloff. Visual fades and alpha modifiers scale the completed
|
|
217
|
+
* fragment after that classification; they must not change node type or shape.
|
|
218
|
+
* Set for foveated `.rad`.
|
|
210
219
|
*
|
|
211
220
|
* @experimental `.rad` foveation option; may change in a minor release.
|
|
212
221
|
*/
|
|
@@ -219,9 +228,9 @@ export interface SplatMeshOptions {
|
|
|
219
228
|
* cosmetic flip and renders in the data frame (raw Spark / mkkellogg parity);
|
|
220
229
|
* LCC still self-orients (that is format semantics, not part of the switch).
|
|
221
230
|
*
|
|
222
|
-
* For a
|
|
223
|
-
* (stamped by the loaders); a dynamic-capacity mesh carries no format, so
|
|
224
|
-
*
|
|
231
|
+
* For a fully loaded mesh the flip is chosen from {@link SplatData.format}
|
|
232
|
+
* (stamped by the loaders); a dynamic-capacity mesh carries no format, so the
|
|
233
|
+
* caller applies {@link yUpTransformForFormat} itself. See {@link SplatOrientation}.
|
|
225
234
|
*/
|
|
226
235
|
orientation?: SplatOrientation;
|
|
227
236
|
/**
|
|
@@ -266,7 +275,7 @@ export interface SplatMeshOptions {
|
|
|
266
275
|
export type SplatSortStrategy = 'counting' | 'radix' | 'exact';
|
|
267
276
|
/** Controls optional work during a per-frame source update. */
|
|
268
277
|
export interface SplatUpdateOptions {
|
|
269
|
-
/** Leave sorting to {@link
|
|
278
|
+
/** Leave sorting to {@link UnifiedSplatMesh}; uploads and LOD state still update. */
|
|
270
279
|
sort?: boolean;
|
|
271
280
|
}
|
|
272
281
|
/**
|
|
@@ -303,8 +312,8 @@ export interface UnifiedSourceView {
|
|
|
303
312
|
readonly modifiers: readonly SplatModifier[];
|
|
304
313
|
/**
|
|
305
314
|
* True when this source is itself a unified pool with per-source placement
|
|
306
|
-
* (`
|
|
307
|
-
* `
|
|
315
|
+
* (`MergedSplatMesh`). The gather path cannot resolve nested placement, so
|
|
316
|
+
* `UnifiedSplatMesh` rejects these sources.
|
|
308
317
|
*/
|
|
309
318
|
readonly hasSourcePlacement: boolean;
|
|
310
319
|
readonly channels: ReadonlyMap<string, {
|
|
@@ -133,7 +133,7 @@ export declare class SplatMesh extends THREE.Mesh implements SplatPoolTenant {
|
|
|
133
133
|
/** Created on the first update, when the renderer backend is known. */
|
|
134
134
|
private sorter;
|
|
135
135
|
/**
|
|
136
|
-
* Set by a unified {@link
|
|
136
|
+
* Set by a unified {@link MergedSplatMesh} subclass before the first sort: makes
|
|
137
137
|
* the WebGPU sorter transform each splat's center to world space by its
|
|
138
138
|
* source's matrix before measuring depth. `null` for an ordinary mesh, whose
|
|
139
139
|
* sorter is byte-identical to before. See `source-transform.ts`.
|
|
@@ -376,7 +376,7 @@ export declare class SplatMesh extends THREE.Mesh implements SplatPoolTenant {
|
|
|
376
376
|
*/
|
|
377
377
|
getUnifiedSourceView(): UnifiedSourceView;
|
|
378
378
|
/**
|
|
379
|
-
* Marks this mesh as a source drawn by {@link
|
|
379
|
+
* Marks this mesh as a source drawn by {@link UnifiedSplatMesh}.
|
|
380
380
|
* The source stays invisible to the regular scene draw, while its own picker
|
|
381
381
|
* mirrors this resolved visibility so existing per-source hit testing works.
|
|
382
382
|
* Internal consumers should clear the state with `null` before disposing.
|
|
@@ -384,7 +384,7 @@ export declare class SplatMesh extends THREE.Mesh implements SplatPoolTenant {
|
|
|
384
384
|
setUnifiedPickVisibility(visible: boolean | null): void;
|
|
385
385
|
/**
|
|
386
386
|
* The visibility that actually decides whether this mesh's splats reach the
|
|
387
|
-
* screen: the owning {@link
|
|
387
|
+
* screen: the owning {@link UnifiedSplatMesh}'s per-source visibility
|
|
388
388
|
* while one owns the draw, else `Object3D.visible`. Consumers that gate on
|
|
389
389
|
* "is this mesh showing" - the picker, `CameraBudgetGovernor` - must read
|
|
390
390
|
* this rather than `visible`, which a unified renderer forces to `false` on
|
|
@@ -708,7 +708,7 @@ export declare class SplatMesh extends THREE.Mesh implements SplatPoolTenant {
|
|
|
708
708
|
/**
|
|
709
709
|
* Refreshes {@link boundingSphereLocal} - the sphere the sorter quantizes
|
|
710
710
|
* depth over - when {@link boundsDirty}. The base mesh uses its local splat
|
|
711
|
-
* bounds; a unified {@link
|
|
711
|
+
* bounds; a unified {@link MergedSplatMesh} overrides this to supply a world-space
|
|
712
712
|
* bound spanning all its sources (whose transforms live in the shader).
|
|
713
713
|
*/
|
|
714
714
|
protected refreshSortBounds(): void;
|
|
@@ -9,7 +9,7 @@ export interface SplatContext {
|
|
|
9
9
|
/**
|
|
10
10
|
* Splat center in mesh-local space (pre-displacement).
|
|
11
11
|
*
|
|
12
|
-
* Inside a `
|
|
12
|
+
* Inside a `MergedSplatMesh` this is the splat's **placed** position
|
|
13
13
|
* (`sourceMatrix · poolCenter`) - the placement is applied before the stack
|
|
14
14
|
* runs, so effects stay anchored to the scene rather than travelling with a
|
|
15
15
|
* moved source. Use {@link sourceCenter} for the pre-placement position.
|
|
@@ -17,14 +17,14 @@ export interface SplatContext {
|
|
|
17
17
|
readonly localCenter: Node<'vec3'>;
|
|
18
18
|
/**
|
|
19
19
|
* The splat's position in its own source's data frame. Identical to
|
|
20
|
-
* {@link localCenter} on a plain mesh; inside a `
|
|
20
|
+
* {@link localCenter} on a plain mesh; inside a `MergedSplatMesh` it is the
|
|
21
21
|
* **pre-placement** position, for effects that should travel *with* a moved
|
|
22
22
|
* source instead of staying put in the scene.
|
|
23
23
|
*/
|
|
24
24
|
readonly sourceCenter: Node<'vec3'>;
|
|
25
25
|
/**
|
|
26
26
|
* Linear transform from the source data frame to mesh-local space. This is
|
|
27
|
-
* identity on a plain mesh; inside a {@link
|
|
27
|
+
* identity on a plain mesh; inside a {@link MergedSplatMesh} it is the linear part
|
|
28
28
|
* of the source placement. Apply it to source-frame displacement vectors.
|
|
29
29
|
* To express a source-frame rotation `R` as a mesh-local `rotation` output,
|
|
30
30
|
* conjugate it: `sourceToLocal · R · sourceToLocal.inverse()`.
|
|
@@ -109,8 +109,8 @@ export interface ModifierStackTarget {
|
|
|
109
109
|
* - An **empty slot costs nothing**: it is omitted from the compacted list
|
|
110
110
|
* entirely, never compiled as a passthrough. All slots empty ⇒ the mesh
|
|
111
111
|
* gets an empty list ⇒ the unhooked graph (and the unified renderer's
|
|
112
|
-
* zero-modifier gather fast path stays eligible - except for a `
|
|
113
|
-
* which `
|
|
112
|
+
* zero-modifier gather fast path stays eligible - except for a `MergedSplatMesh`,
|
|
113
|
+
* which `UnifiedSplatMesh` does not accept as a source at all).
|
|
114
114
|
* - {@link apply} hands the mesh a **compacted array whose reference is
|
|
115
115
|
* stable** while the occupancy is unchanged, so re-applying after
|
|
116
116
|
* uniform-only changes is a guaranteed no-op on the mesh's identity diff -
|
|
@@ -19,14 +19,6 @@ export interface WebGpuRequiredLimits {
|
|
|
19
19
|
maxTextureDimension2D: number;
|
|
20
20
|
[limit: string]: number;
|
|
21
21
|
}
|
|
22
|
-
/** Bytes per splat in the largest unified work-buffer attribute (RGBA32F centers). */
|
|
23
|
-
export declare const WORK_BUFFER_CENTERS_BYTES_PER_SPLAT = 16;
|
|
24
|
-
/**
|
|
25
|
-
* Bytes per work-buffer slot across *all* of its attributes: centers, colors,
|
|
26
|
-
* covarianceA and covarianceB at RGBA32F (16 each), plus the isotropic mix and
|
|
27
|
-
* screen-radius scalars (4 each).
|
|
28
|
-
*/
|
|
29
|
-
export declare const WORK_BUFFER_BYTES_PER_SLOT: number;
|
|
30
22
|
/**
|
|
31
23
|
* WebGPU's default `maxStorageBufferBindingSize` when the host does not raise
|
|
32
24
|
* it via `requiredLimits` (128 MiB).
|
|
@@ -68,57 +60,6 @@ export declare function supportsWebGpuPowerPreference(nav?: NavigatorPlatformPro
|
|
|
68
60
|
export declare function webGpuPowerPreferenceOptions(powerPreference?: WebGpuPowerPreference, nav?: NavigatorPlatformProbe): {
|
|
69
61
|
powerPreference: WebGpuPowerPreference;
|
|
70
62
|
} | Record<string, never>;
|
|
71
|
-
/**
|
|
72
|
-
* Byte size of the largest single storage-buffer bind VLAM allocates for a
|
|
73
|
-
* given splat capacity (unified work-buffer centers: `capacity × 16`).
|
|
74
|
-
*
|
|
75
|
-
* Use with adapter/device limits to decide whether to raise `requiredLimits`
|
|
76
|
-
* or lower the budget before constructing {@link UnifiedSplatRenderer}.
|
|
77
|
-
*/
|
|
78
|
-
export declare function estimateLargestStorageBufferBytes(capacity: number): number;
|
|
79
|
-
/**
|
|
80
|
-
* Estimates what a {@link UnifiedSplatRenderer}'s work buffer costs, in bytes,
|
|
81
|
-
* once the scene has rendered a frame.
|
|
82
|
-
*
|
|
83
|
-
* This used to be double the figure below, and the doubling was not a detail.
|
|
84
|
-
* Every `THREE.StorageBufferAttribute` is constructed around a JS typed array,
|
|
85
|
-
* and three's WebGPU backend never releases it: the
|
|
86
|
-
* `attribute.onUploadCallback()` call that would is missing from the backend's
|
|
87
|
-
* buffer upload path. So a work buffer of N slots cost
|
|
88
|
-
* N × {@link WORK_BUFFER_BYTES_PER_SLOT} on the GPU *and* the same again on the
|
|
89
|
-
* JS heap, permanently, even though nothing ever reads the CPU copy back - the
|
|
90
|
-
* gather pass writes these buffers entirely on the GPU.
|
|
91
|
-
*
|
|
92
|
-
* `WorkBuffer.releaseCpuMirrors` now drops those mirrors after the first
|
|
93
|
-
* dispatch that uploads them (see `storage-attribute-mirror`), so steady state
|
|
94
|
-
* is the GPU side alone. The *peak* is still double - the array has to exist
|
|
95
|
-
* for the upload copy - which is what
|
|
96
|
-
* {@link estimateUnifiedWorkBufferPeakBytes} reports.
|
|
97
|
-
*
|
|
98
|
-
* Either figure is invisible to `estimateSplatPoolBytes`, which prices the
|
|
99
|
-
* splat *pool* and knows nothing about the unified renderer's scratch space. A
|
|
100
|
-
* host sizing a scene for a memory-constrained device wants both.
|
|
101
|
-
*
|
|
102
|
-
* @param capacity - Work-buffer capacity in splats.
|
|
103
|
-
* @returns Estimated steady-state bytes.
|
|
104
|
-
* @throws {RangeError} if `capacity` is not a non-negative finite number.
|
|
105
|
-
*/
|
|
106
|
-
export declare function estimateUnifiedWorkBufferBytes(capacity: number): number;
|
|
107
|
-
/**
|
|
108
|
-
* Peak bytes a {@link UnifiedSplatRenderer}'s work buffer occupies: the window
|
|
109
|
-
* between construction and the first dispatch, while the GPU buffer and the JS
|
|
110
|
-
* array three copied it from are both alive.
|
|
111
|
-
*
|
|
112
|
-
* Ask this one when the question is "will allocating this scene succeed" - an
|
|
113
|
-
* out-of-memory failure happens against the peak. Ask
|
|
114
|
-
* {@link estimateUnifiedWorkBufferBytes} when the question is "what will this
|
|
115
|
-
* scene hold once it is up".
|
|
116
|
-
*
|
|
117
|
-
* @param capacity - Work-buffer capacity in splats.
|
|
118
|
-
* @returns Estimated bytes, GPU plus the not-yet-released CPU mirror.
|
|
119
|
-
* @throws {RangeError} if `capacity` is not a non-negative finite number.
|
|
120
|
-
*/
|
|
121
|
-
export declare function estimateUnifiedWorkBufferPeakBytes(capacity: number): number;
|
|
122
63
|
/**
|
|
123
64
|
* The renderer's WebGPU `maxStorageBufferBindingSize`, or 0 when it cannot be
|
|
124
65
|
* read (WebGL2 fallback, or device not yet available). Callers skip the check
|