@playcanvas/splat-transform 2.0.3 → 2.0.4
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 +4 -1
- package/dist/cli.mjs +6701 -3666
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +6683 -3664
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +6683 -3664
- package/dist/index.mjs.map +1 -1
- package/dist/lib/gpu/gpu-dilation.d.ts +87 -0
- package/dist/lib/gpu/gpu-voxelization.d.ts +2 -1
- package/dist/lib/gpu/index.d.ts +1 -0
- package/dist/lib/index.d.cts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/io/write/memory-file-system.d.ts +1 -1
- package/dist/lib/mesh/index.d.ts +2 -1
- package/dist/lib/mesh/marching-cubes.d.ts +19 -6
- package/dist/lib/mesh/voxel-faces.d.ts +18 -0
- package/dist/lib/spatial/gaussian-bvh.d.ts +34 -0
- package/dist/lib/types.d.ts +10 -3
- package/dist/lib/utils/math.d.ts +2 -1
- package/dist/lib/voxel/block-cleanup.d.ts +6 -3
- package/dist/lib/voxel/block-mask-buffer.d.ts +18 -19
- package/dist/lib/voxel/block-mask-map.d.ts +5 -0
- package/dist/lib/voxel/carve.d.ts +3 -2
- package/dist/lib/voxel/dilation.d.ts +12 -15
- package/dist/lib/voxel/fill-exterior.d.ts +4 -3
- package/dist/lib/voxel/fill-floor.d.ts +10 -6
- package/dist/lib/voxel/flood-fill.d.ts +4 -1
- package/dist/lib/voxel/grid-ops.d.ts +2 -1
- package/dist/lib/voxel/morton.d.ts +1 -17
- package/dist/lib/voxel/sparse-voxel-grid.d.ts +52 -5
- package/dist/lib/voxel/voxel-query.d.ts +14 -9
- package/dist/lib/writers/collision-glb.d.ts +7 -8
- package/dist/lib/writers/sparse-octree.d.ts +15 -14
- package/dist/lib/writers/write-voxel.d.ts +14 -5
- package/package.json +1 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { GraphicsDevice } from 'playcanvas';
|
|
2
|
+
import type { SparseVoxelGrid } from '../voxel/sparse-voxel-grid';
|
|
3
|
+
/**
|
|
4
|
+
* Separable 3D dilation on the GPU using a row-aligned dense bit grid
|
|
5
|
+
* (1 bit per voxel, packed into u32 words; each row of bits along X starts
|
|
6
|
+
* on a word boundary so per-word access is trivial). Each pass owns its
|
|
7
|
+
* own `Compute` instance because their uniform buffers must not collide
|
|
8
|
+
* within a single submit.
|
|
9
|
+
*/
|
|
10
|
+
declare class GpuDilation {
|
|
11
|
+
private device;
|
|
12
|
+
private dilateXShader;
|
|
13
|
+
private dilateYZShader;
|
|
14
|
+
private clearShader;
|
|
15
|
+
private extractShader;
|
|
16
|
+
private compactShader;
|
|
17
|
+
private dilateXBindGroupFormat;
|
|
18
|
+
private dilateYZBindGroupFormat;
|
|
19
|
+
private clearBindGroupFormat;
|
|
20
|
+
private extractBindGroupFormat;
|
|
21
|
+
private compactBindGroupFormat;
|
|
22
|
+
private slots;
|
|
23
|
+
private srcTypesBuffer;
|
|
24
|
+
private srcKeysBuffer;
|
|
25
|
+
private srcLoBuffer;
|
|
26
|
+
private srcHiBuffer;
|
|
27
|
+
private srcTypesCapacity;
|
|
28
|
+
private srcMasksCapacity;
|
|
29
|
+
private srcMeta;
|
|
30
|
+
/** Number of double-buffered dispatch slots. */
|
|
31
|
+
static readonly NUM_SLOTS = 2;
|
|
32
|
+
constructor(device: GraphicsDevice);
|
|
33
|
+
private ensureSlotBuffers;
|
|
34
|
+
/**
|
|
35
|
+
* Dispatch a compute clear of `dst` to zero for the first `numWords` words.
|
|
36
|
+
* Uses the command encoder so it's correctly ordered with subsequent
|
|
37
|
+
* dilation passes (unlike `queue.writeBuffer`, which is queued separately
|
|
38
|
+
* and would race against the dispatches).
|
|
39
|
+
* @param slot - Per-chunk slot whose `clearCompute` pipeline is dispatched.
|
|
40
|
+
* @param dst - Destination buffer to zero.
|
|
41
|
+
* @param numWords - Number of leading u32 words to clear.
|
|
42
|
+
*/
|
|
43
|
+
private dispatchClear;
|
|
44
|
+
/**
|
|
45
|
+
* Upload a `SparseVoxelGrid` to GPU storage buffers used by the extract
|
|
46
|
+
* shader. Reuses the existing buffers if they're large enough; otherwise
|
|
47
|
+
* destroys and reallocates. Designed to be called once per
|
|
48
|
+
* `gpuDilate3` call (the same `src` is read across all chunks).
|
|
49
|
+
* @param src - Source sparse grid to upload.
|
|
50
|
+
*/
|
|
51
|
+
uploadSrc(src: SparseVoxelGrid): void;
|
|
52
|
+
/** Free uploaded `src` buffers. Caller can call after `gpuDilate3` finishes. */
|
|
53
|
+
releaseSrc(): void;
|
|
54
|
+
private ensureSlotOutputBuffers;
|
|
55
|
+
/**
|
|
56
|
+
* Sparse-path submit. Reads from the previously-uploaded `src` (via
|
|
57
|
+
* `uploadSrc`), runs extract → dilate → compact as GPU passes, and returns
|
|
58
|
+
* Promises for the per-block `typesOut` (packed 2-bit) and `masksOut`
|
|
59
|
+
* (lo/hi pairs). Caller integrates these into `dst` directly.
|
|
60
|
+
* @param slotIdx - Round-robin slot index (`0..NUM_SLOTS-1`).
|
|
61
|
+
* @param minBx - Outer chunk origin block X (in `src`'s block coords).
|
|
62
|
+
* @param minBy - Outer chunk origin block Y.
|
|
63
|
+
* @param minBz - Outer chunk origin block Z.
|
|
64
|
+
* @param outerBx - Outer chunk size in blocks along X.
|
|
65
|
+
* @param outerBy - Outer chunk size in blocks along Y.
|
|
66
|
+
* @param outerBz - Outer chunk size in blocks along Z.
|
|
67
|
+
* @param haloBx - Halo size in blocks along X (one side).
|
|
68
|
+
* @param haloBy - Halo size in blocks along Y (one side).
|
|
69
|
+
* @param haloBz - Halo size in blocks along Z (one side).
|
|
70
|
+
* @param innerBx - Inner (output) region size in blocks along X.
|
|
71
|
+
* @param innerBy - Inner region size in blocks along Y.
|
|
72
|
+
* @param innerBz - Inner region size in blocks along Z.
|
|
73
|
+
* @param halfExtentXZ - Dilation half-extent in voxels along X and Z.
|
|
74
|
+
* @param halfExtentY - Dilation half-extent in voxels along Y.
|
|
75
|
+
* @returns Promises for the inner region's packed types and `[lo, hi]` masks.
|
|
76
|
+
*/
|
|
77
|
+
submitChunkSparse(slotIdx: number, minBx: number, minBy: number, minBz: number, outerBx: number, outerBy: number, outerBz: number, haloBx: number, haloBy: number, haloBz: number, innerBx: number, innerBy: number, innerBz: number, halfExtentXZ: number, halfExtentY: number): {
|
|
78
|
+
types: Promise<Uint32Array>;
|
|
79
|
+
masks: Promise<Uint32Array>;
|
|
80
|
+
};
|
|
81
|
+
private dispatchExtract;
|
|
82
|
+
private dispatchCompact;
|
|
83
|
+
private dispatchX;
|
|
84
|
+
private dispatchYZ;
|
|
85
|
+
destroy(): void;
|
|
86
|
+
}
|
|
87
|
+
export { GpuDilation };
|
|
@@ -49,9 +49,10 @@ declare class GpuVoxelization {
|
|
|
49
49
|
private gaussianBuffer;
|
|
50
50
|
private slots;
|
|
51
51
|
private totalGaussians;
|
|
52
|
-
private zeroBuffer;
|
|
53
52
|
/** Floats per Gaussian in the interleaved buffer (16 for alignment) */
|
|
54
53
|
private static readonly FLOATS_PER_GAUSSIAN;
|
|
54
|
+
/** Gaussian rows per CPU staging chunk when uploading to the shared GPU buffer. */
|
|
55
|
+
private static readonly UPLOAD_CHUNK_GAUSSIANS;
|
|
55
56
|
/** Maximum blocks per batch (16^3 = 4096 for 4x4x4 voxel blocks in a 16-block batch) */
|
|
56
57
|
static readonly MAX_BLOCKS_PER_BATCH = 4096;
|
|
57
58
|
/** Number of u32 fields per BatchInfo struct */
|
package/dist/lib/gpu/index.d.ts
CHANGED
package/dist/lib/index.d.cts
CHANGED
|
@@ -17,5 +17,5 @@ export { writeSog, writePly, writeCompressedPly, writeCsv, writeHtml, writeLod,
|
|
|
17
17
|
export type { WriteVoxelOptions, VoxelMetadata } from './writers';
|
|
18
18
|
export { carve, fillExterior, fillFloor, filterCluster, filterFloaters, findClusterVoxelFlood, voxelizeToBuffer } from './voxel';
|
|
19
19
|
export type { NavSeed, NavSimplifyResult } from './voxel';
|
|
20
|
-
export type { Options, Param, DeviceCreator } from './types';
|
|
20
|
+
export type { CollisionMeshShape, Options, Param, DeviceCreator } from './types';
|
|
21
21
|
export { version, revision } from './version';
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -17,5 +17,5 @@ export { writeSog, writePly, writeCompressedPly, writeCsv, writeHtml, writeLod,
|
|
|
17
17
|
export type { WriteVoxelOptions, VoxelMetadata } from './writers';
|
|
18
18
|
export { carve, fillExterior, fillFloor, filterCluster, filterFloaters, findClusterVoxelFlood, voxelizeToBuffer } from './voxel';
|
|
19
19
|
export type { NavSeed, NavSimplifyResult } from './voxel';
|
|
20
|
-
export type { Options, Param, DeviceCreator } from './types';
|
|
20
|
+
export type { CollisionMeshShape, Options, Param, DeviceCreator } from './types';
|
|
21
21
|
export { version, revision } from './version';
|
|
@@ -17,6 +17,6 @@ import { type FileSystem, type Writer } from './file-system';
|
|
|
17
17
|
declare class MemoryFileSystem implements FileSystem {
|
|
18
18
|
results: Map<string, Uint8Array>;
|
|
19
19
|
createWriter(filename: string): Writer;
|
|
20
|
-
mkdir(
|
|
20
|
+
mkdir(_path: string): Promise<void>;
|
|
21
21
|
}
|
|
22
22
|
export { MemoryFileSystem };
|
package/dist/lib/mesh/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { marchingCubes } from './marching-cubes';
|
|
2
|
-
export type { Mesh, MarchingCubesMesh } from './marching-cubes';
|
|
2
|
+
export type { Mesh, MarchingCubesMesh, MarchingCubesOptions } from './marching-cubes';
|
|
3
3
|
export { coplanarMerge } from './coplanar-merge';
|
|
4
|
+
export { voxelFaces } from './voxel-faces';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Bounds } from '../data-table';
|
|
2
|
-
import {
|
|
2
|
+
import { SparseVoxelGrid } from '../voxel/sparse-voxel-grid';
|
|
3
3
|
/**
|
|
4
4
|
* A simple triangle mesh with positions and indices.
|
|
5
5
|
*/
|
|
@@ -14,17 +14,30 @@ interface Mesh {
|
|
|
14
14
|
*/
|
|
15
15
|
type MarchingCubesMesh = Mesh;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Options for marching cubes extraction.
|
|
18
|
+
*/
|
|
19
|
+
interface MarchingCubesOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Pre-merge exact full-face cells on flat axis-aligned regions before
|
|
22
|
+
* creating the mesh. Ambiguous and bevel cases still use normal marching
|
|
23
|
+
* cubes, so coplanarMerge can apply the final lossless optimization.
|
|
24
|
+
*/
|
|
25
|
+
mergeFlatFaces?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extract a triangle mesh from a SparseVoxelGrid using marching cubes.
|
|
18
29
|
*
|
|
19
30
|
* Each voxel is treated as a cell in the marching cubes grid. Corner values
|
|
20
31
|
* are binary (0 = empty, 1 = occupied) with a 0.5 threshold. Vertices are
|
|
21
|
-
* placed at edge midpoints, producing
|
|
32
|
+
* placed at edge midpoints, producing the binary-field isosurface between
|
|
33
|
+
* occupied and empty samples.
|
|
22
34
|
*
|
|
23
|
-
* @param
|
|
35
|
+
* @param grid - Voxel grid (after filtering / nav phases)
|
|
24
36
|
* @param gridBounds - Grid bounds aligned to block boundaries
|
|
25
37
|
* @param voxelResolution - Size of each voxel in world units
|
|
38
|
+
* @param options - Optional extraction settings
|
|
26
39
|
* @returns Mesh with positions and indices
|
|
27
40
|
*/
|
|
28
|
-
declare function marchingCubes(
|
|
41
|
+
declare function marchingCubes(grid: SparseVoxelGrid, gridBounds: Bounds, voxelResolution: number, options?: MarchingCubesOptions): MarchingCubesMesh;
|
|
29
42
|
export { marchingCubes };
|
|
30
|
-
export type { Mesh, MarchingCubesMesh };
|
|
43
|
+
export type { Mesh, MarchingCubesMesh, MarchingCubesOptions };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Bounds } from '../data-table';
|
|
2
|
+
import type { Mesh } from './marching-cubes';
|
|
3
|
+
import { SparseVoxelGrid } from '../voxel/sparse-voxel-grid';
|
|
4
|
+
/**
|
|
5
|
+
* Extract a watertight voxel-boundary mesh from a SparseVoxelGrid.
|
|
6
|
+
*
|
|
7
|
+
* Exposed voxel faces are first greedily merged into axis-aligned rectangles.
|
|
8
|
+
* Rectangle boundaries are then split at every collinear rectangle corner
|
|
9
|
+
* before triangulation, so adjacent rectangles share matching edges instead
|
|
10
|
+
* of producing T-junctions.
|
|
11
|
+
*
|
|
12
|
+
* @param grid - Voxel grid after filtering / nav phases.
|
|
13
|
+
* @param gridBounds - Grid bounds aligned to block boundaries.
|
|
14
|
+
* @param voxelResolution - Size of each voxel in world units.
|
|
15
|
+
* @returns Mesh with positions and indices.
|
|
16
|
+
*/
|
|
17
|
+
declare const voxelFaces: (grid: SparseVoxelGrid, gridBounds: Bounds, voxelResolution: number) => Mesh;
|
|
18
|
+
export { voxelFaces };
|
|
@@ -86,6 +86,24 @@ declare class GaussianBVH {
|
|
|
86
86
|
* @returns Array of Gaussian indices that overlap the box
|
|
87
87
|
*/
|
|
88
88
|
queryOverlappingRaw(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number): number[];
|
|
89
|
+
/**
|
|
90
|
+
* Query overlapping Gaussian indices directly into a caller-provided buffer.
|
|
91
|
+
*
|
|
92
|
+
* Returns the total number of matches even if the target buffer is too
|
|
93
|
+
* small; in that case only the prefix that fits is written and the caller
|
|
94
|
+
* can grow the buffer then retry.
|
|
95
|
+
*
|
|
96
|
+
* @param minX - Minimum X of query box
|
|
97
|
+
* @param minY - Minimum Y of query box
|
|
98
|
+
* @param minZ - Minimum Z of query box
|
|
99
|
+
* @param maxX - Maximum X of query box
|
|
100
|
+
* @param maxY - Maximum Y of query box
|
|
101
|
+
* @param maxZ - Maximum Z of query box
|
|
102
|
+
* @param result - Buffer to append matching Gaussian indices into.
|
|
103
|
+
* @param offset - Starting element offset in `result`.
|
|
104
|
+
* @returns Number of matching Gaussian indices.
|
|
105
|
+
*/
|
|
106
|
+
queryOverlappingRawInto(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, result: Uint32Array, offset: number): number;
|
|
89
107
|
/**
|
|
90
108
|
* Recursive query helper.
|
|
91
109
|
*
|
|
@@ -99,6 +117,22 @@ declare class GaussianBVH {
|
|
|
99
117
|
* @param result - Array to append matching indices to
|
|
100
118
|
*/
|
|
101
119
|
private queryNode;
|
|
120
|
+
/**
|
|
121
|
+
* Recursive typed-buffer query helper.
|
|
122
|
+
*
|
|
123
|
+
* @param node - Current BVH node to query
|
|
124
|
+
* @param minX - Query box minimum X
|
|
125
|
+
* @param minY - Query box minimum Y
|
|
126
|
+
* @param minZ - Query box minimum Z
|
|
127
|
+
* @param maxX - Query box maximum X
|
|
128
|
+
* @param maxY - Query box maximum Y
|
|
129
|
+
* @param maxZ - Query box maximum Z
|
|
130
|
+
* @param result - Buffer to append matching indices into
|
|
131
|
+
* @param offset - Starting element offset in `result`
|
|
132
|
+
* @param count - Number of matches already found for this query
|
|
133
|
+
* @returns Updated match count
|
|
134
|
+
*/
|
|
135
|
+
private queryNodeInto;
|
|
102
136
|
/**
|
|
103
137
|
* Get the total number of Gaussians in the BVH.
|
|
104
138
|
*
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collision mesh shape generated alongside voxel output.
|
|
3
|
+
*
|
|
4
|
+
* - `smooth` - marching cubes with lossless coplanar merge.
|
|
5
|
+
* - `faces` - direct watertight voxel-boundary faces.
|
|
6
|
+
*/
|
|
7
|
+
type CollisionMeshShape = 'smooth' | 'faces';
|
|
1
8
|
/**
|
|
2
9
|
* Options for read/write operations.
|
|
3
10
|
*/
|
|
@@ -35,8 +42,8 @@ type Options = {
|
|
|
35
42
|
y: number;
|
|
36
43
|
z: number;
|
|
37
44
|
};
|
|
38
|
-
/** When
|
|
39
|
-
collisionMesh?: boolean;
|
|
45
|
+
/** When set, a collision mesh (.collision.glb) is generated alongside the voxel output. `true` is equivalent to `smooth`. */
|
|
46
|
+
collisionMesh?: boolean | CollisionMeshShape;
|
|
40
47
|
};
|
|
41
48
|
/**
|
|
42
49
|
* Parameter passed to MJS generator scripts.
|
|
@@ -55,4 +62,4 @@ type Param = {
|
|
|
55
62
|
* @returns Promise resolving to a GraphicsDevice instance.
|
|
56
63
|
*/
|
|
57
64
|
type DeviceCreator = () => Promise<import('playcanvas').GraphicsDevice>;
|
|
58
|
-
export type { Options, Param, DeviceCreator };
|
|
65
|
+
export type { CollisionMeshShape, Options, Param, DeviceCreator };
|
package/dist/lib/utils/math.d.ts
CHANGED
|
@@ -92,7 +92,8 @@ declare class Transform {
|
|
|
92
92
|
static IDENTITY: Readonly<Transform>;
|
|
93
93
|
/**
|
|
94
94
|
* PLY coordinate convention: 180-degree rotation around Z.
|
|
95
|
-
* Used by
|
|
95
|
+
* Used by formats that store Gaussian data in PLY-style coordinates:
|
|
96
|
+
* PLY, splat, KSplat, SPZ, and SOG.
|
|
96
97
|
*/
|
|
97
98
|
static PLY: Readonly<Transform>;
|
|
98
99
|
}
|
|
@@ -9,8 +9,11 @@ import { BlockMaskBuffer } from './block-mask-buffer';
|
|
|
9
9
|
*
|
|
10
10
|
* Blocks that become empty or solid as a consequence are handled automatically.
|
|
11
11
|
*
|
|
12
|
-
* @param buffer - BlockMaskBuffer with voxelization results
|
|
13
|
-
* @
|
|
12
|
+
* @param buffer - BlockMaskBuffer with voxelization results (linear-keyed).
|
|
13
|
+
* @param nbx - Grid block dimension X (used to decode block indices).
|
|
14
|
+
* @param nby - Grid block dimension Y (used to decode block indices).
|
|
15
|
+
* @param nbz - Grid block dimension Z (used for neighbor bounds checks).
|
|
16
|
+
* @returns New BlockMaskBuffer with filtered/filled data.
|
|
14
17
|
*/
|
|
15
|
-
declare function filterAndFillBlocks(buffer: BlockMaskBuffer): BlockMaskBuffer;
|
|
18
|
+
declare function filterAndFillBlocks(buffer: BlockMaskBuffer, nbx: number, nby: number, nbz: number): BlockMaskBuffer;
|
|
16
19
|
export { filterAndFillBlocks };
|
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Append-only buffer for streaming voxelization results.
|
|
3
|
-
* Stores
|
|
3
|
+
* Stores (linear blockIdx, voxel mask) pairs for non-empty 4x4x4 blocks.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* above V8's regular-array backing-store limit so very large grids can
|
|
9
|
-
* round-trip without throwing `RangeError: Invalid array length`.
|
|
5
|
+
* Block keys are linear block indices `bx + by*nbx + bz*nbx*nby` in the
|
|
6
|
+
* producer's grid coordinate system. Producers and consumers must agree
|
|
7
|
+
* on the grid dimensions; the buffer itself is dimension-agnostic.
|
|
10
8
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* Backed by typed arrays that grow geometrically. Keys use Float64Array so
|
|
10
|
+
* the per-buffer capacity exceeds V8's regular-array backing-store limit
|
|
11
|
+
* (large grids exceed Smi range and would throw `RangeError: Invalid array
|
|
12
|
+
* length` with a regular array).
|
|
14
13
|
*/
|
|
15
14
|
declare class BlockMaskBuffer {
|
|
16
|
-
/**
|
|
17
|
-
private
|
|
15
|
+
/** Linear block indices for solid blocks (mask is implicitly all 1s) */
|
|
16
|
+
private _solidIdx;
|
|
18
17
|
private _solidCount;
|
|
19
18
|
private _solidCap;
|
|
20
|
-
/**
|
|
21
|
-
private
|
|
19
|
+
/** Linear block indices for mixed blocks */
|
|
20
|
+
private _mixedIdx;
|
|
22
21
|
private _mixedCount;
|
|
23
22
|
private _mixedCap;
|
|
24
23
|
/** Interleaved voxel masks for mixed blocks: [lo0, hi0, lo1, hi1, ...] */
|
|
@@ -27,25 +26,25 @@ declare class BlockMaskBuffer {
|
|
|
27
26
|
* Add a non-empty block to the buffer.
|
|
28
27
|
* Automatically classifies as solid or mixed based on mask values.
|
|
29
28
|
*
|
|
30
|
-
* @param
|
|
29
|
+
* @param blockIdx - Linear block index (`bx + by*nbx + bz*nbx*nby`)
|
|
31
30
|
* @param lo - Lower 32 bits of voxel mask
|
|
32
31
|
* @param hi - Upper 32 bits of voxel mask
|
|
33
32
|
*/
|
|
34
|
-
addBlock(
|
|
33
|
+
addBlock(blockIdx: number, lo: number, hi: number): void;
|
|
35
34
|
/**
|
|
36
35
|
* Get all mixed blocks as views into the underlying buffers.
|
|
37
|
-
* Index `i` of `
|
|
36
|
+
* Index `i` of `blockIdx` corresponds to mask pair `(masks[i*2], masks[i*2+1])`.
|
|
38
37
|
*
|
|
39
|
-
* @returns Object with
|
|
38
|
+
* @returns Object with linear block indices and interleaved masks
|
|
40
39
|
*/
|
|
41
40
|
getMixedBlocks(): {
|
|
42
|
-
|
|
41
|
+
blockIdx: Float64Array;
|
|
43
42
|
masks: Uint32Array;
|
|
44
43
|
};
|
|
45
44
|
/**
|
|
46
45
|
* Get all solid blocks as a view into the underlying buffer.
|
|
47
46
|
*
|
|
48
|
-
* @returns Array of
|
|
47
|
+
* @returns Array of linear block indices
|
|
49
48
|
*/
|
|
50
49
|
getSolidBlocks(): Float64Array;
|
|
51
50
|
/**
|
|
@@ -51,6 +51,11 @@ declare class BlockMaskMap {
|
|
|
51
51
|
removeAt(slot: number): void;
|
|
52
52
|
delete(key: number): void;
|
|
53
53
|
clear(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Release all backing storage. The map should not be used again except by
|
|
56
|
+
* replacing it with a new instance.
|
|
57
|
+
*/
|
|
58
|
+
releaseStorage(): void;
|
|
54
59
|
forEach(fn: (key: number, lo: number, hi: number) => void): void;
|
|
55
60
|
clone(): BlockMaskMap;
|
|
56
61
|
private _grow;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { BlockMaskBuffer } from './block-mask-buffer';
|
|
2
1
|
import type { NavSeed, NavSimplifyResult } from './fill-exterior';
|
|
3
2
|
import type { Bounds } from '../data-table';
|
|
4
|
-
|
|
3
|
+
import type { GpuDilation } from '../gpu';
|
|
4
|
+
import { SparseVoxelGrid } from './sparse-voxel-grid';
|
|
5
|
+
declare const carve: (gridA: SparseVoxelGrid, gridBounds: Bounds, voxelResolution: number, capsuleHeight: number, capsuleRadius: number, seed: NavSeed, gpu: GpuDilation) => Promise<NavSimplifyResult>;
|
|
5
6
|
export { carve };
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import { SparseVoxelGrid } from './sparse-voxel-grid';
|
|
2
|
+
import { GpuDilation } from '../gpu';
|
|
2
3
|
/**
|
|
3
|
-
* 3D dilation
|
|
4
|
+
* GPU separable 3D dilation. Chunks the grid into block-aligned inner regions plus
|
|
5
|
+
* a halo on each side, runs three GPU passes per chunk, and OR's the
|
|
6
|
+
* dilated inner region into a fresh destination `SparseVoxelGrid`.
|
|
4
7
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* full SparseVoxelGrid allocation per call. After the function returns
|
|
9
|
-
* with `consumeSrc=true`, `src` references an empty grid and must not
|
|
10
|
-
* be read by the caller.
|
|
8
|
+
* The exact requested half-extents are passed to the dilation shaders. The
|
|
9
|
+
* sparse extraction halo is rounded up to the next 4-voxel block boundary so
|
|
10
|
+
* chunk extract/compact math remains block-aligned without over-dilating.
|
|
11
11
|
*
|
|
12
|
-
* @param
|
|
13
|
-
*
|
|
12
|
+
* @param gpu - Reusable GPU dilation context (compiled shader + buffers).
|
|
13
|
+
* @param src - Input sparse grid (read-only across the call).
|
|
14
14
|
* @param halfExtentXZ - Dilation half-extent in voxels along X and Z.
|
|
15
15
|
* @param halfExtentY - Dilation half-extent in voxels along Y.
|
|
16
|
-
* @
|
|
17
|
-
* a working buffer. Saves ~one full grid's worth of allocation. The
|
|
18
|
-
* caller must not read `src` after the call.
|
|
19
|
-
* @returns Newly allocated dilated grid.
|
|
16
|
+
* @returns Newly allocated dilated sparse grid.
|
|
20
17
|
*/
|
|
21
|
-
declare function
|
|
22
|
-
export {
|
|
18
|
+
declare function gpuDilate3(gpu: GpuDilation, src: SparseVoxelGrid, halfExtentXZ: number, halfExtentY: number): Promise<SparseVoxelGrid>;
|
|
19
|
+
export { gpuDilate3 };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { BlockMaskBuffer } from './block-mask-buffer';
|
|
2
1
|
import type { Bounds } from '../data-table';
|
|
2
|
+
import type { GpuDilation } from '../gpu';
|
|
3
|
+
import { SparseVoxelGrid } from './sparse-voxel-grid';
|
|
3
4
|
type NavSeed = {
|
|
4
5
|
x: number;
|
|
5
6
|
y: number;
|
|
6
7
|
z: number;
|
|
7
8
|
};
|
|
8
9
|
type NavSimplifyResult = {
|
|
9
|
-
|
|
10
|
+
grid: SparseVoxelGrid;
|
|
10
11
|
gridBounds: Bounds;
|
|
11
12
|
};
|
|
12
|
-
declare const fillExterior: (
|
|
13
|
+
declare const fillExterior: (gridOriginal: SparseVoxelGrid, gridBounds: Bounds, voxelResolution: number, dilation: number, seed: NavSeed, gpu: GpuDilation) => Promise<NavSimplifyResult>;
|
|
13
14
|
export { fillExterior };
|
|
14
15
|
export type { NavSeed, NavSimplifyResult };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { BlockMaskBuffer } from './block-mask-buffer';
|
|
2
1
|
import type { NavSimplifyResult } from './fill-exterior';
|
|
3
2
|
import type { Bounds } from '../data-table';
|
|
3
|
+
import type { GpuDilation } from '../gpu';
|
|
4
|
+
import { SparseVoxelGrid } from './sparse-voxel-grid';
|
|
4
5
|
/**
|
|
5
6
|
* Floor-fill via XZ dilate -> per-column upward walk -> XZ dilate -> OR.
|
|
6
7
|
*
|
|
@@ -9,12 +10,12 @@ import type { Bounds } from '../data-table';
|
|
|
9
10
|
* 3D boundary BFS, and the dilations operate only in X and Z.
|
|
10
11
|
*
|
|
11
12
|
* Steps with `r = ceil(dilation / voxelResolution)`:
|
|
12
|
-
* 1. `S_xz =
|
|
13
|
+
* 1. `S_xz = gpuDilate3(S, r, 0)` closes any XZ holes in horizontal
|
|
13
14
|
* surfaces smaller than `2 * r`.
|
|
14
15
|
* 2. For every (lx, lz), walk `y = 0` upward through `S_xz`. Mark each
|
|
15
16
|
* visited empty voxel into `foundEmpty`. Stop on the first solid voxel
|
|
16
17
|
* of `S_xz` or at the grid top.
|
|
17
|
-
* 3. `dilatedFound =
|
|
18
|
+
* 3. `dilatedFound = gpuDilate3(foundEmpty, r, 0)` spreads the found
|
|
18
19
|
* under-surface volume back out in XZ to cover the kernel halo.
|
|
19
20
|
* 4. `output = S | dilatedFound` adds the dilated under-surface region as
|
|
20
21
|
* solid on top of the original solids.
|
|
@@ -27,11 +28,14 @@ import type { Bounds } from '../data-table';
|
|
|
27
28
|
* "fill the under-side of every column up to the first solid", matching the
|
|
28
29
|
* original (pre-dilation) `fillFloor` behavior.
|
|
29
30
|
*
|
|
30
|
-
* @param
|
|
31
|
+
* @param grid - Voxel grid (linear-keyed) — mutated as the under-surface
|
|
32
|
+
* region is OR'd into it. The same grid instance is returned in
|
|
33
|
+
* `NavSimplifyResult.grid`.
|
|
31
34
|
* @param gridBounds - Axis-aligned bounds of the voxel grid.
|
|
32
35
|
* @param voxelResolution - Size of each voxel in world units.
|
|
33
36
|
* @param dilation - XZ dilation radius in world units. 0 disables dilation.
|
|
34
|
-
* @
|
|
37
|
+
* @param gpu - Reusable GPU dilation context. Required when dilation > 0.
|
|
38
|
+
* @returns Modified grid with under-surface regions filled.
|
|
35
39
|
*/
|
|
36
|
-
declare const fillFloor: (
|
|
40
|
+
declare const fillFloor: (grid: SparseVoxelGrid, gridBounds: Bounds, voxelResolution: number, dilation?: number, gpu?: GpuDilation | null) => Promise<NavSimplifyResult>;
|
|
37
41
|
export { fillFloor };
|
|
@@ -20,11 +20,14 @@ import { SparseVoxelGrid } from './sparse-voxel-grid';
|
|
|
20
20
|
* @param nx - Grid dimension X in voxels.
|
|
21
21
|
* @param ny - Grid dimension Y in voxels.
|
|
22
22
|
* @param nz - Grid dimension Z in voxels.
|
|
23
|
+
* @param onBlockFilled - Optional progress callback receiving the running
|
|
24
|
+
* count of whole-block fills. Throttled internally so callers can wire it
|
|
25
|
+
* directly to a progress bar without worrying about per-block overhead.
|
|
23
26
|
* @returns Sparse voxel grid marking all reachable voxels.
|
|
24
27
|
*/
|
|
25
28
|
declare function twoLevelBFS(blocked: SparseVoxelGrid, blockSeeds: number[], voxelSeeds: {
|
|
26
29
|
ix: number;
|
|
27
30
|
iy: number;
|
|
28
31
|
iz: number;
|
|
29
|
-
}[], nx: number, ny: number, nz: number): SparseVoxelGrid;
|
|
32
|
+
}[], nx: number, ny: number, nz: number, onBlockFilled?: (count: number) => void): SparseVoxelGrid;
|
|
30
33
|
export { twoLevelBFS };
|
|
@@ -18,8 +18,9 @@ declare function computeEmptyGrid(visited: SparseVoxelGrid, blocked: SparseVoxel
|
|
|
18
18
|
* @param consumeA - If true, `a` is mutated in place and returned. The
|
|
19
19
|
* caller must not subsequently read `a` as an independent value
|
|
20
20
|
* (the returned grid IS `a`).
|
|
21
|
+
* @param onProgress - Optional progress callback over `b.types` words.
|
|
21
22
|
* @returns Grid containing the union of both inputs. Equal to `a` when
|
|
22
23
|
* `consumeA=true`, otherwise a freshly cloned grid.
|
|
23
24
|
*/
|
|
24
|
-
declare function sparseOrGrids(a: SparseVoxelGrid, b: SparseVoxelGrid, consumeA?: boolean): SparseVoxelGrid;
|
|
25
|
+
declare function sparseOrGrids(a: SparseVoxelGrid, b: SparseVoxelGrid, consumeA?: boolean, onProgress?: (done: number, total: number) => void): SparseVoxelGrid;
|
|
25
26
|
export { computeEmptyGrid, sparseOrGrids };
|
|
@@ -8,13 +8,6 @@
|
|
|
8
8
|
* @returns Morton code with interleaved bits: ...z2y2x2 z1y1x1 z0y0x0
|
|
9
9
|
*/
|
|
10
10
|
declare function xyzToMorton(x: number, y: number, z: number): number;
|
|
11
|
-
/**
|
|
12
|
-
* Decode Morton code to block coordinates.
|
|
13
|
-
*
|
|
14
|
-
* @param m - Morton code
|
|
15
|
-
* @returns Tuple of [x, y, z] block coordinates
|
|
16
|
-
*/
|
|
17
|
-
declare function mortonToXYZ(m: number): [number, number, number];
|
|
18
11
|
/**
|
|
19
12
|
* Count the number of set bits in a 32-bit integer.
|
|
20
13
|
*
|
|
@@ -38,13 +31,4 @@ declare function isSolid(lo: number, hi: number): boolean;
|
|
|
38
31
|
* @returns True if all 64 voxels are empty
|
|
39
32
|
*/
|
|
40
33
|
declare function isEmpty(lo: number, hi: number): boolean;
|
|
41
|
-
|
|
42
|
-
* Get the offset to a child node given a parent's child mask and octant.
|
|
43
|
-
* Uses popcount to count how many children come before this octant.
|
|
44
|
-
*
|
|
45
|
-
* @param mask - 8-bit child mask from parent node
|
|
46
|
-
* @param octant - Octant index (0-7)
|
|
47
|
-
* @returns Offset from base child pointer
|
|
48
|
-
*/
|
|
49
|
-
declare function getChildOffset(mask: number, octant: number): number;
|
|
50
|
-
export { xyzToMorton, mortonToXYZ, popcount, isSolid, isEmpty, getChildOffset };
|
|
34
|
+
export { xyzToMorton, popcount, isSolid, isEmpty };
|
|
@@ -68,16 +68,62 @@ declare class SparseVoxelGrid {
|
|
|
68
68
|
setVoxel(ix: number, iy: number, iz: number): void;
|
|
69
69
|
orBlock(blockIdx: number, lo: number, hi: number): void;
|
|
70
70
|
clear(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Release the large backing arrays once a grid has been consumed.
|
|
73
|
+
*/
|
|
74
|
+
releaseStorage(): void;
|
|
71
75
|
clone(): SparseVoxelGrid;
|
|
72
|
-
static fromBuffer(acc: BlockMaskBuffer, nx: number, ny: number, nz: number): SparseVoxelGrid;
|
|
73
|
-
toBuffer(cropMinBx: number, cropMinBy: number, cropMinBz: number, cropMaxBx: number, cropMaxBy: number, cropMaxBz: number,
|
|
74
|
-
|
|
76
|
+
static fromBuffer(acc: BlockMaskBuffer, nx: number, ny: number, nz: number, onProgress?: (done: number, total: number) => void): SparseVoxelGrid;
|
|
77
|
+
toBuffer(cropMinBx: number, cropMinBy: number, cropMinBz: number, cropMaxBx: number, cropMaxBy: number, cropMaxBz: number, onProgress?: (done: number, total: number) => void): BlockMaskBuffer;
|
|
78
|
+
/**
|
|
79
|
+
* Crop this grid to a block-aligned sub-region. Returns a fresh grid of
|
|
80
|
+
* size `(cropMaxBx-cropMinBx)*4 x (cropMaxBy-cropMinBy)*4 x (cropMaxBz-cropMinBz)*4`
|
|
81
|
+
* containing the same data with origin shifted to (cropMinBx, cropMinBy, cropMinBz).
|
|
82
|
+
*
|
|
83
|
+
* Iterates only non-empty blocks of the source via word-level skipping.
|
|
84
|
+
*
|
|
85
|
+
* @param cropMinBx - Min block X (inclusive).
|
|
86
|
+
* @param cropMinBy - Min block Y (inclusive).
|
|
87
|
+
* @param cropMinBz - Min block Z (inclusive).
|
|
88
|
+
* @param cropMaxBx - Max block X (exclusive).
|
|
89
|
+
* @param cropMaxBy - Max block Y (exclusive).
|
|
90
|
+
* @param cropMaxBz - Max block Z (exclusive).
|
|
91
|
+
* @param onProgress - Optional progress callback over source `types` words.
|
|
92
|
+
* @returns Newly allocated cropped grid.
|
|
93
|
+
*/
|
|
94
|
+
cropTo(cropMinBx: number, cropMinBy: number, cropMinBz: number, cropMaxBx: number, cropMaxBy: number, cropMaxBz: number, onProgress?: (done: number, total: number) => void): SparseVoxelGrid;
|
|
95
|
+
/**
|
|
96
|
+
* Crop this grid to a sub-region with inverted occupancy: source EMPTY
|
|
97
|
+
* becomes destination SOLID, source SOLID becomes destination EMPTY,
|
|
98
|
+
* source MIXED becomes destination MIXED with bitwise-inverted mask.
|
|
99
|
+
*
|
|
100
|
+
* The destination grid has dimensions matching the crop window. Used by
|
|
101
|
+
* carve to flip the navigable region (1=navigable) into the runtime's
|
|
102
|
+
* occupancy convention (1=blocked).
|
|
103
|
+
*
|
|
104
|
+
* Note: cropping the EMPTY-becomes-SOLID region is exact within the crop
|
|
105
|
+
* window only. Since the source grid's EMPTY blocks become SOLID in the
|
|
106
|
+
* output, the output's `types` for empty blocks must be set rather than
|
|
107
|
+
* left at their default. We therefore initialize the entire output to
|
|
108
|
+
* SOLID (word fill) and then patch any non-EMPTY source blocks.
|
|
109
|
+
*
|
|
110
|
+
* @param cropMinBx - Min block X (inclusive).
|
|
111
|
+
* @param cropMinBy - Min block Y (inclusive).
|
|
112
|
+
* @param cropMinBz - Min block Z (inclusive).
|
|
113
|
+
* @param cropMaxBx - Max block X (exclusive).
|
|
114
|
+
* @param cropMaxBy - Max block Y (exclusive).
|
|
115
|
+
* @param cropMaxBz - Max block Z (exclusive).
|
|
116
|
+
* @param onProgress - Optional progress callback over source `types` words.
|
|
117
|
+
* @returns Newly allocated cropped + inverted grid.
|
|
118
|
+
*/
|
|
119
|
+
cropToInverted(cropMinBx: number, cropMinBy: number, cropMinBz: number, cropMaxBx: number, cropMaxBy: number, cropMaxBz: number, onProgress?: (done: number, total: number) => void): SparseVoxelGrid;
|
|
75
120
|
/**
|
|
76
121
|
* Get the bounding box of occupied blocks.
|
|
77
122
|
*
|
|
123
|
+
* @param onProgress - Optional progress callback over `types` words.
|
|
78
124
|
* @returns Block coordinate bounds, or null if no blocks are occupied.
|
|
79
125
|
*/
|
|
80
|
-
getOccupiedBlockBounds(): {
|
|
126
|
+
getOccupiedBlockBounds(onProgress?: (done: number, total: number) => void): {
|
|
81
127
|
minBx: number;
|
|
82
128
|
minBy: number;
|
|
83
129
|
minBz: number;
|
|
@@ -91,9 +137,10 @@ declare class SparseVoxelGrid {
|
|
|
91
137
|
* voxel). Useful when the runtime treats out-of-grid as solid, so fully
|
|
92
138
|
* solid blocks beyond the navigable region can be cropped away.
|
|
93
139
|
*
|
|
140
|
+
* @param onProgress - Optional progress callback over `types` words.
|
|
94
141
|
* @returns Block coordinate bounds, or null if every block is solid.
|
|
95
142
|
*/
|
|
96
|
-
getNavigableBlockBounds(): {
|
|
143
|
+
getNavigableBlockBounds(onProgress?: (done: number, total: number) => void): {
|
|
97
144
|
minBx: number;
|
|
98
145
|
minBy: number;
|
|
99
146
|
minBz: number;
|