@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/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://www.reddit.com/r/PlayCanvas)
|
|
8
8
|
[](https://x.com/intent/follow?screen_name=playcanvas)
|
|
9
9
|
|
|
10
|
-
| [User Guide](https://developer.playcanvas.com/user-manual/gaussian-splatting/editing/splat-transform/) | [Blog](https://blog.playcanvas.com/) | [Forum](https://forum.playcanvas.com/) |
|
|
10
|
+
| [User Guide](https://developer.playcanvas.com/user-manual/gaussian-splatting/editing/splat-transform/) | [API Reference](https://api.playcanvas.com/splat-transform/) | [Blog](https://blog.playcanvas.com/) | [Forum](https://forum.playcanvas.com/) |
|
|
11
11
|
|
|
12
12
|
SplatTransform is an open source library and CLI tool for converting and editing Gaussian splats. It can:
|
|
13
13
|
|
package/dist/cli.mjs
CHANGED
|
@@ -10702,6 +10702,18 @@ class Compute {
|
|
|
10702
10702
|
}
|
|
10703
10703
|
}
|
|
10704
10704
|
|
|
10705
|
+
/**
|
|
10706
|
+
* A named column of typed array data within a DataTable.
|
|
10707
|
+
*
|
|
10708
|
+
* Columns store homogeneous numeric data efficiently using JavaScript typed arrays.
|
|
10709
|
+
*
|
|
10710
|
+
* @example
|
|
10711
|
+
* ```ts
|
|
10712
|
+
* const positions = new Column('x', new Float32Array([1.0, 2.0, 3.0]));
|
|
10713
|
+
* console.log(positions.name); // 'x'
|
|
10714
|
+
* console.log(positions.dataType); // 'float32'
|
|
10715
|
+
* ```
|
|
10716
|
+
*/
|
|
10705
10717
|
class Column {
|
|
10706
10718
|
name;
|
|
10707
10719
|
data;
|
|
@@ -10726,6 +10738,32 @@ class Column {
|
|
|
10726
10738
|
return new Column(this.name, this.data.slice());
|
|
10727
10739
|
}
|
|
10728
10740
|
}
|
|
10741
|
+
/**
|
|
10742
|
+
* A table of columnar data representing Gaussian splat properties.
|
|
10743
|
+
*
|
|
10744
|
+
* DataTable is the core data structure for splat data. Each column represents
|
|
10745
|
+
* a property (e.g., position, rotation, color) as a typed array, and all columns
|
|
10746
|
+
* must have the same number of rows.
|
|
10747
|
+
*
|
|
10748
|
+
* Standard columns include:
|
|
10749
|
+
* - Position: `x`, `y`, `z`
|
|
10750
|
+
* - Rotation: `rot_0`, `rot_1`, `rot_2`, `rot_3` (quaternion)
|
|
10751
|
+
* - Scale: `scale_0`, `scale_1`, `scale_2` (log scale)
|
|
10752
|
+
* - Color: `f_dc_0`, `f_dc_1`, `f_dc_2` (spherical harmonics DC)
|
|
10753
|
+
* - Opacity: `opacity` (logit)
|
|
10754
|
+
* - Spherical Harmonics: `f_rest_0` through `f_rest_44`
|
|
10755
|
+
*
|
|
10756
|
+
* @example
|
|
10757
|
+
* ```ts
|
|
10758
|
+
* const table = new DataTable([
|
|
10759
|
+
* new Column('x', new Float32Array([0, 1, 2])),
|
|
10760
|
+
* new Column('y', new Float32Array([0, 0, 0])),
|
|
10761
|
+
* new Column('z', new Float32Array([0, 0, 0]))
|
|
10762
|
+
* ]);
|
|
10763
|
+
* console.log(table.numRows); // 3
|
|
10764
|
+
* console.log(table.numColumns); // 3
|
|
10765
|
+
* ```
|
|
10766
|
+
*/
|
|
10729
10767
|
class DataTable {
|
|
10730
10768
|
columns;
|
|
10731
10769
|
constructor(columns) {
|
|
@@ -10817,7 +10855,22 @@ class DataTable {
|
|
|
10817
10855
|
}
|
|
10818
10856
|
}
|
|
10819
10857
|
|
|
10820
|
-
|
|
10858
|
+
/**
|
|
10859
|
+
* Combines multiple DataTables into a single DataTable.
|
|
10860
|
+
*
|
|
10861
|
+
* Merges rows from all input tables. Columns are matched by name and type;
|
|
10862
|
+
* columns that don't exist in all tables will have undefined values for
|
|
10863
|
+
* rows from tables lacking that column.
|
|
10864
|
+
*
|
|
10865
|
+
* @param dataTables - Array of DataTables to combine.
|
|
10866
|
+
* @returns A new DataTable containing all rows from all input tables.
|
|
10867
|
+
*
|
|
10868
|
+
* @example
|
|
10869
|
+
* ```ts
|
|
10870
|
+
* const combined = combine([tableA, tableB, tableC]);
|
|
10871
|
+
* console.log(combined.numRows); // tableA.numRows + tableB.numRows + tableC.numRows
|
|
10872
|
+
* ```
|
|
10873
|
+
*/
|
|
10821
10874
|
const combine = (dataTables) => {
|
|
10822
10875
|
if (dataTables.length === 1) {
|
|
10823
10876
|
// nothing to combine
|
|
@@ -11043,7 +11096,25 @@ class RotateSH {
|
|
|
11043
11096
|
const shNames$3 = new Array(45).fill('').map((_, i) => `f_rest_${i}`);
|
|
11044
11097
|
const v = new Vec3();
|
|
11045
11098
|
const q$1 = new Quat();
|
|
11046
|
-
|
|
11099
|
+
/**
|
|
11100
|
+
* Applies a spatial transformation to splat data in-place.
|
|
11101
|
+
*
|
|
11102
|
+
* Transforms position, rotation, scale, and spherical harmonics data.
|
|
11103
|
+
* The transformation is applied as: scale first, then rotation, then translation.
|
|
11104
|
+
*
|
|
11105
|
+
* @param dataTable - The DataTable to transform (modified in-place).
|
|
11106
|
+
* @param t - Translation vector.
|
|
11107
|
+
* @param r - Rotation quaternion.
|
|
11108
|
+
* @param s - Uniform scale factor.
|
|
11109
|
+
*
|
|
11110
|
+
* @example
|
|
11111
|
+
* ```ts
|
|
11112
|
+
* import { Vec3, Quat } from 'playcanvas';
|
|
11113
|
+
*
|
|
11114
|
+
* // Scale by 2x, rotate 90° around Y, translate up
|
|
11115
|
+
* transform(dataTable, new Vec3(0, 5, 0), new Quat().setFromEulerAngles(0, 90, 0), 2.0);
|
|
11116
|
+
* ```
|
|
11117
|
+
*/
|
|
11047
11118
|
const transform = (dataTable, t, r, s) => {
|
|
11048
11119
|
const mat = new Mat4().setTRS(t, r, new Vec3(s, s, s));
|
|
11049
11120
|
const mat3 = new Mat3().setFromQuat(r);
|
|
@@ -11162,6 +11233,23 @@ const computeColumnStats = (data) => {
|
|
|
11162
11233
|
infCount
|
|
11163
11234
|
};
|
|
11164
11235
|
};
|
|
11236
|
+
/**
|
|
11237
|
+
* Computes statistical summary for all columns in a DataTable.
|
|
11238
|
+
*
|
|
11239
|
+
* For each column, calculates min, max, median, mean, standard deviation,
|
|
11240
|
+
* and counts of NaN/Infinity values. Useful for data validation and analysis.
|
|
11241
|
+
*
|
|
11242
|
+
* @param dataTable - The DataTable to analyze.
|
|
11243
|
+
* @returns Summary data with per-column statistics.
|
|
11244
|
+
*
|
|
11245
|
+
* @example
|
|
11246
|
+
* ```ts
|
|
11247
|
+
* const summary = computeSummary(dataTable);
|
|
11248
|
+
* console.log(summary.rowCount);
|
|
11249
|
+
* console.log(summary.columns['x'].mean);
|
|
11250
|
+
* console.log(summary.columns['opacity'].nanCount);
|
|
11251
|
+
* ```
|
|
11252
|
+
*/
|
|
11165
11253
|
const computeSummary = (dataTable) => {
|
|
11166
11254
|
const columns = {};
|
|
11167
11255
|
for (const column of dataTable.columns) {
|
|
@@ -11620,6 +11708,17 @@ const COMPRESSION_MODES = [
|
|
|
11620
11708
|
}
|
|
11621
11709
|
];
|
|
11622
11710
|
const HARMONICS_COMPONENT_COUNT$1 = [0, 9, 24, 45];
|
|
11711
|
+
/**
|
|
11712
|
+
* Reads a .ksplat file containing compressed Gaussian splat data.
|
|
11713
|
+
*
|
|
11714
|
+
* The .ksplat format (Kevin Kwok's format) uses spatial bucketing and
|
|
11715
|
+
* quantization to achieve high compression ratios while preserving quality.
|
|
11716
|
+
* Supports multiple compression modes and spherical harmonics bands.
|
|
11717
|
+
*
|
|
11718
|
+
* @param source - The read source providing access to the .ksplat file data.
|
|
11719
|
+
* @returns Promise resolving to a DataTable containing the splat data.
|
|
11720
|
+
* @ignore
|
|
11721
|
+
*/
|
|
11623
11722
|
const readKsplat = async (source) => {
|
|
11624
11723
|
// Load complete file
|
|
11625
11724
|
const fileBuffer = await source.read().readAll();
|
|
@@ -12283,6 +12382,19 @@ const deserializeEnvironment = (raw, compressInfo, hasSH) => {
|
|
|
12283
12382
|
}
|
|
12284
12383
|
return new DataTable(columns);
|
|
12285
12384
|
};
|
|
12385
|
+
/**
|
|
12386
|
+
* Reads an XGrids LCC format containing multi-LOD Gaussian splat data.
|
|
12387
|
+
*
|
|
12388
|
+
* The LCC format uses a quadtree spatial structure with multiple LOD levels.
|
|
12389
|
+
* Each LOD level is stored separately in data.bin with optional spherical
|
|
12390
|
+
* harmonics in shcoef.bin. Environment splats are stored in environment.bin.
|
|
12391
|
+
*
|
|
12392
|
+
* @param fileSystem - File system for reading the LCC files.
|
|
12393
|
+
* @param filename - Path to the meta.lcc file.
|
|
12394
|
+
* @param options - Options including LOD selection via `lodSelect`.
|
|
12395
|
+
* @returns Promise resolving to an array of DataTables, one per LOD level plus environment.
|
|
12396
|
+
* @ignore
|
|
12397
|
+
*/
|
|
12286
12398
|
const readLcc = async (fileSystem, filename, options) => {
|
|
12287
12399
|
const lccData = await readFile$1(fileSystem, filename);
|
|
12288
12400
|
const lccText = new TextDecoder().decode(lccData);
|
|
@@ -12357,6 +12469,18 @@ const readLcc = async (fileSystem, filename, options) => {
|
|
|
12357
12469
|
return result;
|
|
12358
12470
|
};
|
|
12359
12471
|
|
|
12472
|
+
/**
|
|
12473
|
+
* Reads splat data from a JavaScript module generator.
|
|
12474
|
+
*
|
|
12475
|
+
* The module must export a `Generator` class with a static `create(params)` method
|
|
12476
|
+
* that returns an object with `count`, `columnNames`, and `getRow(index, row)` properties.
|
|
12477
|
+
* This allows programmatic generation of splat data.
|
|
12478
|
+
*
|
|
12479
|
+
* @param moduleUrl - URL or path to the JavaScript module.
|
|
12480
|
+
* @param params - Parameters to pass to the generator's create method.
|
|
12481
|
+
* @returns Promise resolving to a DataTable containing the generated splat data.
|
|
12482
|
+
* @ignore
|
|
12483
|
+
*/
|
|
12360
12484
|
const readMjs = async (moduleUrl, params) => {
|
|
12361
12485
|
const module = await import(moduleUrl);
|
|
12362
12486
|
if (!module) {
|
|
@@ -12677,6 +12801,16 @@ const readExact = async (stream, buffer, offset, length) => {
|
|
|
12677
12801
|
}
|
|
12678
12802
|
return totalRead;
|
|
12679
12803
|
};
|
|
12804
|
+
/**
|
|
12805
|
+
* Reads a PLY file containing Gaussian splat data.
|
|
12806
|
+
*
|
|
12807
|
+
* Supports both standard PLY files and compressed PLY format. The PLY format is
|
|
12808
|
+
* the standard output from 3D Gaussian Splatting training pipelines.
|
|
12809
|
+
*
|
|
12810
|
+
* @param source - The read source providing access to the PLY file data.
|
|
12811
|
+
* @returns Promise resolving to a DataTable containing the splat data.
|
|
12812
|
+
* @ignore
|
|
12813
|
+
*/
|
|
12680
12814
|
const readPly = async (source) => {
|
|
12681
12815
|
const stream = source.read();
|
|
12682
12816
|
// we don't support ply text header larger than 128k
|
|
@@ -12889,6 +13023,7 @@ const sigmoidInv = (y) => {
|
|
|
12889
13023
|
* @param fileSystem - The file system to read from
|
|
12890
13024
|
* @param filename - Path to meta.json (relative paths resolved from its directory)
|
|
12891
13025
|
* @returns DataTable with Gaussian splat data
|
|
13026
|
+
* @ignore
|
|
12892
13027
|
*/
|
|
12893
13028
|
const readSog = async (fileSystem, filename) => {
|
|
12894
13029
|
const decoder = await WebPCodec.create();
|
|
@@ -13036,6 +13171,16 @@ const readSog = async (fileSystem, filename) => {
|
|
|
13036
13171
|
return new DataTable(columns);
|
|
13037
13172
|
};
|
|
13038
13173
|
|
|
13174
|
+
/**
|
|
13175
|
+
* Reads an Antimatter15 .splat file containing Gaussian splat data.
|
|
13176
|
+
*
|
|
13177
|
+
* The .splat format stores each splat as 32 bytes with position, scale, color,
|
|
13178
|
+
* opacity, and rotation data in a compact binary format.
|
|
13179
|
+
*
|
|
13180
|
+
* @param source - The read source providing access to the .splat file data.
|
|
13181
|
+
* @returns Promise resolving to a DataTable containing the splat data.
|
|
13182
|
+
* @ignore
|
|
13183
|
+
*/
|
|
13039
13184
|
const readSplat = async (source) => {
|
|
13040
13185
|
// Load complete file
|
|
13041
13186
|
const fileBuffer = await source.read().readAll();
|
|
@@ -13159,6 +13304,18 @@ function getFixed24(positionsView, elementIndex, memberIndex) {
|
|
|
13159
13304
|
return fixed32;
|
|
13160
13305
|
}
|
|
13161
13306
|
const HARMONICS_COMPONENT_COUNT = [0, 9, 24, 45];
|
|
13307
|
+
/**
|
|
13308
|
+
* Reads a .spz file containing Niantic Labs compressed Gaussian splat data.
|
|
13309
|
+
*
|
|
13310
|
+
* The .spz format uses GZIP compression and fixed-point encoding to achieve
|
|
13311
|
+
* compact file sizes. Supports version 2 and 3 of the format.
|
|
13312
|
+
*
|
|
13313
|
+
* @see https://github.com/nianticlabs/spz
|
|
13314
|
+
*
|
|
13315
|
+
* @param source - The read source providing access to the .spz file data.
|
|
13316
|
+
* @returns Promise resolving to a DataTable containing the splat data.
|
|
13317
|
+
* @ignore
|
|
13318
|
+
*/
|
|
13162
13319
|
const readSpz = async (source) => {
|
|
13163
13320
|
// Load complete file
|
|
13164
13321
|
let fileBuffer = await source.read().readAll();
|
|
@@ -13395,6 +13552,19 @@ const logger = {
|
|
|
13395
13552
|
}
|
|
13396
13553
|
};
|
|
13397
13554
|
|
|
13555
|
+
/**
|
|
13556
|
+
* Determines the input format based on file extension.
|
|
13557
|
+
*
|
|
13558
|
+
* @param filename - The filename to analyze.
|
|
13559
|
+
* @returns The detected input format.
|
|
13560
|
+
* @throws Error if the file extension is not recognized.
|
|
13561
|
+
*
|
|
13562
|
+
* @example
|
|
13563
|
+
* ```ts
|
|
13564
|
+
* const format = getInputFormat('scene.ply'); // returns 'ply'
|
|
13565
|
+
* const format2 = getInputFormat('scene.splat'); // returns 'splat'
|
|
13566
|
+
* ```
|
|
13567
|
+
*/
|
|
13398
13568
|
const getInputFormat = (filename) => {
|
|
13399
13569
|
const lowerFilename = filename.toLowerCase();
|
|
13400
13570
|
if (lowerFilename.endsWith('.mjs')) {
|
|
@@ -13420,6 +13590,30 @@ const getInputFormat = (filename) => {
|
|
|
13420
13590
|
}
|
|
13421
13591
|
throw new Error(`Unsupported input file type: ${filename}`);
|
|
13422
13592
|
};
|
|
13593
|
+
/**
|
|
13594
|
+
* Reads a Gaussian splat file and returns its data as one or more DataTables.
|
|
13595
|
+
*
|
|
13596
|
+
* Supports multiple input formats including PLY, splat, ksplat, spz, SOG, and LCC.
|
|
13597
|
+
* Some formats (like LCC) may return multiple DataTables for different LOD levels.
|
|
13598
|
+
*
|
|
13599
|
+
* @param readFileOptions - Options specifying the file to read and how to read it.
|
|
13600
|
+
* @returns Promise resolving to an array of DataTables containing the splat data.
|
|
13601
|
+
*
|
|
13602
|
+
* @example
|
|
13603
|
+
* ```ts
|
|
13604
|
+
* import { readFile, getInputFormat, UrlReadFileSystem } from '@playcanvas/splat-transform';
|
|
13605
|
+
*
|
|
13606
|
+
* const filename = 'scene.ply';
|
|
13607
|
+
* const fileSystem = new UrlReadFileSystem('https://example.com/');
|
|
13608
|
+
* const tables = await readFile({
|
|
13609
|
+
* filename,
|
|
13610
|
+
* inputFormat: getInputFormat(filename),
|
|
13611
|
+
* options: {},
|
|
13612
|
+
* params: [],
|
|
13613
|
+
* fileSystem
|
|
13614
|
+
* });
|
|
13615
|
+
* ```
|
|
13616
|
+
*/
|
|
13423
13617
|
const readFile = async (readFileOptions) => {
|
|
13424
13618
|
const { filename, inputFormat, options, params, fileSystem } = readFileOptions;
|
|
13425
13619
|
let result;
|
|
@@ -13614,7 +13808,7 @@ class CompressedChunk {
|
|
|
13614
13808
|
}
|
|
13615
13809
|
}
|
|
13616
13810
|
|
|
13617
|
-
var version = "1.
|
|
13811
|
+
var version = "1.1.0";
|
|
13618
13812
|
|
|
13619
13813
|
// sort the provided indices into morton order
|
|
13620
13814
|
const sortMortonOrder = (dataTable, indices) => {
|
|
@@ -13733,6 +13927,17 @@ const vertexProps = [
|
|
|
13733
13927
|
const shNames$2 = new Array(45).fill('').map((_, i) => `f_rest_${i}`);
|
|
13734
13928
|
// Size of a chunk in the compressed PLY format (number of splats per chunk)
|
|
13735
13929
|
const CHUNK_SIZE = 256;
|
|
13930
|
+
/**
|
|
13931
|
+
* Writes Gaussian splat data to compressed PLY format.
|
|
13932
|
+
*
|
|
13933
|
+
* Uses quantization and chunking to reduce file size while maintaining
|
|
13934
|
+
* compatibility with PLY-based viewers. Data is sorted using Morton order
|
|
13935
|
+
* for better compression and streaming performance.
|
|
13936
|
+
*
|
|
13937
|
+
* @param options - Options including filename and data table to write.
|
|
13938
|
+
* @param fs - File system for writing the output file.
|
|
13939
|
+
* @ignore
|
|
13940
|
+
*/
|
|
13736
13941
|
const writeCompressedPly = async (options, fs) => {
|
|
13737
13942
|
const { filename, dataTable } = options;
|
|
13738
13943
|
const shBands = { '9': 1, '24': 2, '-1': 3 }[shNames$2.findIndex(v => !dataTable.hasColumn(v))] ?? 0;
|
|
@@ -13806,6 +14011,16 @@ const writeCompressedPly = async (options, fs) => {
|
|
|
13806
14011
|
await writer.close();
|
|
13807
14012
|
};
|
|
13808
14013
|
|
|
14014
|
+
/**
|
|
14015
|
+
* Writes Gaussian splat data to a CSV text file.
|
|
14016
|
+
*
|
|
14017
|
+
* Useful for debugging, analysis, or importing into spreadsheet applications.
|
|
14018
|
+
* Each row represents one splat with all column values separated by commas.
|
|
14019
|
+
*
|
|
14020
|
+
* @param options - Options including filename and data table to write.
|
|
14021
|
+
* @param fs - File system for writing the output file.
|
|
14022
|
+
* @ignore
|
|
14023
|
+
*/
|
|
13809
14024
|
const writeCsv = async (options, fs) => {
|
|
13810
14025
|
const { filename, dataTable } = options;
|
|
13811
14026
|
const len = dataTable.numRows;
|
|
@@ -13877,6 +14092,21 @@ class MemoryWriter {
|
|
|
13877
14092
|
};
|
|
13878
14093
|
}
|
|
13879
14094
|
}
|
|
14095
|
+
/**
|
|
14096
|
+
* A file system that writes files to in-memory buffers.
|
|
14097
|
+
*
|
|
14098
|
+
* Useful for generating output without writing to disk, such as when
|
|
14099
|
+
* creating data for download or further processing.
|
|
14100
|
+
*
|
|
14101
|
+
* @example
|
|
14102
|
+
* ```ts
|
|
14103
|
+
* const fs = new MemoryFileSystem();
|
|
14104
|
+
* await writeFile({ filename: 'output.ply', ... }, fs);
|
|
14105
|
+
*
|
|
14106
|
+
* // Get the generated data
|
|
14107
|
+
* const data = fs.results.get('output.ply');
|
|
14108
|
+
* ```
|
|
14109
|
+
*/
|
|
13880
14110
|
class MemoryFileSystem {
|
|
13881
14111
|
results = new Map();
|
|
13882
14112
|
createWriter(filename) {
|
|
@@ -13943,7 +14173,26 @@ class ZipEntryWriter {
|
|
|
13943
14173
|
};
|
|
13944
14174
|
}
|
|
13945
14175
|
}
|
|
13946
|
-
|
|
14176
|
+
/**
|
|
14177
|
+
* A file system that writes files into a ZIP archive.
|
|
14178
|
+
*
|
|
14179
|
+
* Creates a ZIP file containing all written files. Used internally
|
|
14180
|
+
* for bundled output formats like .sog files.
|
|
14181
|
+
*
|
|
14182
|
+
* @example
|
|
14183
|
+
* ```ts
|
|
14184
|
+
* const outputWriter = await fs.createWriter('bundle.zip');
|
|
14185
|
+
* const zipFs = new ZipFileSystem(outputWriter);
|
|
14186
|
+
*
|
|
14187
|
+
* // Write files into the zip
|
|
14188
|
+
* const writer = await zipFs.createWriter('data.json');
|
|
14189
|
+
* await writer.write(jsonData);
|
|
14190
|
+
* await writer.close();
|
|
14191
|
+
*
|
|
14192
|
+
* // Finalize the zip
|
|
14193
|
+
* await zipFs.close();
|
|
14194
|
+
* ```
|
|
14195
|
+
*/
|
|
13947
14196
|
class ZipFileSystem {
|
|
13948
14197
|
close;
|
|
13949
14198
|
createWriter;
|
|
@@ -14523,6 +14772,17 @@ const cluster1d = async (dataTable, iterations, device) => {
|
|
|
14523
14772
|
};
|
|
14524
14773
|
};
|
|
14525
14774
|
let webPCodec;
|
|
14775
|
+
/**
|
|
14776
|
+
* Writes Gaussian splat data to the PlayCanvas SOG format.
|
|
14777
|
+
*
|
|
14778
|
+
* SOG (Splat Optimized Graphics) uses WebP lossless compression and k-means
|
|
14779
|
+
* clustering to achieve high compression ratios. Data is stored in textures
|
|
14780
|
+
* for efficient GPU loading.
|
|
14781
|
+
*
|
|
14782
|
+
* @param options - Options including filename, data, and compression settings.
|
|
14783
|
+
* @param fs - File system for writing output files.
|
|
14784
|
+
* @ignore
|
|
14785
|
+
*/
|
|
14526
14786
|
const writeSog = async (options, fs) => {
|
|
14527
14787
|
const { filename: outputFilename, bundle, dataTable, iterations, createDevice } = options;
|
|
14528
14788
|
// initialize output stream - use ZipFileSystem for bundled output
|
|
@@ -14761,6 +15021,16 @@ const toBase64 = (bytes) => {
|
|
|
14761
15021
|
return btoa(binary);
|
|
14762
15022
|
};
|
|
14763
15023
|
|
|
15024
|
+
/**
|
|
15025
|
+
* Writes Gaussian splat data as a self-contained HTML viewer.
|
|
15026
|
+
*
|
|
15027
|
+
* Creates an interactive 3D viewer that can be opened directly in a browser.
|
|
15028
|
+
* Uses the PlayCanvas SuperSplat viewer for rendering.
|
|
15029
|
+
*
|
|
15030
|
+
* @param options - Options including filename, data, and viewer settings.
|
|
15031
|
+
* @param fs - File system for writing output files.
|
|
15032
|
+
* @ignore
|
|
15033
|
+
*/
|
|
14764
15034
|
const writeHtml = async (options, fs) => {
|
|
14765
15035
|
const { filename, dataTable, viewerSettingsJson, bundle, iterations, createDevice } = options;
|
|
14766
15036
|
const pad = (text, spaces) => {
|
|
@@ -15056,6 +15326,17 @@ const binIndices = (parent, lod) => {
|
|
|
15056
15326
|
recurse(parent);
|
|
15057
15327
|
return result;
|
|
15058
15328
|
};
|
|
15329
|
+
/**
|
|
15330
|
+
* Writes Gaussian splat data to multi-LOD format with spatial chunking.
|
|
15331
|
+
*
|
|
15332
|
+
* Creates a hierarchical structure with multiple LOD levels, each stored
|
|
15333
|
+
* in separate SOG files. Includes spatial indexing via a binary tree for
|
|
15334
|
+
* efficient streaming and view-dependent loading.
|
|
15335
|
+
*
|
|
15336
|
+
* @param options - Options including filename, data, and chunking parameters.
|
|
15337
|
+
* @param fs - File system for writing output files.
|
|
15338
|
+
* @ignore
|
|
15339
|
+
*/
|
|
15059
15340
|
const writeLod = async (options, fs) => {
|
|
15060
15341
|
const { filename, dataTable, envDataTable, iterations, createDevice, chunkCount, chunkExtent } = options;
|
|
15061
15342
|
const outputDir = dirname(filename);
|
|
@@ -15207,6 +15488,16 @@ const columnTypeToPlyType = (type) => {
|
|
|
15207
15488
|
case 'uint32': return 'uint';
|
|
15208
15489
|
}
|
|
15209
15490
|
};
|
|
15491
|
+
/**
|
|
15492
|
+
* Writes Gaussian splat data to a binary PLY file.
|
|
15493
|
+
*
|
|
15494
|
+
* The PLY format is the standard output from 3D Gaussian Splatting training
|
|
15495
|
+
* and is widely supported by visualization tools.
|
|
15496
|
+
*
|
|
15497
|
+
* @param options - Options including filename and PLY data to write.
|
|
15498
|
+
* @param fs - File system for writing the output file.
|
|
15499
|
+
* @ignore
|
|
15500
|
+
*/
|
|
15210
15501
|
const writePly = async (options, fs) => {
|
|
15211
15502
|
const { filename, plyData } = options;
|
|
15212
15503
|
const header = [
|
|
@@ -15255,6 +15546,20 @@ const writePly = async (options, fs) => {
|
|
|
15255
15546
|
await writer.close();
|
|
15256
15547
|
};
|
|
15257
15548
|
|
|
15549
|
+
/**
|
|
15550
|
+
* Determines the output format based on file extension and options.
|
|
15551
|
+
*
|
|
15552
|
+
* @param filename - The filename to analyze.
|
|
15553
|
+
* @param options - Options that may affect format selection.
|
|
15554
|
+
* @returns The detected output format.
|
|
15555
|
+
* @throws Error if the file extension is not recognized.
|
|
15556
|
+
*
|
|
15557
|
+
* @example
|
|
15558
|
+
* ```ts
|
|
15559
|
+
* const format = getOutputFormat('scene.ply', {}); // returns 'ply'
|
|
15560
|
+
* const format2 = getOutputFormat('scene.sog', {}); // returns 'sog-bundle'
|
|
15561
|
+
* ```
|
|
15562
|
+
*/
|
|
15258
15563
|
const getOutputFormat = (filename, options) => {
|
|
15259
15564
|
const lowerFilename = filename.toLowerCase();
|
|
15260
15565
|
if (lowerFilename.endsWith('.csv')) {
|
|
@@ -15280,6 +15585,27 @@ const getOutputFormat = (filename, options) => {
|
|
|
15280
15585
|
}
|
|
15281
15586
|
throw new Error(`Unsupported output file type: ${filename}`);
|
|
15282
15587
|
};
|
|
15588
|
+
/**
|
|
15589
|
+
* Writes Gaussian splat data to a file in the specified format.
|
|
15590
|
+
*
|
|
15591
|
+
* Supports multiple output formats including PLY, compressed PLY, CSV, SOG, LOD, and HTML.
|
|
15592
|
+
*
|
|
15593
|
+
* @param writeOptions - Options specifying the data and format to write.
|
|
15594
|
+
* @param fs - File system abstraction for writing files.
|
|
15595
|
+
*
|
|
15596
|
+
* @example
|
|
15597
|
+
* ```ts
|
|
15598
|
+
* import { writeFile, getOutputFormat, MemoryFileSystem } from '@playcanvas/splat-transform';
|
|
15599
|
+
*
|
|
15600
|
+
* const fs = new MemoryFileSystem();
|
|
15601
|
+
* await writeFile({
|
|
15602
|
+
* filename: 'output.sog',
|
|
15603
|
+
* outputFormat: getOutputFormat('output.sog', {}),
|
|
15604
|
+
* dataTable: myDataTable,
|
|
15605
|
+
* options: { iterations: 8 }
|
|
15606
|
+
* }, fs);
|
|
15607
|
+
* ```
|
|
15608
|
+
*/
|
|
15283
15609
|
const writeFile = async (writeOptions, fs) => {
|
|
15284
15610
|
const { filename, outputFormat, dataTable, envDataTable, options, createDevice } = writeOptions;
|
|
15285
15611
|
logger.log(`writing '${filename}'...`);
|
|
@@ -15387,7 +15713,28 @@ const filter = (dataTable, predicate) => {
|
|
|
15387
15713
|
}
|
|
15388
15714
|
return dataTable.permuteRows(indices.subarray(0, index));
|
|
15389
15715
|
};
|
|
15390
|
-
|
|
15716
|
+
/**
|
|
15717
|
+
* Applies a sequence of processing actions to splat data.
|
|
15718
|
+
*
|
|
15719
|
+
* Actions are applied in order and can include transformations (translate, rotate, scale),
|
|
15720
|
+
* filters (NaN, value, box, sphere, bands), and analysis (summary).
|
|
15721
|
+
*
|
|
15722
|
+
* @param dataTable - The input splat data.
|
|
15723
|
+
* @param processActions - Array of actions to apply in sequence.
|
|
15724
|
+
* @returns The processed DataTable (may be a new instance if filtered).
|
|
15725
|
+
*
|
|
15726
|
+
* @example
|
|
15727
|
+
* ```ts
|
|
15728
|
+
* import { Vec3 } from 'playcanvas';
|
|
15729
|
+
*
|
|
15730
|
+
* const processed = processDataTable(dataTable, [
|
|
15731
|
+
* { kind: 'scale', value: 0.5 },
|
|
15732
|
+
* { kind: 'translate', value: new Vec3(0, 1, 0) },
|
|
15733
|
+
* { kind: 'filterNaN' },
|
|
15734
|
+
* { kind: 'filterByValue', columnName: 'opacity', comparator: 'gt', value: 0.1 }
|
|
15735
|
+
* ]);
|
|
15736
|
+
* ```
|
|
15737
|
+
*/
|
|
15391
15738
|
const processDataTable = (dataTable, processActions) => {
|
|
15392
15739
|
let result = dataTable;
|
|
15393
15740
|
for (let i = 0; i < processActions.length; i++) {
|