@playcanvas/splat-transform 2.0.3 → 2.0.5

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.
Files changed (35) hide show
  1. package/README.md +112 -24
  2. package/dist/cli.mjs +6742 -3734
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/index.cjs +6683 -3664
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.mjs +6683 -3664
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/lib/gpu/gpu-dilation.d.ts +87 -0
  9. package/dist/lib/gpu/gpu-voxelization.d.ts +2 -1
  10. package/dist/lib/gpu/index.d.ts +1 -0
  11. package/dist/lib/index.d.cts +1 -1
  12. package/dist/lib/index.d.ts +1 -1
  13. package/dist/lib/io/write/memory-file-system.d.ts +1 -1
  14. package/dist/lib/mesh/index.d.ts +2 -1
  15. package/dist/lib/mesh/marching-cubes.d.ts +19 -6
  16. package/dist/lib/mesh/voxel-faces.d.ts +18 -0
  17. package/dist/lib/spatial/gaussian-bvh.d.ts +34 -0
  18. package/dist/lib/types.d.ts +10 -3
  19. package/dist/lib/utils/math.d.ts +2 -1
  20. package/dist/lib/voxel/block-cleanup.d.ts +6 -3
  21. package/dist/lib/voxel/block-mask-buffer.d.ts +18 -19
  22. package/dist/lib/voxel/block-mask-map.d.ts +5 -0
  23. package/dist/lib/voxel/carve.d.ts +3 -2
  24. package/dist/lib/voxel/dilation.d.ts +12 -15
  25. package/dist/lib/voxel/fill-exterior.d.ts +4 -3
  26. package/dist/lib/voxel/fill-floor.d.ts +10 -6
  27. package/dist/lib/voxel/flood-fill.d.ts +4 -1
  28. package/dist/lib/voxel/grid-ops.d.ts +2 -1
  29. package/dist/lib/voxel/morton.d.ts +1 -17
  30. package/dist/lib/voxel/sparse-voxel-grid.d.ts +52 -5
  31. package/dist/lib/voxel/voxel-query.d.ts +14 -9
  32. package/dist/lib/writers/collision-glb.d.ts +7 -8
  33. package/dist/lib/writers/sparse-octree.d.ts +15 -14
  34. package/dist/lib/writers/write-voxel.d.ts +14 -5
  35. package/package.json +1 -1
@@ -24,14 +24,14 @@ interface BlockGridParams {
24
24
  strideZ: number;
25
25
  }
26
26
  /**
27
- * Build block lookup structures from the buffer's Morton codes.
27
+ * Build block lookup structures from the buffer's linear block indices.
28
+ * The buffer's keys are already linear block indices, so this is a direct
29
+ * copy into a Set / Map for O(1) random access.
28
30
  *
29
31
  * @param buffer - Block mask buffer containing voxelized blocks.
30
- * @param strideY - numBlocksX (stride for Y dimension).
31
- * @param strideZ - numBlocksX * numBlocksY (stride for Z dimension).
32
32
  * @returns Solid block set, mixed block map (linear index to masks array index), and masks.
33
33
  */
34
- declare const buildBlockLookup: (buffer: BlockMaskBuffer, strideY: number, strideZ: number) => BlockLookup;
34
+ declare const buildBlockLookup: (buffer: BlockMaskBuffer) => BlockLookup;
35
35
  /**
36
36
  * Test whether a Gaussian's center lies inside an occupied voxel.
37
37
  *
@@ -45,11 +45,15 @@ declare const buildBlockLookup: (buffer: BlockMaskBuffer, strideY: number, strid
45
45
  */
46
46
  declare const isCenterInOccupiedVoxel: (px: number, py: number, pz: number, grid: BlockGridParams, lookup: BlockLookup, blockFilter?: Set<number>) => boolean;
47
47
  /**
48
- * Test whether a Gaussian has meaningful contribution at any occupied voxel
49
- * center within its AABB range.
48
+ * Test whether a Gaussian has meaningful contribution at occupied voxel
49
+ * centers in blocks that overlap its AABB.
50
50
  *
51
51
  * Iterates over blocks that overlap the Gaussian's AABB, then evaluates the
52
- * Gaussian's opacity contribution at each occupied voxel center in those blocks.
52
+ * Gaussian's opacity contribution at each occupied voxel center in those
53
+ * blocks. Returns true once `minHits` qualifying voxels are found. With the
54
+ * default `minHits = 1` this short-circuits on the first hit; larger values
55
+ * let callers reject elongated outliers (e.g. spikes) whose tails clip only
56
+ * a single cluster voxel.
53
57
  *
54
58
  * @param gaussianIdx - Index of the Gaussian.
55
59
  * @param columns - Gaussian column data arrays.
@@ -57,7 +61,8 @@ declare const isCenterInOccupiedVoxel: (px: number, py: number, pz: number, grid
57
61
  * @param lookup - Block lookup structures.
58
62
  * @param minContribution - Minimum contribution threshold.
59
63
  * @param blockFilter - Optional set of block indices to restrict the test to.
60
- * @returns True if the Gaussian contributes above threshold at any qualifying voxel.
64
+ * @param minHits - Minimum number of qualifying voxels required. Default 1.
65
+ * @returns True if at least `minHits` qualifying voxels were found.
61
66
  */
62
- declare const gaussianContributesToVoxels: (gaussianIdx: number, columns: GaussianColumns, grid: BlockGridParams, lookup: BlockLookup, minContribution: number, blockFilter?: Set<number>) => boolean;
67
+ declare const gaussianContributesToVoxels: (gaussianIdx: number, columns: GaussianColumns, grid: BlockGridParams, lookup: BlockLookup, minContribution: number, blockFilter?: Set<number>, minHits?: number) => boolean;
63
68
  export { buildBlockLookup, isCenterInOccupiedVoxel, gaussianContributesToVoxels, type BlockLookup, type BlockGridParams };
@@ -1,18 +1,17 @@
1
1
  import type { Bounds } from '../data-table';
2
- import { BlockMaskBuffer } from '../voxel/block-mask-buffer';
2
+ import type { CollisionMeshShape } from '../types';
3
+ import { SparseVoxelGrid } from '../voxel/sparse-voxel-grid';
3
4
  /**
4
5
  * Extract a collision mesh from voxel data and encode it as a GLB file.
5
6
  *
6
- * Runs marching cubes on the voxel surface, then a lossless coplanar-merge
7
- * pass that fuses the redundant axis-aligned triangles inside each
8
- * voxel-face plane into greedy-style quads while leaving the corner-cutting
9
- * bevel triangles untouched. The output surface is identical to the raw MC
10
- * surface but typically has 1-2 orders of magnitude fewer triangles.
7
+ * Generates collision geometry from voxel data using either the smooth
8
+ * marching-cubes path or a direct watertight voxel-face mesh.
11
9
  *
12
- * @param blockBuffer - Voxel block data after filtering
10
+ * @param grid - Voxel grid after filtering / nav phases
13
11
  * @param gridBounds - Grid bounds aligned to block boundaries
14
12
  * @param voxelResolution - Size of each voxel in world units
13
+ * @param shape - Collision mesh shape to generate
15
14
  * @returns GLB bytes, or null if no triangles were generated
16
15
  */
17
- declare const buildCollisionMesh: (blockBuffer: BlockMaskBuffer, gridBounds: Bounds, voxelResolution: number) => Uint8Array | null;
16
+ declare const buildCollisionMesh: (grid: SparseVoxelGrid, gridBounds: Bounds, voxelResolution: number, shape?: CollisionMeshShape) => Uint8Array | null;
18
17
  export { buildCollisionMesh };
@@ -1,5 +1,5 @@
1
1
  import type { Bounds } from '../data-table';
2
- import { BlockMaskBuffer } from '../voxel/block-mask-buffer';
2
+ import { SparseVoxelGrid } from '../voxel/sparse-voxel-grid';
3
3
  /**
4
4
  * Solid leaf node marker: childMask = 0xFF, baseOffset = 0.
5
5
  * This is unambiguous because BFS layout guarantees children always come after
@@ -29,26 +29,27 @@ interface SparseOctree {
29
29
  /** Voxel masks for mixed leaves: pairs of u32 (lo, hi) */
30
30
  leafData: Uint32Array;
31
31
  }
32
+ interface BuildSparseOctreeOptions {
33
+ /** Release the input grid's backing storage after the octree has copied the data it needs. */
34
+ consumeGrid?: boolean;
35
+ /** Force dense-mip construction; intended for tests and benchmarks. */
36
+ dense?: boolean;
37
+ }
32
38
  /**
33
- * Build a sparse octree from accumulated voxelization blocks.
34
- *
35
- * Uses Structure-of-Arrays (SoA) representation and linear scans on sorted
36
- * Morton codes instead of Maps and per-node objects for performance.
39
+ * Build a sparse octree from a SparseVoxelGrid.
37
40
  *
38
- * **Mutates `buffer` in place.** Phase 1 sorts the buffer's solid-morton,
39
- * mixed-morton, and mixed-mask typed arrays directly (no SoA copy) to keep
40
- * peak memory low on very large grids. After this call the buffer's blocks
41
- * are still semantically equivalent same morton/mask pairs but reordered
42
- * by morton ascending. Callers must not rely on insertion order being
43
- * preserved across this call.
41
+ * Walks the grid's `types` array word-by-word (skipping empty words), counts
42
+ * solid + mixed blocks, then emits Morton-keyed (solidStream, mixedStream,
43
+ * mixedMasks) typed arrays sized exactly. The streams are then sorted; this
44
+ * is the only place Morton encoding is paid in the post-voxelization pipeline.
44
45
  *
45
- * @param buffer - BlockMaskBuffer containing voxelized blocks. Mutated:
46
- * solid mortons, mixed mortons, and mixed masks are sorted in place.
46
+ * @param grid - SparseVoxelGrid containing voxelized blocks.
47
47
  * @param gridBounds - Grid bounds aligned to block boundaries
48
48
  * @param sceneBounds - Original scene bounds
49
49
  * @param voxelResolution - Size of each voxel in world units
50
+ * @param options - Build options.
50
51
  * @returns Sparse octree structure
51
52
  */
52
- declare function buildSparseOctree(buffer: BlockMaskBuffer, gridBounds: Bounds, sceneBounds: Bounds, voxelResolution: number): SparseOctree;
53
+ declare function buildSparseOctree(grid: SparseVoxelGrid, gridBounds: Bounds, sceneBounds: Bounds, voxelResolution: number, options?: BuildSparseOctreeOptions): SparseOctree;
53
54
  export { buildSparseOctree, SOLID_LEAF_MARKER };
54
55
  export type { SparseOctree };
@@ -1,6 +1,7 @@
1
1
  import { DataTable } from '../data-table';
2
2
  import { type FileSystem } from '../io/write';
3
- import type { DeviceCreator } from '../types';
3
+ import type { CollisionMeshShape, DeviceCreator } from '../types';
4
+ import { type SparseOctree } from './sparse-octree';
4
5
  import { type NavSeed } from '../voxel';
5
6
  /**
6
7
  * Options for writing a voxel octree file.
@@ -29,8 +30,8 @@ type WriteVoxelOptions = {
29
30
  floorFill?: boolean;
30
31
  /** When `floorFill` is enabled, dilation radius in world units used to identify "interior" XZ columns to patch. Empty XZ areas larger than `2 * floorFillDilation` from any solid column are treated as exterior and left empty. Default: 0 (patch every empty column). */
31
32
  floorFillDilation?: number;
32
- /** When `true`, a collision mesh (.collision.glb) is generated alongside the voxel output, using marching cubes followed by lossless coplanar merge. */
33
- collisionMesh?: boolean;
33
+ /** When set, a collision mesh (.collision.glb) is generated alongside the voxel output. `true` is equivalent to `smooth`. */
34
+ collisionMesh?: boolean | CollisionMeshShape;
34
35
  };
35
36
  /**
36
37
  * Metadata for a voxel octree file.
@@ -63,6 +64,14 @@ interface VoxelMetadata {
63
64
  /** Total number of Uint32 entries in the leafData array */
64
65
  leafDataCount: number;
65
66
  }
67
+ /**
68
+ * Write octree data to files.
69
+ *
70
+ * @param fs - File system for writing output files.
71
+ * @param jsonFilename - Output filename for JSON metadata.
72
+ * @param octree - Sparse octree structure to write.
73
+ */
74
+ declare const writeOctreeFiles: (fs: FileSystem, jsonFilename: string, octree: SparseOctree) => Promise<void>;
66
75
  /**
67
76
  * Voxelizes Gaussian splat data and writes the result as a sparse voxel octree.
68
77
  *
@@ -70,7 +79,7 @@ interface VoxelMetadata {
70
79
  * and outputs two or three files:
71
80
  * - `filename` (.voxel.json) - JSON metadata including bounds, resolution, and array sizes
72
81
  * - Corresponding .voxel.bin - Binary octree data (nodes + leafData as Uint32 arrays)
73
- * - Corresponding .collision.glb - Triangle mesh extracted via marching cubes (GLB format, optional)
82
+ * - Corresponding .collision.glb - Triangle mesh extracted from the voxel output (GLB format, optional)
74
83
  *
75
84
  * The binary file layout is:
76
85
  * - Bytes 0 to (nodeCount * 4 - 1): nodes array (Uint32, little-endian)
@@ -95,4 +104,4 @@ interface VoxelMetadata {
95
104
  * ```
96
105
  */
97
106
  declare const writeVoxel: (options: WriteVoxelOptions, fs: FileSystem) => Promise<void>;
98
- export { writeVoxel, type WriteVoxelOptions, type VoxelMetadata };
107
+ export { writeVoxel, writeOctreeFiles, type WriteVoxelOptions, type VoxelMetadata };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcanvas/splat-transform",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "author": "PlayCanvas<support@playcanvas.com>",
5
5
  "homepage": "https://playcanvas.com",
6
6
  "description": "Library and CLI tool for 3D Gaussian splat format conversion and transformation",