@voluma/vlam 0.3.0 → 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 +0 -2
- package/dist/chunk-loader-DlNwggfG.js.map +1 -1
- package/dist/{index.d.ts → core/index.d.ts} +1 -1
- package/dist/{splat-budget.d.ts → core/splat-budget.d.ts} +1 -1
- package/dist/{splat-data.d.ts → core/splat-data.d.ts} +1 -1
- package/dist/{splat-mesh-types.d.ts → core/splat-mesh-types.d.ts} +5 -2
- package/dist/{effects.d.ts → effects/index.d.ts} +3 -3
- package/dist/effects.js.map +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 +2 -2
- 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.map +1 -1
- package/dist/formats/ply/parse-compressed-ply.d.ts +2 -2
- package/dist/formats/ply/parse-splat-ply.d.ts +2 -2
- 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 +1 -1
- package/dist/formats/rad/parse-rad.d.ts +1 -1
- package/dist/formats/rad/rad-foveated-source.d.ts +3 -3
- package/dist/formats/rad/rad.d.ts +5 -5
- package/dist/formats/rad.js.map +1 -1
- package/dist/formats/sog/parse-sog.d.ts +2 -2
- package/dist/formats/sog.js.map +1 -1
- package/dist/formats/splat/parse-splat.d.ts +1 -1
- package/dist/formats/splat.js.map +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 +3 -3
- package/dist/index.js.map +1 -1
- package/dist/{chunk-loader.d.ts → loaders/chunk-loader.d.ts} +2 -2
- package/dist/{load-splat-data.d.ts → loaders/load-splat-data.d.ts} +1 -1
- package/dist/{load-worker-protocol.d.ts → loaders/load-worker-protocol.d.ts} +2 -2
- package/dist/loaders.js.map +1 -1
- package/dist/loading-wLo8vRbA.js.map +1 -1
- package/dist/lod-scheduler-B0a_uBlv.js.map +1 -1
- package/dist/logging-BfPdd7NJ.js.map +1 -1
- package/dist/ply-header-B9WllbPg.js.map +1 -1
- package/dist/{radix-sorter-R0FCSqKu.js → radix-sorter-BrbUg_CV.js} +2 -2
- package/dist/radix-sorter-BrbUg_CV.js.map +1 -0
- package/dist/{relighting-CSQF3UcL.js → relighting-Tiwep8yd.js} +302 -294
- package/dist/relighting-Tiwep8yd.js.map +1 -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} +1 -1
- package/dist/selection.js.map +1 -1
- package/dist/sh-pack-D5wAe5gg.js.map +1 -1
- package/dist/splat-budget-DuVZspPQ.js.map +1 -1
- package/dist/splat-data-BZM5dhhx.js.map +1 -1
- package/dist/{splat-mesh-aQdcWA6v.js → splat-mesh-CsLOQb08.js} +3 -3
- package/dist/splat-mesh-CsLOQb08.js.map +1 -0
- package/dist/splat-mesh-types-BZIko-_9.js.map +1 -1
- package/dist/{static-lod-splat-mesh.d.ts → static-lod/static-lod-splat-mesh.d.ts} +2 -2
- 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.js +1 -1
- package/dist/static-lod.js.map +1 -1
- package/dist/{dataset-source.d.ts → streaming/dataset-source.d.ts} +1 -1
- package/dist/{streaming.d.ts → streaming/index.d.ts} +3 -3
- package/dist/{lod-source.d.ts → streaming/lod-source.d.ts} +4 -4
- 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} +45 -5
- package/dist/streaming.js +844 -810
- package/dist/streaming.js.map +1 -1
- package/dist/{unified-splat-mesh.d.ts → unified/unified-splat-mesh.d.ts} +13 -6
- package/dist/{work-buffer-gather.d.ts → unified/work-buffer-gather.d.ts} +5 -5
- package/dist/{work-buffer-material.d.ts → unified/work-buffer-material.d.ts} +1 -1
- package/dist/unified.js +280 -272
- package/dist/unified.js.map +1 -1
- package/dist/webgpu-limits-Y3CI_6_6.js.map +1 -1
- package/package.json +9 -9
- package/dist/radix-sorter-R0FCSqKu.js.map +0 -1
- package/dist/relighting-CSQF3UcL.js.map +0 -1
- package/dist/splat-mesh-aQdcWA6v.js.map +0 -1
- /package/dist/{compute-sorter.d.ts → core/compute-sorter.d.ts} +0 -0
- /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/{merged-splat-mesh.d.ts → core/merged-splat-mesh.d.ts} +0 -0
- /package/dist/{orientation.d.ts → core/orientation.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/{relighting.d.ts → core/relighting.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/{source-transform.d.ts → core/source-transform.d.ts} +0 -0
- /package/dist/{splat-depth-pack.d.ts → core/splat-depth-pack.d.ts} +0 -0
- /package/dist/{splat-mesh-material.d.ts → core/splat-mesh-material.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-mesh.d.ts → core/splat-mesh.d.ts} +0 -0
- /package/dist/{splat-modifier-stack.d.ts → core/splat-modifier-stack.d.ts} +0 -0
- /package/dist/{splat-modifier.d.ts → core/splat-modifier.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/{webgpu-limits.d.ts → core/webgpu-limits.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/{loaders.d.ts → loaders/index.d.ts} +0 -0
- /package/dist/{loading.d.ts → loaders/loading.d.ts} +0 -0
- /package/dist/{ply-header.d.ts → loaders/ply-header.d.ts} +0 -0
- /package/dist/{selection.d.ts → selection/index.d.ts} +0 -0
- /package/dist/{static-lod-entry.d.ts → static-lod/index.d.ts} +0 -0
- /package/dist/{budget-governor.d.ts → streaming/budget-governor.d.ts} +0 -0
- /package/dist/{camera-budget-governor.d.ts → streaming/camera-budget-governor.d.ts} +0 -0
- /package/dist/{chunk-cache-budget.d.ts → streaming/chunk-cache-budget.d.ts} +0 -0
- /package/dist/{chunk-fetch-scheduler.d.ts → streaming/chunk-fetch-scheduler.d.ts} +0 -0
- /package/dist/{lod-manifest.d.ts → streaming/lod-manifest.d.ts} +0 -0
- /package/dist/{lod-scheduler.d.ts → streaming/lod-scheduler.d.ts} +0 -0
- /package/dist/{unified.d.ts → unified/index.d.ts} +0 -0
- /package/dist/{unified-work-buffer.d.ts → unified/unified-work-buffer.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ksplat.js","sources":["../../src/lib/formats/ksplat/parse-ksplat.ts"],"sourcesContent":["import { halfToFloat } from '../../half-float';\nimport { packShCoefficients } from '../../sh-pack';\nimport { writeCovariance, type SplatData } from '../../splat-data';\n\nconst HEADER_BYTES = 4096;\nconst SECTION_HEADER_BYTES = 1024;\nconst BUCKET_CENTER_BYTES = 12;\n/** Default 8-bit SH dequant range half-width (GaussianSplats3D `Constants`). */\nconst DEFAULT_SH_RANGE_HALF = 1.5;\n\ninterface KsplatHeader {\n versionMajor: number;\n versionMinor: number;\n sectionCount: number;\n splatCount: number;\n compressionLevel: number;\n shCoeffMin: number;\n shCoeffMax: number;\n}\n\ninterface KsplatSection {\n count: number;\n maxCount: number;\n bucketSize: number;\n bucketCount: number;\n bucketBlockSize: number;\n bucketStorageBytes: number;\n compressionRange: number;\n fullBucketCount: number;\n partialBucketCount: number;\n shDegree: number;\n bytesPerSplat: number;\n base: number;\n bucketsBase: number;\n dataBase: number;\n}\n\n/**\n * Parses a GaussianSplats3D `.ksplat` file, including compression levels 0–2.\n * Base color, opacity, position, scale, rotation and optional higher-order\n * spherical harmonics (degrees 1–2) are retained.\n *\n * @throws {Error} if the header, section layout or record data is invalid.\n */\nexport function parseKsplat(buffer: ArrayBuffer): SplatData {\n const view = new DataView(buffer);\n const header = parseHeader(view);\n const sections = parseSections(view, header);\n const totalSectionSplats = sections.reduce((sum, section) => sum + section.count, 0);\n if (totalSectionSplats !== header.splatCount) {\n throw new Error(\n `Invalid KSPLAT counts: header declares ${header.splatCount}, sections contain ${totalSectionSplats}.`,\n );\n }\n\n const positions = new Float32Array(header.splatCount * 3);\n const colors = new Uint8Array(header.splatCount * 4);\n const covariances = new Float32Array(header.splatCount * 6);\n const maxShDegree = sections.reduce((max, section) => Math.max(max, section.shDegree), 0);\n const shComponents = shComponentsForDegree(maxShDegree);\n const coefficients = shComponents > 0 ? new Float32Array(header.splatCount * shComponents) : null;\n let outputIndex = 0;\n\n for (const section of sections) {\n const partialLengths = readPartialBucketLengths(view, section);\n const sectionShComponents = shComponentsForDegree(section.shDegree);\n const shOffset = header.compressionLevel === 0 ? 44 : 24;\n for (let localIndex = 0; localIndex < section.count; localIndex++, outputIndex++) {\n const source = section.dataBase + localIndex * section.bytesPerSplat;\n const position = outputIndex * 3;\n const color = outputIndex * 4;\n const scaleOffset = header.compressionLevel === 0 ? 12 : 6;\n const rotationOffset = header.compressionLevel === 0 ? 24 : 12;\n const colorOffset = header.compressionLevel === 0 ? 40 : 20;\n\n if (header.compressionLevel === 0) {\n positions[position + 0] = view.getFloat32(source + 0, true);\n positions[position + 1] = view.getFloat32(source + 4, true);\n positions[position + 2] = view.getFloat32(source + 8, true);\n } else {\n const bucket = bucketIndexForSplat(localIndex, section, partialLengths);\n const bucketBase = section.bucketsBase + bucket * section.bucketStorageBytes;\n const factor = (section.bucketBlockSize * 0.5) / section.compressionRange;\n positions[position + 0] =\n (view.getUint16(source + 0, true) - section.compressionRange) * factor +\n view.getFloat32(bucketBase + 0, true);\n positions[position + 1] =\n (view.getUint16(source + 2, true) - section.compressionRange) * factor +\n view.getFloat32(bucketBase + 4, true);\n positions[position + 2] =\n (view.getUint16(source + 4, true) - section.compressionRange) * factor +\n view.getFloat32(bucketBase + 8, true);\n }\n\n colors[color + 0] = view.getUint8(source + colorOffset + 0);\n colors[color + 1] = view.getUint8(source + colorOffset + 1);\n colors[color + 2] = view.getUint8(source + colorOffset + 2);\n colors[color + 3] = view.getUint8(source + colorOffset + 3);\n\n const readScalar = (offset: number): number =>\n header.compressionLevel === 0\n ? view.getFloat32(source + offset, true)\n : halfToFloat(view.getUint16(source + offset, true));\n const scalarBytes = header.compressionLevel === 0 ? 4 : 2;\n writeCovariance(\n covariances,\n outputIndex,\n readScalar(scaleOffset + 0 * scalarBytes),\n readScalar(scaleOffset + 1 * scalarBytes),\n readScalar(scaleOffset + 2 * scalarBytes),\n readScalar(rotationOffset + 0 * scalarBytes),\n readScalar(rotationOffset + 1 * scalarBytes),\n readScalar(rotationOffset + 2 * scalarBytes),\n readScalar(rotationOffset + 3 * scalarBytes),\n );\n\n if (coefficients && sectionShComponents > 0) {\n const dest = outputIndex * shComponents;\n for (let c = 0; c < sectionShComponents; c++) {\n const byteOffset = shOffset + c * shScalarBytes(header.compressionLevel);\n coefficients[dest + c] = readShScalar(\n view,\n source + byteOffset,\n header.compressionLevel,\n header.shCoeffMin,\n header.shCoeffMax,\n );\n }\n }\n }\n }\n\n const shPacked =\n coefficients && maxShDegree > 0\n ? packShCoefficients(coefficients, header.splatCount, maxShDegree as 1 | 2)\n : undefined;\n\n return {\n count: header.splatCount,\n positions,\n colors,\n covariances,\n ...(shPacked ? { shPacked } : {}),\n };\n}\n\nfunction shScalarBytes(compressionLevel: number): number {\n return compressionLevel === 0 ? 4 : compressionLevel === 1 ? 2 : 1;\n}\n\nfunction readShScalar(\n view: DataView,\n offset: number,\n compressionLevel: number,\n rangeMin: number,\n rangeMax: number,\n): number {\n if (compressionLevel === 0) return view.getFloat32(offset, true);\n if (compressionLevel === 1) return halfToFloat(view.getUint16(offset, true));\n const encoded = view.getUint8(offset);\n return (encoded / 255) * (rangeMax - rangeMin) + rangeMin;\n}\n\nfunction shComponentsForDegree(shDegree: number): number {\n if (shDegree === 0) return 0;\n if (shDegree === 1) return 9;\n if (shDegree === 2) return 24;\n throw new Error(`Unsupported KSPLAT SH degree ${shDegree}.`);\n}\n\nfunction parseHeader(view: DataView): KsplatHeader {\n if (view.byteLength < HEADER_BYTES) throw new Error('Truncated KSPLAT header.');\n const versionMajor = view.getUint8(0);\n const versionMinor = view.getUint8(1);\n const maxSectionCount = view.getUint32(4, true);\n const sectionCount = view.getUint32(8, true);\n const maxSplatCount = view.getUint32(12, true);\n const splatCount = view.getUint32(16, true);\n const compressionLevel = view.getUint16(20, true);\n const shCoeffMin = view.getFloat32(36, true) || -DEFAULT_SH_RANGE_HALF;\n const shCoeffMax = view.getFloat32(40, true) || DEFAULT_SH_RANGE_HALF;\n\n if (versionMajor !== 0 || versionMinor < 1) {\n throw new Error(\n `Unsupported KSPLAT version ${versionMajor}.${versionMinor}; expected 0.1 or newer.`,\n );\n }\n if (compressionLevel < 0 || compressionLevel > 2) {\n throw new Error(`Unsupported KSPLAT compression level ${compressionLevel}.`);\n }\n if (\n !Number.isSafeInteger(maxSectionCount) ||\n sectionCount > maxSectionCount ||\n sectionCount === 0\n ) {\n throw new Error(`Invalid KSPLAT section count ${sectionCount}/${maxSectionCount}.`);\n }\n if (splatCount > maxSplatCount) {\n throw new Error(`Invalid KSPLAT splat count ${splatCount}/${maxSplatCount}.`);\n }\n const headersEnd = HEADER_BYTES + maxSectionCount * SECTION_HEADER_BYTES;\n if (!Number.isSafeInteger(headersEnd) || headersEnd > view.byteLength) {\n throw new Error('Truncated KSPLAT section headers.');\n }\n\n return {\n versionMajor,\n versionMinor,\n sectionCount,\n splatCount,\n compressionLevel,\n shCoeffMin,\n shCoeffMax,\n };\n}\n\nfunction parseSections(view: DataView, header: KsplatHeader): KsplatSection[] {\n const maxSectionCount = view.getUint32(4, true);\n let sectionBase = HEADER_BYTES + maxSectionCount * SECTION_HEADER_BYTES;\n const sections: KsplatSection[] = [];\n\n for (let index = 0; index < maxSectionCount; index++) {\n const offset = HEADER_BYTES + index * SECTION_HEADER_BYTES;\n const count = view.getUint32(offset + 0, true);\n const maxCount = view.getUint32(offset + 4, true);\n const bucketSize = view.getUint32(offset + 8, true);\n const bucketCount = view.getUint32(offset + 12, true);\n const bucketBlockSize = view.getFloat32(offset + 16, true);\n const bucketStorageBytes = view.getUint16(offset + 20, true);\n const compressionRange = view.getUint32(offset + 24, true) || 32767;\n const fullBucketCount = view.getUint32(offset + 32, true);\n const partialBucketCount = view.getUint32(offset + 36, true);\n const shDegree = view.getUint16(offset + 40, true);\n const bytesPerSplat = bytesPerKsplat(header.compressionLevel, shDegree);\n const bucketMetadataBytes = partialBucketCount * 4;\n const bucketBytes = bucketCount * bucketStorageBytes;\n const storageBytes = bucketMetadataBytes + bucketBytes + maxCount * bytesPerSplat;\n\n if (index < header.sectionCount) {\n if (count > maxCount)\n throw new Error(`Invalid KSPLAT section ${index} count ${count}/${maxCount}.`);\n if (header.compressionLevel > 0) {\n if (bucketSize === 0 || bucketCount === 0 || bucketStorageBytes < BUCKET_CENTER_BYTES) {\n throw new Error(`Invalid KSPLAT bucket layout in section ${index}.`);\n }\n if (!Number.isFinite(bucketBlockSize) || bucketBlockSize <= 0 || compressionRange === 0) {\n throw new Error(`Invalid KSPLAT compression parameters in section ${index}.`);\n }\n if (fullBucketCount + partialBucketCount > bucketCount) {\n throw new Error(\n `Invalid KSPLAT section ${index}: ${fullBucketCount} full + ` +\n `${partialBucketCount} partial buckets exceed the ${bucketCount} declared.`,\n );\n }\n }\n if (sectionBase + storageBytes > view.byteLength) {\n throw new Error(`Truncated KSPLAT data in section ${index}.`);\n }\n sections.push({\n count,\n maxCount,\n bucketSize,\n bucketCount,\n bucketBlockSize,\n bucketStorageBytes,\n compressionRange,\n fullBucketCount,\n partialBucketCount,\n shDegree,\n bytesPerSplat,\n base: sectionBase,\n bucketsBase: sectionBase + bucketMetadataBytes,\n dataBase: sectionBase + bucketMetadataBytes + bucketBytes,\n });\n }\n sectionBase += storageBytes;\n }\n return sections;\n}\n\nfunction bytesPerKsplat(compressionLevel: number, shDegree: number): number {\n if (shDegree < 0 || shDegree > 2) throw new Error(`Unsupported KSPLAT SH degree ${shDegree}.`);\n const shComponents = shComponentsForDegree(shDegree);\n if (compressionLevel === 0) return 44 + shComponents * 4;\n return 24 + shComponents * shScalarBytes(compressionLevel);\n}\n\nfunction readPartialBucketLengths(view: DataView, section: KsplatSection): Uint32Array {\n const lengths = new Uint32Array(section.partialBucketCount);\n for (let i = 0; i < lengths.length; i++) lengths[i] = view.getUint32(section.base + i * 4, true);\n return lengths;\n}\n\nfunction bucketIndexForSplat(\n localIndex: number,\n section: KsplatSection,\n partialLengths: Uint32Array,\n): number {\n const fullSplats = section.fullBucketCount * section.bucketSize;\n const checked = (bucket: number): number => {\n // Belt-and-braces: a bucket index at or past bucketCount would read\n // bucket centers out of the section's storage (OOB DataView reads or\n // garbage positions from a hostile file).\n if (bucket >= section.bucketCount) {\n throw new Error(`KSPLAT splat ${localIndex} maps to out-of-range bucket ${bucket}.`);\n }\n return bucket;\n };\n if (localIndex < fullSplats) return checked(Math.floor(localIndex / section.bucketSize));\n let first = fullSplats;\n for (let i = 0; i < partialLengths.length; i++) {\n const length = partialLengths[i] as number;\n if (localIndex < first + length) return checked(section.fullBucketCount + i);\n first += length;\n }\n throw new Error(`KSPLAT splat ${localIndex} does not belong to a bucket.`);\n}\n"],"names":["HEADER_BYTES","SECTION_HEADER_BYTES","BUCKET_CENTER_BYTES","DEFAULT_SH_RANGE_HALF","parseKsplat","buffer","view","header","parseHeader","sections","parseSections","totalSectionSplats","sum","section","positions","colors","covariances","maxShDegree","max","shComponents","shComponentsForDegree","coefficients","outputIndex","partialLengths","readPartialBucketLengths","sectionShComponents","shOffset","localIndex","source","position","color","scaleOffset","rotationOffset","colorOffset","bucket","bucketIndexForSplat","bucketBase","factor","readScalar","offset","halfToFloat","scalarBytes","writeCovariance","dest","c","byteOffset","shScalarBytes","readShScalar","shPacked","packShCoefficients","compressionLevel","rangeMin","rangeMax","shDegree","versionMajor","versionMinor","maxSectionCount","sectionCount","maxSplatCount","splatCount","shCoeffMin","shCoeffMax","headersEnd","sectionBase","index","count","maxCount","bucketSize","bucketCount","bucketBlockSize","bucketStorageBytes","compressionRange","fullBucketCount","partialBucketCount","bytesPerSplat","bytesPerKsplat","bucketMetadataBytes","bucketBytes","storageBytes","lengths","i","fullSplats","checked","first","length"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ksplat.js","sources":["../../src/lib/formats/ksplat/parse-ksplat.ts"],"sourcesContent":["import { halfToFloat } from '../../core/half-float';\nimport { packShCoefficients } from '../../core/sh-pack';\nimport { writeCovariance, type SplatData } from '../../core/splat-data';\n\nconst HEADER_BYTES = 4096;\nconst SECTION_HEADER_BYTES = 1024;\nconst BUCKET_CENTER_BYTES = 12;\n/** Default 8-bit SH dequant range half-width (GaussianSplats3D `Constants`). */\nconst DEFAULT_SH_RANGE_HALF = 1.5;\n\ninterface KsplatHeader {\n versionMajor: number;\n versionMinor: number;\n sectionCount: number;\n splatCount: number;\n compressionLevel: number;\n shCoeffMin: number;\n shCoeffMax: number;\n}\n\ninterface KsplatSection {\n count: number;\n maxCount: number;\n bucketSize: number;\n bucketCount: number;\n bucketBlockSize: number;\n bucketStorageBytes: number;\n compressionRange: number;\n fullBucketCount: number;\n partialBucketCount: number;\n shDegree: number;\n bytesPerSplat: number;\n base: number;\n bucketsBase: number;\n dataBase: number;\n}\n\n/**\n * Parses a GaussianSplats3D `.ksplat` file, including compression levels 0–2.\n * Base color, opacity, position, scale, rotation and optional higher-order\n * spherical harmonics (degrees 1–2) are retained.\n *\n * @throws {Error} if the header, section layout or record data is invalid.\n */\nexport function parseKsplat(buffer: ArrayBuffer): SplatData {\n const view = new DataView(buffer);\n const header = parseHeader(view);\n const sections = parseSections(view, header);\n const totalSectionSplats = sections.reduce((sum, section) => sum + section.count, 0);\n if (totalSectionSplats !== header.splatCount) {\n throw new Error(\n `Invalid KSPLAT counts: header declares ${header.splatCount}, sections contain ${totalSectionSplats}.`,\n );\n }\n\n const positions = new Float32Array(header.splatCount * 3);\n const colors = new Uint8Array(header.splatCount * 4);\n const covariances = new Float32Array(header.splatCount * 6);\n const maxShDegree = sections.reduce((max, section) => Math.max(max, section.shDegree), 0);\n const shComponents = shComponentsForDegree(maxShDegree);\n const coefficients = shComponents > 0 ? new Float32Array(header.splatCount * shComponents) : null;\n let outputIndex = 0;\n\n for (const section of sections) {\n const partialLengths = readPartialBucketLengths(view, section);\n const sectionShComponents = shComponentsForDegree(section.shDegree);\n const shOffset = header.compressionLevel === 0 ? 44 : 24;\n for (let localIndex = 0; localIndex < section.count; localIndex++, outputIndex++) {\n const source = section.dataBase + localIndex * section.bytesPerSplat;\n const position = outputIndex * 3;\n const color = outputIndex * 4;\n const scaleOffset = header.compressionLevel === 0 ? 12 : 6;\n const rotationOffset = header.compressionLevel === 0 ? 24 : 12;\n const colorOffset = header.compressionLevel === 0 ? 40 : 20;\n\n if (header.compressionLevel === 0) {\n positions[position + 0] = view.getFloat32(source + 0, true);\n positions[position + 1] = view.getFloat32(source + 4, true);\n positions[position + 2] = view.getFloat32(source + 8, true);\n } else {\n const bucket = bucketIndexForSplat(localIndex, section, partialLengths);\n const bucketBase = section.bucketsBase + bucket * section.bucketStorageBytes;\n const factor = (section.bucketBlockSize * 0.5) / section.compressionRange;\n positions[position + 0] =\n (view.getUint16(source + 0, true) - section.compressionRange) * factor +\n view.getFloat32(bucketBase + 0, true);\n positions[position + 1] =\n (view.getUint16(source + 2, true) - section.compressionRange) * factor +\n view.getFloat32(bucketBase + 4, true);\n positions[position + 2] =\n (view.getUint16(source + 4, true) - section.compressionRange) * factor +\n view.getFloat32(bucketBase + 8, true);\n }\n\n colors[color + 0] = view.getUint8(source + colorOffset + 0);\n colors[color + 1] = view.getUint8(source + colorOffset + 1);\n colors[color + 2] = view.getUint8(source + colorOffset + 2);\n colors[color + 3] = view.getUint8(source + colorOffset + 3);\n\n const readScalar = (offset: number): number =>\n header.compressionLevel === 0\n ? view.getFloat32(source + offset, true)\n : halfToFloat(view.getUint16(source + offset, true));\n const scalarBytes = header.compressionLevel === 0 ? 4 : 2;\n writeCovariance(\n covariances,\n outputIndex,\n readScalar(scaleOffset + 0 * scalarBytes),\n readScalar(scaleOffset + 1 * scalarBytes),\n readScalar(scaleOffset + 2 * scalarBytes),\n readScalar(rotationOffset + 0 * scalarBytes),\n readScalar(rotationOffset + 1 * scalarBytes),\n readScalar(rotationOffset + 2 * scalarBytes),\n readScalar(rotationOffset + 3 * scalarBytes),\n );\n\n if (coefficients && sectionShComponents > 0) {\n const dest = outputIndex * shComponents;\n for (let c = 0; c < sectionShComponents; c++) {\n const byteOffset = shOffset + c * shScalarBytes(header.compressionLevel);\n coefficients[dest + c] = readShScalar(\n view,\n source + byteOffset,\n header.compressionLevel,\n header.shCoeffMin,\n header.shCoeffMax,\n );\n }\n }\n }\n }\n\n const shPacked =\n coefficients && maxShDegree > 0\n ? packShCoefficients(coefficients, header.splatCount, maxShDegree as 1 | 2)\n : undefined;\n\n return {\n count: header.splatCount,\n positions,\n colors,\n covariances,\n ...(shPacked ? { shPacked } : {}),\n };\n}\n\nfunction shScalarBytes(compressionLevel: number): number {\n return compressionLevel === 0 ? 4 : compressionLevel === 1 ? 2 : 1;\n}\n\nfunction readShScalar(\n view: DataView,\n offset: number,\n compressionLevel: number,\n rangeMin: number,\n rangeMax: number,\n): number {\n if (compressionLevel === 0) return view.getFloat32(offset, true);\n if (compressionLevel === 1) return halfToFloat(view.getUint16(offset, true));\n const encoded = view.getUint8(offset);\n return (encoded / 255) * (rangeMax - rangeMin) + rangeMin;\n}\n\nfunction shComponentsForDegree(shDegree: number): number {\n if (shDegree === 0) return 0;\n if (shDegree === 1) return 9;\n if (shDegree === 2) return 24;\n throw new Error(`Unsupported KSPLAT SH degree ${shDegree}.`);\n}\n\nfunction parseHeader(view: DataView): KsplatHeader {\n if (view.byteLength < HEADER_BYTES) throw new Error('Truncated KSPLAT header.');\n const versionMajor = view.getUint8(0);\n const versionMinor = view.getUint8(1);\n const maxSectionCount = view.getUint32(4, true);\n const sectionCount = view.getUint32(8, true);\n const maxSplatCount = view.getUint32(12, true);\n const splatCount = view.getUint32(16, true);\n const compressionLevel = view.getUint16(20, true);\n const shCoeffMin = view.getFloat32(36, true) || -DEFAULT_SH_RANGE_HALF;\n const shCoeffMax = view.getFloat32(40, true) || DEFAULT_SH_RANGE_HALF;\n\n if (versionMajor !== 0 || versionMinor < 1) {\n throw new Error(\n `Unsupported KSPLAT version ${versionMajor}.${versionMinor}; expected 0.1 or newer.`,\n );\n }\n if (compressionLevel < 0 || compressionLevel > 2) {\n throw new Error(`Unsupported KSPLAT compression level ${compressionLevel}.`);\n }\n if (\n !Number.isSafeInteger(maxSectionCount) ||\n sectionCount > maxSectionCount ||\n sectionCount === 0\n ) {\n throw new Error(`Invalid KSPLAT section count ${sectionCount}/${maxSectionCount}.`);\n }\n if (splatCount > maxSplatCount) {\n throw new Error(`Invalid KSPLAT splat count ${splatCount}/${maxSplatCount}.`);\n }\n const headersEnd = HEADER_BYTES + maxSectionCount * SECTION_HEADER_BYTES;\n if (!Number.isSafeInteger(headersEnd) || headersEnd > view.byteLength) {\n throw new Error('Truncated KSPLAT section headers.');\n }\n\n return {\n versionMajor,\n versionMinor,\n sectionCount,\n splatCount,\n compressionLevel,\n shCoeffMin,\n shCoeffMax,\n };\n}\n\nfunction parseSections(view: DataView, header: KsplatHeader): KsplatSection[] {\n const maxSectionCount = view.getUint32(4, true);\n let sectionBase = HEADER_BYTES + maxSectionCount * SECTION_HEADER_BYTES;\n const sections: KsplatSection[] = [];\n\n for (let index = 0; index < maxSectionCount; index++) {\n const offset = HEADER_BYTES + index * SECTION_HEADER_BYTES;\n const count = view.getUint32(offset + 0, true);\n const maxCount = view.getUint32(offset + 4, true);\n const bucketSize = view.getUint32(offset + 8, true);\n const bucketCount = view.getUint32(offset + 12, true);\n const bucketBlockSize = view.getFloat32(offset + 16, true);\n const bucketStorageBytes = view.getUint16(offset + 20, true);\n const compressionRange = view.getUint32(offset + 24, true) || 32767;\n const fullBucketCount = view.getUint32(offset + 32, true);\n const partialBucketCount = view.getUint32(offset + 36, true);\n const shDegree = view.getUint16(offset + 40, true);\n const bytesPerSplat = bytesPerKsplat(header.compressionLevel, shDegree);\n const bucketMetadataBytes = partialBucketCount * 4;\n const bucketBytes = bucketCount * bucketStorageBytes;\n const storageBytes = bucketMetadataBytes + bucketBytes + maxCount * bytesPerSplat;\n\n if (index < header.sectionCount) {\n if (count > maxCount)\n throw new Error(`Invalid KSPLAT section ${index} count ${count}/${maxCount}.`);\n if (header.compressionLevel > 0) {\n if (bucketSize === 0 || bucketCount === 0 || bucketStorageBytes < BUCKET_CENTER_BYTES) {\n throw new Error(`Invalid KSPLAT bucket layout in section ${index}.`);\n }\n if (!Number.isFinite(bucketBlockSize) || bucketBlockSize <= 0 || compressionRange === 0) {\n throw new Error(`Invalid KSPLAT compression parameters in section ${index}.`);\n }\n if (fullBucketCount + partialBucketCount > bucketCount) {\n throw new Error(\n `Invalid KSPLAT section ${index}: ${fullBucketCount} full + ` +\n `${partialBucketCount} partial buckets exceed the ${bucketCount} declared.`,\n );\n }\n }\n if (sectionBase + storageBytes > view.byteLength) {\n throw new Error(`Truncated KSPLAT data in section ${index}.`);\n }\n sections.push({\n count,\n maxCount,\n bucketSize,\n bucketCount,\n bucketBlockSize,\n bucketStorageBytes,\n compressionRange,\n fullBucketCount,\n partialBucketCount,\n shDegree,\n bytesPerSplat,\n base: sectionBase,\n bucketsBase: sectionBase + bucketMetadataBytes,\n dataBase: sectionBase + bucketMetadataBytes + bucketBytes,\n });\n }\n sectionBase += storageBytes;\n }\n return sections;\n}\n\nfunction bytesPerKsplat(compressionLevel: number, shDegree: number): number {\n if (shDegree < 0 || shDegree > 2) throw new Error(`Unsupported KSPLAT SH degree ${shDegree}.`);\n const shComponents = shComponentsForDegree(shDegree);\n if (compressionLevel === 0) return 44 + shComponents * 4;\n return 24 + shComponents * shScalarBytes(compressionLevel);\n}\n\nfunction readPartialBucketLengths(view: DataView, section: KsplatSection): Uint32Array {\n const lengths = new Uint32Array(section.partialBucketCount);\n for (let i = 0; i < lengths.length; i++) lengths[i] = view.getUint32(section.base + i * 4, true);\n return lengths;\n}\n\nfunction bucketIndexForSplat(\n localIndex: number,\n section: KsplatSection,\n partialLengths: Uint32Array,\n): number {\n const fullSplats = section.fullBucketCount * section.bucketSize;\n const checked = (bucket: number): number => {\n // Belt-and-braces: a bucket index at or past bucketCount would read\n // bucket centers out of the section's storage (OOB DataView reads or\n // garbage positions from a hostile file).\n if (bucket >= section.bucketCount) {\n throw new Error(`KSPLAT splat ${localIndex} maps to out-of-range bucket ${bucket}.`);\n }\n return bucket;\n };\n if (localIndex < fullSplats) return checked(Math.floor(localIndex / section.bucketSize));\n let first = fullSplats;\n for (let i = 0; i < partialLengths.length; i++) {\n const length = partialLengths[i] as number;\n if (localIndex < first + length) return checked(section.fullBucketCount + i);\n first += length;\n }\n throw new Error(`KSPLAT splat ${localIndex} does not belong to a bucket.`);\n}\n"],"names":["HEADER_BYTES","SECTION_HEADER_BYTES","BUCKET_CENTER_BYTES","DEFAULT_SH_RANGE_HALF","parseKsplat","buffer","view","header","parseHeader","sections","parseSections","totalSectionSplats","sum","section","positions","colors","covariances","maxShDegree","max","shComponents","shComponentsForDegree","coefficients","outputIndex","partialLengths","readPartialBucketLengths","sectionShComponents","shOffset","localIndex","source","position","color","scaleOffset","rotationOffset","colorOffset","bucket","bucketIndexForSplat","bucketBase","factor","readScalar","offset","halfToFloat","scalarBytes","writeCovariance","dest","c","byteOffset","shScalarBytes","readShScalar","shPacked","packShCoefficients","compressionLevel","rangeMin","rangeMax","shDegree","versionMajor","versionMinor","maxSectionCount","sectionCount","maxSplatCount","splatCount","shCoeffMin","shCoeffMax","headersEnd","sectionBase","index","count","maxCount","bucketSize","bucketCount","bucketBlockSize","bucketStorageBytes","compressionRange","fullBucketCount","partialBucketCount","bytesPerSplat","bytesPerKsplat","bucketMetadataBytes","bucketBytes","storageBytes","lengths","i","fullSplats","checked","first","length"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as THREE from 'three/webgpu';
|
|
2
|
-
import { type SplatRequestOptions } from '../../loading';
|
|
2
|
+
import { type SplatRequestOptions } from '../../loaders/loading';
|
|
3
3
|
import { type TriangleMeshData } from './parse-mesh-ply';
|
|
4
|
-
import type { SplatCollisionData } from '../../lod-source';
|
|
4
|
+
import type { SplatCollisionData } from '../../streaming/lod-source';
|
|
5
5
|
/**
|
|
6
6
|
* Fetches the collision-mesh tiles a streamed scene declares.
|
|
7
7
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TriangleMeshData } from './parse-mesh-ply';
|
|
2
|
-
import type { SelectionVolume } from '../../selection-volume';
|
|
2
|
+
import type { SelectionVolume } from '../../selection/selection-volume';
|
|
3
3
|
/**
|
|
4
4
|
* Splits a collision triangle mesh by the same {@link SelectionVolume} used to
|
|
5
5
|
* separate a splat region, so the separated object keeps its collision
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { LodSourceOptions, StreamedScene } from '../../lod-source';
|
|
1
|
+
import type { LodSourceOptions, StreamedScene } from '../../streaming/lod-source';
|
|
2
2
|
import { type LccManifest } from './parse-lcc';
|
|
3
|
-
import { type SplatRequestOptions } from '../../loading';
|
|
4
|
-
import type { SplatDatasetSource } from '../../dataset-source';
|
|
3
|
+
import { type SplatRequestOptions } from '../../loaders/loading';
|
|
4
|
+
import type { SplatDatasetSource } from '../../streaming/dataset-source';
|
|
5
5
|
/** Options for {@link buildLccScene} beyond the shared LOD knobs. */
|
|
6
6
|
export interface LccSceneOptions extends LodSourceOptions {
|
|
7
7
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LodSourceOptions, StreamedScene } from '../../lod-source';
|
|
2
|
-
import type { SplatDatasetSource } from '../../dataset-source';
|
|
1
|
+
import type { LodSourceOptions, StreamedScene } from '../../streaming/lod-source';
|
|
2
|
+
import type { SplatDatasetSource } from '../../streaming/dataset-source';
|
|
3
3
|
/** Builds a scene from a parsed `.lcc2` manifest (JSON already fetched). */
|
|
4
4
|
export declare function buildLcc2Scene(json: unknown, dataset: SplatDatasetSource, options: LodSourceOptions, shBands?: 0 | 1 | 2 | 3): StreamedScene;
|