@playcanvas/splat-transform 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.mjs +352 -5
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +5478 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +352 -5
- package/dist/index.mjs.map +1 -1
- package/dist/lib/data-table/combine.d.ts +16 -0
- package/dist/lib/data-table/data-table.d.ts +48 -0
- package/dist/lib/data-table/summary.d.ts +33 -0
- package/dist/lib/data-table/transform.d.ts +19 -0
- package/dist/lib/index.d.cts +34 -0
- package/dist/lib/index.d.ts +4 -4
- package/dist/lib/io/read/index.d.ts +1 -1
- package/dist/lib/io/read/zip-file-system.d.ts +1 -1
- package/dist/lib/io/write/memory-file-system.d.ts +15 -0
- package/dist/lib/io/write/zip-file-system.d.ts +20 -0
- package/dist/lib/process.d.ts +96 -1
- package/dist/lib/read.d.ts +57 -1
- package/dist/lib/readers/read-ksplat.d.ts +11 -0
- package/dist/lib/readers/read-lcc.d.ts +13 -0
- package/dist/lib/readers/read-mjs.d.ts +12 -0
- package/dist/lib/readers/read-ply.d.ts +10 -0
- package/dist/lib/readers/read-sog.d.ts +1 -0
- package/dist/lib/readers/read-splat.d.ts +10 -0
- package/dist/lib/readers/read-spz.d.ts +12 -0
- package/dist/lib/types.d.ts +1 -0
- package/dist/lib/write.d.ts +57 -1
- package/dist/lib/writers/write-compressed-ply.d.ts +11 -0
- package/dist/lib/writers/write-csv.d.ts +10 -0
- package/dist/lib/writers/write-html.d.ts +10 -0
- package/dist/lib/writers/write-lod.d.ts +11 -0
- package/dist/lib/writers/write-ply.d.ts +10 -0
- package/dist/lib/writers/write-sog.d.ts +16 -1
- package/package.json +13 -4
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { Vec3, Quat, Mat4, Mat3, BindGroupFormat, BindUniformBufferFormat, BindStorageBufferFormat, SHADERSTAGE_COMPUTE, Shader, UniformBufferFormat, SHADERLANGUAGE_WGSL, UniformFormat, UNIFORMTYPE_UINT, StorageBuffer, BUFFERUSAGE_COPY_DST, BUFFERUSAGE_COPY_SRC, Compute, FloatPacking, BoundingBox } from 'playcanvas';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* A named column of typed array data within a DataTable.
|
|
5
|
+
*
|
|
6
|
+
* Columns store homogeneous numeric data efficiently using JavaScript typed arrays.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const positions = new Column('x', new Float32Array([1.0, 2.0, 3.0]));
|
|
11
|
+
* console.log(positions.name); // 'x'
|
|
12
|
+
* console.log(positions.dataType); // 'float32'
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
3
15
|
class Column {
|
|
4
16
|
name;
|
|
5
17
|
data;
|
|
@@ -24,6 +36,32 @@ class Column {
|
|
|
24
36
|
return new Column(this.name, this.data.slice());
|
|
25
37
|
}
|
|
26
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* A table of columnar data representing Gaussian splat properties.
|
|
41
|
+
*
|
|
42
|
+
* DataTable is the core data structure for splat data. Each column represents
|
|
43
|
+
* a property (e.g., position, rotation, color) as a typed array, and all columns
|
|
44
|
+
* must have the same number of rows.
|
|
45
|
+
*
|
|
46
|
+
* Standard columns include:
|
|
47
|
+
* - Position: `x`, `y`, `z`
|
|
48
|
+
* - Rotation: `rot_0`, `rot_1`, `rot_2`, `rot_3` (quaternion)
|
|
49
|
+
* - Scale: `scale_0`, `scale_1`, `scale_2` (log scale)
|
|
50
|
+
* - Color: `f_dc_0`, `f_dc_1`, `f_dc_2` (spherical harmonics DC)
|
|
51
|
+
* - Opacity: `opacity` (logit)
|
|
52
|
+
* - Spherical Harmonics: `f_rest_0` through `f_rest_44`
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* const table = new DataTable([
|
|
57
|
+
* new Column('x', new Float32Array([0, 1, 2])),
|
|
58
|
+
* new Column('y', new Float32Array([0, 0, 0])),
|
|
59
|
+
* new Column('z', new Float32Array([0, 0, 0]))
|
|
60
|
+
* ]);
|
|
61
|
+
* console.log(table.numRows); // 3
|
|
62
|
+
* console.log(table.numColumns); // 3
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
27
65
|
class DataTable {
|
|
28
66
|
columns;
|
|
29
67
|
constructor(columns) {
|
|
@@ -115,7 +153,22 @@ class DataTable {
|
|
|
115
153
|
}
|
|
116
154
|
}
|
|
117
155
|
|
|
118
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Combines multiple DataTables into a single DataTable.
|
|
158
|
+
*
|
|
159
|
+
* Merges rows from all input tables. Columns are matched by name and type;
|
|
160
|
+
* columns that don't exist in all tables will have undefined values for
|
|
161
|
+
* rows from tables lacking that column.
|
|
162
|
+
*
|
|
163
|
+
* @param dataTables - Array of DataTables to combine.
|
|
164
|
+
* @returns A new DataTable containing all rows from all input tables.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* const combined = combine([tableA, tableB, tableC]);
|
|
169
|
+
* console.log(combined.numRows); // tableA.numRows + tableB.numRows + tableC.numRows
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
119
172
|
const combine = (dataTables) => {
|
|
120
173
|
if (dataTables.length === 1) {
|
|
121
174
|
// nothing to combine
|
|
@@ -341,7 +394,25 @@ class RotateSH {
|
|
|
341
394
|
const shNames$3 = new Array(45).fill('').map((_, i) => `f_rest_${i}`);
|
|
342
395
|
const v = new Vec3();
|
|
343
396
|
const q$1 = new Quat();
|
|
344
|
-
|
|
397
|
+
/**
|
|
398
|
+
* Applies a spatial transformation to splat data in-place.
|
|
399
|
+
*
|
|
400
|
+
* Transforms position, rotation, scale, and spherical harmonics data.
|
|
401
|
+
* The transformation is applied as: scale first, then rotation, then translation.
|
|
402
|
+
*
|
|
403
|
+
* @param dataTable - The DataTable to transform (modified in-place).
|
|
404
|
+
* @param t - Translation vector.
|
|
405
|
+
* @param r - Rotation quaternion.
|
|
406
|
+
* @param s - Uniform scale factor.
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```ts
|
|
410
|
+
* import { Vec3, Quat } from 'playcanvas';
|
|
411
|
+
*
|
|
412
|
+
* // Scale by 2x, rotate 90° around Y, translate up
|
|
413
|
+
* transform(dataTable, new Vec3(0, 5, 0), new Quat().setFromEulerAngles(0, 90, 0), 2.0);
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
345
416
|
const transform = (dataTable, t, r, s) => {
|
|
346
417
|
const mat = new Mat4().setTRS(t, r, new Vec3(s, s, s));
|
|
347
418
|
const mat3 = new Mat3().setFromQuat(r);
|
|
@@ -460,6 +531,23 @@ const computeColumnStats = (data) => {
|
|
|
460
531
|
infCount
|
|
461
532
|
};
|
|
462
533
|
};
|
|
534
|
+
/**
|
|
535
|
+
* Computes statistical summary for all columns in a DataTable.
|
|
536
|
+
*
|
|
537
|
+
* For each column, calculates min, max, median, mean, standard deviation,
|
|
538
|
+
* and counts of NaN/Infinity values. Useful for data validation and analysis.
|
|
539
|
+
*
|
|
540
|
+
* @param dataTable - The DataTable to analyze.
|
|
541
|
+
* @returns Summary data with per-column statistics.
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```ts
|
|
545
|
+
* const summary = computeSummary(dataTable);
|
|
546
|
+
* console.log(summary.rowCount);
|
|
547
|
+
* console.log(summary.columns['x'].mean);
|
|
548
|
+
* console.log(summary.columns['opacity'].nanCount);
|
|
549
|
+
* ```
|
|
550
|
+
*/
|
|
463
551
|
const computeSummary = (dataTable) => {
|
|
464
552
|
const columns = {};
|
|
465
553
|
for (const column of dataTable.columns) {
|
|
@@ -918,6 +1006,17 @@ const COMPRESSION_MODES = [
|
|
|
918
1006
|
}
|
|
919
1007
|
];
|
|
920
1008
|
const HARMONICS_COMPONENT_COUNT$1 = [0, 9, 24, 45];
|
|
1009
|
+
/**
|
|
1010
|
+
* Reads a .ksplat file containing compressed Gaussian splat data.
|
|
1011
|
+
*
|
|
1012
|
+
* The .ksplat format (Kevin Kwok's format) uses spatial bucketing and
|
|
1013
|
+
* quantization to achieve high compression ratios while preserving quality.
|
|
1014
|
+
* Supports multiple compression modes and spherical harmonics bands.
|
|
1015
|
+
*
|
|
1016
|
+
* @param source - The read source providing access to the .ksplat file data.
|
|
1017
|
+
* @returns Promise resolving to a DataTable containing the splat data.
|
|
1018
|
+
* @ignore
|
|
1019
|
+
*/
|
|
921
1020
|
const readKsplat = async (source) => {
|
|
922
1021
|
// Load complete file
|
|
923
1022
|
const fileBuffer = await source.read().readAll();
|
|
@@ -1875,6 +1974,19 @@ const deserializeEnvironment = (raw, compressInfo, hasSH) => {
|
|
|
1875
1974
|
}
|
|
1876
1975
|
return new DataTable(columns);
|
|
1877
1976
|
};
|
|
1977
|
+
/**
|
|
1978
|
+
* Reads an XGrids LCC format containing multi-LOD Gaussian splat data.
|
|
1979
|
+
*
|
|
1980
|
+
* The LCC format uses a quadtree spatial structure with multiple LOD levels.
|
|
1981
|
+
* Each LOD level is stored separately in data.bin with optional spherical
|
|
1982
|
+
* harmonics in shcoef.bin. Environment splats are stored in environment.bin.
|
|
1983
|
+
*
|
|
1984
|
+
* @param fileSystem - File system for reading the LCC files.
|
|
1985
|
+
* @param filename - Path to the meta.lcc file.
|
|
1986
|
+
* @param options - Options including LOD selection via `lodSelect`.
|
|
1987
|
+
* @returns Promise resolving to an array of DataTables, one per LOD level plus environment.
|
|
1988
|
+
* @ignore
|
|
1989
|
+
*/
|
|
1878
1990
|
const readLcc = async (fileSystem, filename, options) => {
|
|
1879
1991
|
const lccData = await readFile$1(fileSystem, filename);
|
|
1880
1992
|
const lccText = new TextDecoder().decode(lccData);
|
|
@@ -1949,6 +2061,18 @@ const readLcc = async (fileSystem, filename, options) => {
|
|
|
1949
2061
|
return result;
|
|
1950
2062
|
};
|
|
1951
2063
|
|
|
2064
|
+
/**
|
|
2065
|
+
* Reads splat data from a JavaScript module generator.
|
|
2066
|
+
*
|
|
2067
|
+
* The module must export a `Generator` class with a static `create(params)` method
|
|
2068
|
+
* that returns an object with `count`, `columnNames`, and `getRow(index, row)` properties.
|
|
2069
|
+
* This allows programmatic generation of splat data.
|
|
2070
|
+
*
|
|
2071
|
+
* @param moduleUrl - URL or path to the JavaScript module.
|
|
2072
|
+
* @param params - Parameters to pass to the generator's create method.
|
|
2073
|
+
* @returns Promise resolving to a DataTable containing the generated splat data.
|
|
2074
|
+
* @ignore
|
|
2075
|
+
*/
|
|
1952
2076
|
const readMjs = async (moduleUrl, params) => {
|
|
1953
2077
|
const module = await import(moduleUrl);
|
|
1954
2078
|
if (!module) {
|
|
@@ -2269,6 +2393,16 @@ const readExact = async (stream, buffer, offset, length) => {
|
|
|
2269
2393
|
}
|
|
2270
2394
|
return totalRead;
|
|
2271
2395
|
};
|
|
2396
|
+
/**
|
|
2397
|
+
* Reads a PLY file containing Gaussian splat data.
|
|
2398
|
+
*
|
|
2399
|
+
* Supports both standard PLY files and compressed PLY format. The PLY format is
|
|
2400
|
+
* the standard output from 3D Gaussian Splatting training pipelines.
|
|
2401
|
+
*
|
|
2402
|
+
* @param source - The read source providing access to the PLY file data.
|
|
2403
|
+
* @returns Promise resolving to a DataTable containing the splat data.
|
|
2404
|
+
* @ignore
|
|
2405
|
+
*/
|
|
2272
2406
|
const readPly = async (source) => {
|
|
2273
2407
|
const stream = source.read();
|
|
2274
2408
|
// we don't support ply text header larger than 128k
|
|
@@ -2483,6 +2617,7 @@ const sigmoidInv = (y) => {
|
|
|
2483
2617
|
* @param fileSystem - The file system to read from
|
|
2484
2618
|
* @param filename - Path to meta.json (relative paths resolved from its directory)
|
|
2485
2619
|
* @returns DataTable with Gaussian splat data
|
|
2620
|
+
* @ignore
|
|
2486
2621
|
*/
|
|
2487
2622
|
const readSog = async (fileSystem, filename) => {
|
|
2488
2623
|
const decoder = await WebPCodec.create();
|
|
@@ -2630,6 +2765,16 @@ const readSog = async (fileSystem, filename) => {
|
|
|
2630
2765
|
return new DataTable(columns);
|
|
2631
2766
|
};
|
|
2632
2767
|
|
|
2768
|
+
/**
|
|
2769
|
+
* Reads an Antimatter15 .splat file containing Gaussian splat data.
|
|
2770
|
+
*
|
|
2771
|
+
* The .splat format stores each splat as 32 bytes with position, scale, color,
|
|
2772
|
+
* opacity, and rotation data in a compact binary format.
|
|
2773
|
+
*
|
|
2774
|
+
* @param source - The read source providing access to the .splat file data.
|
|
2775
|
+
* @returns Promise resolving to a DataTable containing the splat data.
|
|
2776
|
+
* @ignore
|
|
2777
|
+
*/
|
|
2633
2778
|
const readSplat = async (source) => {
|
|
2634
2779
|
// Load complete file
|
|
2635
2780
|
const fileBuffer = await source.read().readAll();
|
|
@@ -2753,6 +2898,18 @@ function getFixed24(positionsView, elementIndex, memberIndex) {
|
|
|
2753
2898
|
return fixed32;
|
|
2754
2899
|
}
|
|
2755
2900
|
const HARMONICS_COMPONENT_COUNT = [0, 9, 24, 45];
|
|
2901
|
+
/**
|
|
2902
|
+
* Reads a .spz file containing Niantic Labs compressed Gaussian splat data.
|
|
2903
|
+
*
|
|
2904
|
+
* The .spz format uses GZIP compression and fixed-point encoding to achieve
|
|
2905
|
+
* compact file sizes. Supports version 2 and 3 of the format.
|
|
2906
|
+
*
|
|
2907
|
+
* @see https://github.com/nianticlabs/spz
|
|
2908
|
+
*
|
|
2909
|
+
* @param source - The read source providing access to the .spz file data.
|
|
2910
|
+
* @returns Promise resolving to a DataTable containing the splat data.
|
|
2911
|
+
* @ignore
|
|
2912
|
+
*/
|
|
2756
2913
|
const readSpz = async (source) => {
|
|
2757
2914
|
// Load complete file
|
|
2758
2915
|
let fileBuffer = await source.read().readAll();
|
|
@@ -2989,6 +3146,19 @@ const logger = {
|
|
|
2989
3146
|
}
|
|
2990
3147
|
};
|
|
2991
3148
|
|
|
3149
|
+
/**
|
|
3150
|
+
* Determines the input format based on file extension.
|
|
3151
|
+
*
|
|
3152
|
+
* @param filename - The filename to analyze.
|
|
3153
|
+
* @returns The detected input format.
|
|
3154
|
+
* @throws Error if the file extension is not recognized.
|
|
3155
|
+
*
|
|
3156
|
+
* @example
|
|
3157
|
+
* ```ts
|
|
3158
|
+
* const format = getInputFormat('scene.ply'); // returns 'ply'
|
|
3159
|
+
* const format2 = getInputFormat('scene.splat'); // returns 'splat'
|
|
3160
|
+
* ```
|
|
3161
|
+
*/
|
|
2992
3162
|
const getInputFormat = (filename) => {
|
|
2993
3163
|
const lowerFilename = filename.toLowerCase();
|
|
2994
3164
|
if (lowerFilename.endsWith('.mjs')) {
|
|
@@ -3014,6 +3184,30 @@ const getInputFormat = (filename) => {
|
|
|
3014
3184
|
}
|
|
3015
3185
|
throw new Error(`Unsupported input file type: ${filename}`);
|
|
3016
3186
|
};
|
|
3187
|
+
/**
|
|
3188
|
+
* Reads a Gaussian splat file and returns its data as one or more DataTables.
|
|
3189
|
+
*
|
|
3190
|
+
* Supports multiple input formats including PLY, splat, ksplat, spz, SOG, and LCC.
|
|
3191
|
+
* Some formats (like LCC) may return multiple DataTables for different LOD levels.
|
|
3192
|
+
*
|
|
3193
|
+
* @param readFileOptions - Options specifying the file to read and how to read it.
|
|
3194
|
+
* @returns Promise resolving to an array of DataTables containing the splat data.
|
|
3195
|
+
*
|
|
3196
|
+
* @example
|
|
3197
|
+
* ```ts
|
|
3198
|
+
* import { readFile, getInputFormat, UrlReadFileSystem } from '@playcanvas/splat-transform';
|
|
3199
|
+
*
|
|
3200
|
+
* const filename = 'scene.ply';
|
|
3201
|
+
* const fileSystem = new UrlReadFileSystem('https://example.com/');
|
|
3202
|
+
* const tables = await readFile({
|
|
3203
|
+
* filename,
|
|
3204
|
+
* inputFormat: getInputFormat(filename),
|
|
3205
|
+
* options: {},
|
|
3206
|
+
* params: [],
|
|
3207
|
+
* fileSystem
|
|
3208
|
+
* });
|
|
3209
|
+
* ```
|
|
3210
|
+
*/
|
|
3017
3211
|
const readFile = async (readFileOptions) => {
|
|
3018
3212
|
const { filename, inputFormat, options, params, fileSystem } = readFileOptions;
|
|
3019
3213
|
let result;
|
|
@@ -3208,7 +3402,7 @@ class CompressedChunk {
|
|
|
3208
3402
|
}
|
|
3209
3403
|
}
|
|
3210
3404
|
|
|
3211
|
-
var version = "1.
|
|
3405
|
+
var version = "1.1.0";
|
|
3212
3406
|
|
|
3213
3407
|
// sort the provided indices into morton order
|
|
3214
3408
|
const sortMortonOrder = (dataTable, indices) => {
|
|
@@ -3327,6 +3521,17 @@ const vertexProps = [
|
|
|
3327
3521
|
const shNames$2 = new Array(45).fill('').map((_, i) => `f_rest_${i}`);
|
|
3328
3522
|
// Size of a chunk in the compressed PLY format (number of splats per chunk)
|
|
3329
3523
|
const CHUNK_SIZE = 256;
|
|
3524
|
+
/**
|
|
3525
|
+
* Writes Gaussian splat data to compressed PLY format.
|
|
3526
|
+
*
|
|
3527
|
+
* Uses quantization and chunking to reduce file size while maintaining
|
|
3528
|
+
* compatibility with PLY-based viewers. Data is sorted using Morton order
|
|
3529
|
+
* for better compression and streaming performance.
|
|
3530
|
+
*
|
|
3531
|
+
* @param options - Options including filename and data table to write.
|
|
3532
|
+
* @param fs - File system for writing the output file.
|
|
3533
|
+
* @ignore
|
|
3534
|
+
*/
|
|
3330
3535
|
const writeCompressedPly = async (options, fs) => {
|
|
3331
3536
|
const { filename, dataTable } = options;
|
|
3332
3537
|
const shBands = { '9': 1, '24': 2, '-1': 3 }[shNames$2.findIndex(v => !dataTable.hasColumn(v))] ?? 0;
|
|
@@ -3400,6 +3605,16 @@ const writeCompressedPly = async (options, fs) => {
|
|
|
3400
3605
|
await writer.close();
|
|
3401
3606
|
};
|
|
3402
3607
|
|
|
3608
|
+
/**
|
|
3609
|
+
* Writes Gaussian splat data to a CSV text file.
|
|
3610
|
+
*
|
|
3611
|
+
* Useful for debugging, analysis, or importing into spreadsheet applications.
|
|
3612
|
+
* Each row represents one splat with all column values separated by commas.
|
|
3613
|
+
*
|
|
3614
|
+
* @param options - Options including filename and data table to write.
|
|
3615
|
+
* @param fs - File system for writing the output file.
|
|
3616
|
+
* @ignore
|
|
3617
|
+
*/
|
|
3403
3618
|
const writeCsv = async (options, fs) => {
|
|
3404
3619
|
const { filename, dataTable } = options;
|
|
3405
3620
|
const len = dataTable.numRows;
|
|
@@ -3471,6 +3686,21 @@ class MemoryWriter {
|
|
|
3471
3686
|
};
|
|
3472
3687
|
}
|
|
3473
3688
|
}
|
|
3689
|
+
/**
|
|
3690
|
+
* A file system that writes files to in-memory buffers.
|
|
3691
|
+
*
|
|
3692
|
+
* Useful for generating output without writing to disk, such as when
|
|
3693
|
+
* creating data for download or further processing.
|
|
3694
|
+
*
|
|
3695
|
+
* @example
|
|
3696
|
+
* ```ts
|
|
3697
|
+
* const fs = new MemoryFileSystem();
|
|
3698
|
+
* await writeFile({ filename: 'output.ply', ... }, fs);
|
|
3699
|
+
*
|
|
3700
|
+
* // Get the generated data
|
|
3701
|
+
* const data = fs.results.get('output.ply');
|
|
3702
|
+
* ```
|
|
3703
|
+
*/
|
|
3474
3704
|
class MemoryFileSystem {
|
|
3475
3705
|
results = new Map();
|
|
3476
3706
|
createWriter(filename) {
|
|
@@ -3537,7 +3767,26 @@ class ZipEntryWriter {
|
|
|
3537
3767
|
};
|
|
3538
3768
|
}
|
|
3539
3769
|
}
|
|
3540
|
-
|
|
3770
|
+
/**
|
|
3771
|
+
* A file system that writes files into a ZIP archive.
|
|
3772
|
+
*
|
|
3773
|
+
* Creates a ZIP file containing all written files. Used internally
|
|
3774
|
+
* for bundled output formats like .sog files.
|
|
3775
|
+
*
|
|
3776
|
+
* @example
|
|
3777
|
+
* ```ts
|
|
3778
|
+
* const outputWriter = await fs.createWriter('bundle.zip');
|
|
3779
|
+
* const zipFs = new ZipFileSystem(outputWriter);
|
|
3780
|
+
*
|
|
3781
|
+
* // Write files into the zip
|
|
3782
|
+
* const writer = await zipFs.createWriter('data.json');
|
|
3783
|
+
* await writer.write(jsonData);
|
|
3784
|
+
* await writer.close();
|
|
3785
|
+
*
|
|
3786
|
+
* // Finalize the zip
|
|
3787
|
+
* await zipFs.close();
|
|
3788
|
+
* ```
|
|
3789
|
+
*/
|
|
3541
3790
|
class ZipFileSystem {
|
|
3542
3791
|
close;
|
|
3543
3792
|
createWriter;
|
|
@@ -4117,6 +4366,17 @@ const cluster1d = async (dataTable, iterations, device) => {
|
|
|
4117
4366
|
};
|
|
4118
4367
|
};
|
|
4119
4368
|
let webPCodec;
|
|
4369
|
+
/**
|
|
4370
|
+
* Writes Gaussian splat data to the PlayCanvas SOG format.
|
|
4371
|
+
*
|
|
4372
|
+
* SOG (Splat Optimized Graphics) uses WebP lossless compression and k-means
|
|
4373
|
+
* clustering to achieve high compression ratios. Data is stored in textures
|
|
4374
|
+
* for efficient GPU loading.
|
|
4375
|
+
*
|
|
4376
|
+
* @param options - Options including filename, data, and compression settings.
|
|
4377
|
+
* @param fs - File system for writing output files.
|
|
4378
|
+
* @ignore
|
|
4379
|
+
*/
|
|
4120
4380
|
const writeSog = async (options, fs) => {
|
|
4121
4381
|
const { filename: outputFilename, bundle, dataTable, iterations, createDevice } = options;
|
|
4122
4382
|
// initialize output stream - use ZipFileSystem for bundled output
|
|
@@ -4355,6 +4615,16 @@ const toBase64 = (bytes) => {
|
|
|
4355
4615
|
return btoa(binary);
|
|
4356
4616
|
};
|
|
4357
4617
|
|
|
4618
|
+
/**
|
|
4619
|
+
* Writes Gaussian splat data as a self-contained HTML viewer.
|
|
4620
|
+
*
|
|
4621
|
+
* Creates an interactive 3D viewer that can be opened directly in a browser.
|
|
4622
|
+
* Uses the PlayCanvas SuperSplat viewer for rendering.
|
|
4623
|
+
*
|
|
4624
|
+
* @param options - Options including filename, data, and viewer settings.
|
|
4625
|
+
* @param fs - File system for writing output files.
|
|
4626
|
+
* @ignore
|
|
4627
|
+
*/
|
|
4358
4628
|
const writeHtml = async (options, fs) => {
|
|
4359
4629
|
const { filename, dataTable, viewerSettingsJson, bundle, iterations, createDevice } = options;
|
|
4360
4630
|
const pad = (text, spaces) => {
|
|
@@ -4650,6 +4920,17 @@ const binIndices = (parent, lod) => {
|
|
|
4650
4920
|
recurse(parent);
|
|
4651
4921
|
return result;
|
|
4652
4922
|
};
|
|
4923
|
+
/**
|
|
4924
|
+
* Writes Gaussian splat data to multi-LOD format with spatial chunking.
|
|
4925
|
+
*
|
|
4926
|
+
* Creates a hierarchical structure with multiple LOD levels, each stored
|
|
4927
|
+
* in separate SOG files. Includes spatial indexing via a binary tree for
|
|
4928
|
+
* efficient streaming and view-dependent loading.
|
|
4929
|
+
*
|
|
4930
|
+
* @param options - Options including filename, data, and chunking parameters.
|
|
4931
|
+
* @param fs - File system for writing output files.
|
|
4932
|
+
* @ignore
|
|
4933
|
+
*/
|
|
4653
4934
|
const writeLod = async (options, fs) => {
|
|
4654
4935
|
const { filename, dataTable, envDataTable, iterations, createDevice, chunkCount, chunkExtent } = options;
|
|
4655
4936
|
const outputDir = dirname(filename);
|
|
@@ -4801,6 +5082,16 @@ const columnTypeToPlyType = (type) => {
|
|
|
4801
5082
|
case 'uint32': return 'uint';
|
|
4802
5083
|
}
|
|
4803
5084
|
};
|
|
5085
|
+
/**
|
|
5086
|
+
* Writes Gaussian splat data to a binary PLY file.
|
|
5087
|
+
*
|
|
5088
|
+
* The PLY format is the standard output from 3D Gaussian Splatting training
|
|
5089
|
+
* and is widely supported by visualization tools.
|
|
5090
|
+
*
|
|
5091
|
+
* @param options - Options including filename and PLY data to write.
|
|
5092
|
+
* @param fs - File system for writing the output file.
|
|
5093
|
+
* @ignore
|
|
5094
|
+
*/
|
|
4804
5095
|
const writePly = async (options, fs) => {
|
|
4805
5096
|
const { filename, plyData } = options;
|
|
4806
5097
|
const header = [
|
|
@@ -4849,6 +5140,20 @@ const writePly = async (options, fs) => {
|
|
|
4849
5140
|
await writer.close();
|
|
4850
5141
|
};
|
|
4851
5142
|
|
|
5143
|
+
/**
|
|
5144
|
+
* Determines the output format based on file extension and options.
|
|
5145
|
+
*
|
|
5146
|
+
* @param filename - The filename to analyze.
|
|
5147
|
+
* @param options - Options that may affect format selection.
|
|
5148
|
+
* @returns The detected output format.
|
|
5149
|
+
* @throws Error if the file extension is not recognized.
|
|
5150
|
+
*
|
|
5151
|
+
* @example
|
|
5152
|
+
* ```ts
|
|
5153
|
+
* const format = getOutputFormat('scene.ply', {}); // returns 'ply'
|
|
5154
|
+
* const format2 = getOutputFormat('scene.sog', {}); // returns 'sog-bundle'
|
|
5155
|
+
* ```
|
|
5156
|
+
*/
|
|
4852
5157
|
const getOutputFormat = (filename, options) => {
|
|
4853
5158
|
const lowerFilename = filename.toLowerCase();
|
|
4854
5159
|
if (lowerFilename.endsWith('.csv')) {
|
|
@@ -4874,6 +5179,27 @@ const getOutputFormat = (filename, options) => {
|
|
|
4874
5179
|
}
|
|
4875
5180
|
throw new Error(`Unsupported output file type: ${filename}`);
|
|
4876
5181
|
};
|
|
5182
|
+
/**
|
|
5183
|
+
* Writes Gaussian splat data to a file in the specified format.
|
|
5184
|
+
*
|
|
5185
|
+
* Supports multiple output formats including PLY, compressed PLY, CSV, SOG, LOD, and HTML.
|
|
5186
|
+
*
|
|
5187
|
+
* @param writeOptions - Options specifying the data and format to write.
|
|
5188
|
+
* @param fs - File system abstraction for writing files.
|
|
5189
|
+
*
|
|
5190
|
+
* @example
|
|
5191
|
+
* ```ts
|
|
5192
|
+
* import { writeFile, getOutputFormat, MemoryFileSystem } from '@playcanvas/splat-transform';
|
|
5193
|
+
*
|
|
5194
|
+
* const fs = new MemoryFileSystem();
|
|
5195
|
+
* await writeFile({
|
|
5196
|
+
* filename: 'output.sog',
|
|
5197
|
+
* outputFormat: getOutputFormat('output.sog', {}),
|
|
5198
|
+
* dataTable: myDataTable,
|
|
5199
|
+
* options: { iterations: 8 }
|
|
5200
|
+
* }, fs);
|
|
5201
|
+
* ```
|
|
5202
|
+
*/
|
|
4877
5203
|
const writeFile = async (writeOptions, fs) => {
|
|
4878
5204
|
const { filename, outputFormat, dataTable, envDataTable, options, createDevice } = writeOptions;
|
|
4879
5205
|
logger.log(`writing '${filename}'...`);
|
|
@@ -4981,7 +5307,28 @@ const filter = (dataTable, predicate) => {
|
|
|
4981
5307
|
}
|
|
4982
5308
|
return dataTable.permuteRows(indices.subarray(0, index));
|
|
4983
5309
|
};
|
|
4984
|
-
|
|
5310
|
+
/**
|
|
5311
|
+
* Applies a sequence of processing actions to splat data.
|
|
5312
|
+
*
|
|
5313
|
+
* Actions are applied in order and can include transformations (translate, rotate, scale),
|
|
5314
|
+
* filters (NaN, value, box, sphere, bands), and analysis (summary).
|
|
5315
|
+
*
|
|
5316
|
+
* @param dataTable - The input splat data.
|
|
5317
|
+
* @param processActions - Array of actions to apply in sequence.
|
|
5318
|
+
* @returns The processed DataTable (may be a new instance if filtered).
|
|
5319
|
+
*
|
|
5320
|
+
* @example
|
|
5321
|
+
* ```ts
|
|
5322
|
+
* import { Vec3 } from 'playcanvas';
|
|
5323
|
+
*
|
|
5324
|
+
* const processed = processDataTable(dataTable, [
|
|
5325
|
+
* { kind: 'scale', value: 0.5 },
|
|
5326
|
+
* { kind: 'translate', value: new Vec3(0, 1, 0) },
|
|
5327
|
+
* { kind: 'filterNaN' },
|
|
5328
|
+
* { kind: 'filterByValue', columnName: 'opacity', comparator: 'gt', value: 0.1 }
|
|
5329
|
+
* ]);
|
|
5330
|
+
* ```
|
|
5331
|
+
*/
|
|
4985
5332
|
const processDataTable = (dataTable, processActions) => {
|
|
4986
5333
|
let result = dataTable;
|
|
4987
5334
|
for (let i = 0; i < processActions.length; i++) {
|