@playcanvas/splat-transform 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,19 +1,19 @@
1
- Copyright (c) 2011-2024 PlayCanvas Ltd.
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy
4
- of this software and associated documentation files (the "Software"), to deal
5
- in the Software without restriction, including without limitation the rights
6
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- copies of the Software, and to permit persons to whom the Software is
8
- furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in
11
- all copies or substantial portions of the Software.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- THE SOFTWARE.
1
+ Copyright (c) 2011-2025 PlayCanvas Ltd.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
package/README.md CHANGED
@@ -1,127 +1,127 @@
1
- # SplatTransform - 3D Gaussian Splat Converter
2
-
3
- SplatTransform is an open source CLI tool for reading gaussian splat PLY files and writing them to PLY, Compressed PLY, CSV, and SOGS format.
4
-
5
- Multiple files may be combined and transformed before being written to the output.
6
-
7
- ## Installation
8
-
9
- First install the package globally:
10
-
11
- ```bash
12
- npm install -g @playcanvas/splat-transform
13
- ```
14
-
15
- ## Usage
16
-
17
- ```bash
18
- splat-transform [GLOBAL] <input.{ply|splat|ksplat}> [ACTIONS] ... <output.{ply|compressed.ply|meta.json|csv}> [ACTIONS]
19
- ```
20
-
21
- **Key points:**
22
- - Every time an `*.ply*` appears, it becomes the current working set; the following ACTIONS are applied in the order listed
23
- - The last file on the command line is treated as the output; anything after it is interpreted as actions that modify the final result
24
-
25
- ## Supported Formats
26
-
27
- **Input:**
28
- - `.ply` - Standard PLY format
29
- - `.splat` - Binary splat format (antimatter15 format)
30
- - `.ksplat` - Compressed binary splat format (mkkellogg format)
31
-
32
- **Output:**
33
- - `.ply` - Standard PLY format
34
- - `.compressed.ply` - Compressed PLY format
35
- - `meta.json` - SOGS format (JSON + WebP images)
36
- - `.csv` - Comma-separated values
37
-
38
- ## Actions
39
-
40
- Actions can be repeated and applied in any order:
41
-
42
- ```bash
43
- -t, --translate x,y,z Translate splats by (x, y, z)
44
- -r, --rotate x,y,z Rotate splats by Euler angles (deg)
45
- -s, --scale x Uniformly scale splats by factor x
46
- -n, --filterNaN Remove any Gaussian containing NaN/Inf
47
- -c, --filterByValue name,cmp,value Keep splats where <name> <cmp> <value>
48
- cmp ∈ {lt,lte,gt,gte,eq,neq}
49
- -b, --filterBands {0|1|2|3} Strip spherical-harmonic bands > N
50
- ```
51
-
52
- ## Global Options
53
-
54
- ```bash
55
- -w, --overwrite Overwrite output file if it already exists
56
- -h, --help Show help and exit
57
- -v, --version Show version and exit
58
- -g, --no-gpu Disable gpu when compressing spherical harmonics.
59
- -i, --iterations <number> Specify the number of iterations when compressing spherical harmonics. More iterations generally lead to better results. Default is 10.
60
- ```
61
-
62
- ## Examples
63
-
64
- ### Basic Operations
65
-
66
- ```bash
67
- # Simple format conversion
68
- splat-transform input.ply output.csv
69
-
70
- # Convert from .splat format
71
- splat-transform input.splat output.ply
72
-
73
- # Convert from .ksplat format
74
- splat-transform input.ksplat output.ply
75
-
76
- # Convert to compressed PLY
77
- splat-transform input.ply output.compressed.ply
78
-
79
- # Convert to SOGS format
80
- splat-transform input.ply output/meta.json
81
- ```
82
-
83
- ### Transformations
84
-
85
- ```bash
86
- # Scale and translate
87
- splat-transform bunny.ply -s 0.5 -t 0,0,10 bunny_scaled.ply
88
-
89
- # Rotate by 90 degrees around Y axis
90
- splat-transform input.ply -r 0,90,0 output.ply
91
-
92
- # Chain multiple transformations
93
- splat-transform input.ply -s 2 -t 1,0,0 -r 0,0,45 output.ply
94
- ```
95
-
96
- ### Filtering
97
-
98
- ```bash
99
- # Remove entries containing NaN and Inf
100
- splat-transform input.ply --filterNaN output.ply
101
-
102
- # Filter by opacity values (keep only splats with opacity > 0.5)
103
- splat-transform input.ply -c opacity,gt,0.5 output.ply
104
-
105
- # Strip spherical harmonic bands higher than 2
106
- splat-transform input.ply --filterBands 2 output.ply
107
- ```
108
-
109
- ### Advanced Usage
110
-
111
- ```bash
112
- # Combine multiple files with different transforms
113
- splat-transform -w cloudA.ply -r 0,90,0 cloudB.ply -s 2 merged.compressed.ply
114
-
115
- # Apply final transformations to combined result
116
- splat-transform input1.ply input2.ply output.ply -t 0,0,10 -s 0.5
117
- ```
118
-
119
- ## Getting Help
120
-
121
- ```bash
122
- # Show version
123
- splat-transform --version
124
-
125
- # Show help
126
- splat-transform --help
127
- ```
1
+ # SplatTransform - 3D Gaussian Splat Converter
2
+
3
+ SplatTransform is an open source CLI tool for reading gaussian splat PLY files and writing them to PLY, Compressed PLY, CSV, and SOGS format.
4
+
5
+ Multiple files may be combined and transformed before being written to the output.
6
+
7
+ ## Installation
8
+
9
+ First install the package globally:
10
+
11
+ ```bash
12
+ npm install -g @playcanvas/splat-transform
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```bash
18
+ splat-transform [GLOBAL] <input.{ply|splat|ksplat}> [ACTIONS] ... <output.{ply|compressed.ply|meta.json|csv}> [ACTIONS]
19
+ ```
20
+
21
+ **Key points:**
22
+ - Every time an `*.ply*` appears, it becomes the current working set; the following ACTIONS are applied in the order listed
23
+ - The last file on the command line is treated as the output; anything after it is interpreted as actions that modify the final result
24
+
25
+ ## Supported Formats
26
+
27
+ **Input:**
28
+ - `.ply` - Standard PLY format
29
+ - `.splat` - Binary splat format (antimatter15 format)
30
+ - `.ksplat` - Compressed binary splat format (mkkellogg format)
31
+
32
+ **Output:**
33
+ - `.ply` - Standard PLY format
34
+ - `.compressed.ply` - Compressed PLY format
35
+ - `meta.json` - SOGS format (JSON + WebP images)
36
+ - `.csv` - Comma-separated values
37
+
38
+ ## Actions
39
+
40
+ Actions can be repeated and applied in any order:
41
+
42
+ ```bash
43
+ -t, --translate x,y,z Translate splats by (x, y, z)
44
+ -r, --rotate x,y,z Rotate splats by Euler angles (deg)
45
+ -s, --scale x Uniformly scale splats by factor x
46
+ -n, --filterNaN Remove any Gaussian containing NaN/Inf
47
+ -c, --filterByValue name,cmp,value Keep splats where <name> <cmp> <value>
48
+ cmp ∈ {lt,lte,gt,gte,eq,neq}
49
+ -b, --filterBands {0|1|2|3} Strip spherical-harmonic bands > N
50
+ ```
51
+
52
+ ## Global Options
53
+
54
+ ```bash
55
+ -w, --overwrite Overwrite output file if it already exists
56
+ -h, --help Show help and exit
57
+ -v, --version Show version and exit
58
+ -g, --no-gpu Disable gpu when compressing spherical harmonics.
59
+ -i, --iterations <number> Specify the number of iterations when compressing spherical harmonics. More iterations generally lead to better results. Default is 10.
60
+ ```
61
+
62
+ ## Examples
63
+
64
+ ### Basic Operations
65
+
66
+ ```bash
67
+ # Simple format conversion
68
+ splat-transform input.ply output.csv
69
+
70
+ # Convert from .splat format
71
+ splat-transform input.splat output.ply
72
+
73
+ # Convert from .ksplat format
74
+ splat-transform input.ksplat output.ply
75
+
76
+ # Convert to compressed PLY
77
+ splat-transform input.ply output.compressed.ply
78
+
79
+ # Convert to SOGS format
80
+ splat-transform input.ply output/meta.json
81
+ ```
82
+
83
+ ### Transformations
84
+
85
+ ```bash
86
+ # Scale and translate
87
+ splat-transform bunny.ply -s 0.5 -t 0,0,10 bunny_scaled.ply
88
+
89
+ # Rotate by 90 degrees around Y axis
90
+ splat-transform input.ply -r 0,90,0 output.ply
91
+
92
+ # Chain multiple transformations
93
+ splat-transform input.ply -s 2 -t 1,0,0 -r 0,0,45 output.ply
94
+ ```
95
+
96
+ ### Filtering
97
+
98
+ ```bash
99
+ # Remove entries containing NaN and Inf
100
+ splat-transform input.ply --filterNaN output.ply
101
+
102
+ # Filter by opacity values (keep only splats with opacity > 0.5)
103
+ splat-transform input.ply -c opacity,gt,0.5 output.ply
104
+
105
+ # Strip spherical harmonic bands higher than 2
106
+ splat-transform input.ply --filterBands 2 output.ply
107
+ ```
108
+
109
+ ### Advanced Usage
110
+
111
+ ```bash
112
+ # Combine multiple files with different transforms
113
+ splat-transform -w cloudA.ply -r 0,90,0 cloudB.ply -s 2 merged.compressed.ply
114
+
115
+ # Apply final transformations to combined result
116
+ splat-transform input1.ply input2.ply output.ply -t 0,0,10 -s 0.5
117
+ ```
118
+
119
+ ## Getting Help
120
+
121
+ ```bash
122
+ # Show version
123
+ splat-transform --version
124
+
125
+ # Show help
126
+ splat-transform --help
127
+ ```
package/bin/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
- #!/usr/bin/env node
2
-
3
- import { main } from '../dist/index.mjs';
4
-
5
- await main();
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from '../dist/index.mjs';
4
+
5
+ await main();
package/dist/index.mjs CHANGED
@@ -1884,7 +1884,7 @@ let Quat$1 = class Quat {
1884
1884
  }
1885
1885
  };
1886
1886
 
1887
- var version$1 = "0.5.0";
1887
+ var version$1 = "0.5.2";
1888
1888
 
1889
1889
  class Column {
1890
1890
  name;
@@ -89014,116 +89014,131 @@ class KdTree {
89014
89014
  }
89015
89015
  }
89016
89016
 
89017
- const clusterWgsl = (numColumns, numPoints, numCentroids) => {
89018
- return `
89019
-
89020
- enable f16;
89021
-
89022
- @group(0) @binding(0) var<storage, read> points: array<f16>;
89023
- @group(0) @binding(1) var<storage, read> centroids: array<f16>;
89024
- @group(0) @binding(2) var<storage, read_write> results: array<u32>;
89025
-
89026
- const numColumns = ${numColumns};
89027
- const numPoints = ${numPoints};
89028
- const numCentroids = ${numCentroids};
89029
-
89030
- const chunkSize = 128u; // must be a multiple of 64
89031
- var<workgroup> sharedChunk: array<f16, numColumns * chunkSize>;
89032
-
89033
- // calculate the squared distance between the point and centroid
89034
- fn calcDistanceSqr(point: array<f16, numColumns>, centroid: u32) -> f32 {
89035
- var result = 0.0;
89036
-
89037
- var ci = centroid * numColumns;
89038
-
89039
- for (var i = 0u; i < numColumns; i++) {
89040
- let v = f32(point[i] - sharedChunk[ci+i]);
89041
- result += v * v;
89042
- }
89043
-
89044
- return result;
89045
- }
89046
-
89047
- @compute @workgroup_size(64)
89048
- fn main(
89049
- @builtin(local_invocation_index) local_id : u32,
89050
- @builtin(global_invocation_id) global_id: vec3u,
89051
- @builtin(num_workgroups) num_workgroups: vec3u
89052
- ) {
89053
- // calculate row index for this thread point
89054
- let pointIndex = global_id.x + global_id.y * num_workgroups.x * 64;
89055
-
89056
- // copy the point data from global memory
89057
- var point: array<f16, numColumns>;
89058
- if (pointIndex < numPoints) {
89059
- for (var i = 0u; i < numColumns; i++) {
89060
- point[i] = points[pointIndex * numColumns + i];
89061
- }
89062
- }
89063
-
89064
- var mind = 1000000.0;
89065
- var mini = 0u;
89066
-
89067
- // work through the list of centroids in shared memory chunks
89068
- let numChunks = u32(ceil(f32(numCentroids) / f32(chunkSize)));
89069
- for (var i = 0u; i < numChunks; i++) {
89070
-
89071
- // copy this thread's slice of the centroid shared chunk data
89072
- let dstRow = local_id * (chunkSize / 64u);
89073
- let srcRow = min(numCentroids, i * chunkSize + local_id * chunkSize / 64u);
89074
- let numRows = min(numCentroids, srcRow + chunkSize / 64u) - srcRow;
89075
-
89076
- var dst = dstRow * numColumns;
89077
- var src = srcRow * numColumns;
89078
-
89079
- for (var c = 0u; c < numRows * numColumns; c++) {
89080
- sharedChunk[dst + c] = centroids[src + c];
89081
- }
89082
-
89083
- // wait for all threads to finish writing their part of centroids shared memory buffer
89084
- workgroupBarrier();
89085
-
89086
- // loop over the next chunk of centroids finding the closest
89087
- if (pointIndex < numPoints) {
89088
- let thisChunkSize = min(chunkSize, numCentroids - i * chunkSize);
89089
- for (var c = 0u; c < thisChunkSize; c++) {
89090
- let d = calcDistanceSqr(point, c);
89091
- if (d < mind) {
89092
- mind = d;
89093
- mini = i * chunkSize + c;
89094
- }
89095
- }
89096
- }
89097
-
89098
- // next loop will overwrite the shared memory, so wait
89099
- workgroupBarrier();
89100
- }
89101
-
89102
- if (pointIndex < numPoints) {
89103
- results[pointIndex] = mini;
89104
- }
89105
- }
89017
+ const clusterWgsl = (numColumns, numPoints, numCentroids, useF16) => {
89018
+ const floatType = useF16 ? 'f16' : 'f32';
89019
+ return `
89020
+ ${useF16 ? 'enable f16;' : ''}
89021
+
89022
+ @group(0) @binding(0) var<storage, read> points: array<${floatType}>;
89023
+ @group(0) @binding(1) var<storage, read> centroids: array<${floatType}>;
89024
+ @group(0) @binding(2) var<storage, read_write> results: array<u32>;
89025
+
89026
+ const numColumns = ${numColumns};
89027
+ const numPoints = ${numPoints};
89028
+ const numCentroids = ${numCentroids};
89029
+
89030
+ const chunkSize = 128u; // must be a multiple of 64
89031
+ var<workgroup> sharedChunk: array<${floatType}, numColumns * chunkSize>;
89032
+
89033
+ // calculate the squared distance between the point and centroid
89034
+ fn calcDistanceSqr(point: array<${floatType}, numColumns>, centroid: u32) -> f32 {
89035
+ var result = 0.0;
89036
+
89037
+ var ci = centroid * numColumns;
89038
+
89039
+ for (var i = 0u; i < numColumns; i++) {
89040
+ let v = f32(point[i] - sharedChunk[ci+i]);
89041
+ result += v * v;
89042
+ }
89043
+
89044
+ return result;
89045
+ }
89046
+
89047
+ @compute @workgroup_size(64)
89048
+ fn main(
89049
+ @builtin(local_invocation_index) local_id : u32,
89050
+ @builtin(global_invocation_id) global_id: vec3u,
89051
+ @builtin(num_workgroups) num_workgroups: vec3u
89052
+ ) {
89053
+ // calculate row index for this thread point
89054
+ let pointIndex = global_id.x + global_id.y * num_workgroups.x * 64;
89055
+
89056
+ // copy the point data from global memory
89057
+ var point: array<${floatType}, numColumns>;
89058
+ if (pointIndex < numPoints) {
89059
+ for (var i = 0u; i < numColumns; i++) {
89060
+ point[i] = points[pointIndex * numColumns + i];
89061
+ }
89062
+ }
89063
+
89064
+ var mind = 1000000.0;
89065
+ var mini = 0u;
89066
+
89067
+ // work through the list of centroids in shared memory chunks
89068
+ let numChunks = u32(ceil(f32(numCentroids) / f32(chunkSize)));
89069
+ for (var i = 0u; i < numChunks; i++) {
89070
+
89071
+ // copy this thread's slice of the centroid shared chunk data
89072
+ let dstRow = local_id * (chunkSize / 64u);
89073
+ let srcRow = min(numCentroids, i * chunkSize + local_id * chunkSize / 64u);
89074
+ let numRows = min(numCentroids, srcRow + chunkSize / 64u) - srcRow;
89075
+
89076
+ var dst = dstRow * numColumns;
89077
+ var src = srcRow * numColumns;
89078
+
89079
+ for (var c = 0u; c < numRows * numColumns; c++) {
89080
+ sharedChunk[dst + c] = centroids[src + c];
89081
+ }
89082
+
89083
+ // wait for all threads to finish writing their part of centroids shared memory buffer
89084
+ workgroupBarrier();
89085
+
89086
+ // loop over the next chunk of centroids finding the closest
89087
+ if (pointIndex < numPoints) {
89088
+ let thisChunkSize = min(chunkSize, numCentroids - i * chunkSize);
89089
+ for (var c = 0u; c < thisChunkSize; c++) {
89090
+ let d = calcDistanceSqr(point, c);
89091
+ if (d < mind) {
89092
+ mind = d;
89093
+ mini = i * chunkSize + c;
89094
+ }
89095
+ }
89096
+ }
89097
+
89098
+ // next loop will overwrite the shared memory, so wait
89099
+ workgroupBarrier();
89100
+ }
89101
+
89102
+ if (pointIndex < numPoints) {
89103
+ results[pointIndex] = mini;
89104
+ }
89105
+ }
89106
89106
  `;
89107
89107
  };
89108
89108
  const roundUp = (value, multiple) => {
89109
89109
  return Math.ceil(value / multiple) * multiple;
89110
89110
  };
89111
- const interleaveData = (dataTable) => {
89111
+ const interleaveData = (dataTable, useF16) => {
89112
89112
  const { numRows, numColumns } = dataTable;
89113
- const result = new Uint16Array(roundUp(numColumns * numRows, 2));
89114
- for (let c = 0; c < numColumns; ++c) {
89115
- const column = dataTable.columns[c];
89116
- for (let r = 0; r < numRows; ++r) {
89117
- result[r * numColumns + c] = FloatPacking.float2Half(column.data[r]);
89113
+ if (useF16) {
89114
+ const result = new Uint16Array(roundUp(numColumns * numRows, 2));
89115
+ for (let c = 0; c < numColumns; ++c) {
89116
+ const column = dataTable.columns[c];
89117
+ for (let r = 0; r < numRows; ++r) {
89118
+ result[r * numColumns + c] = FloatPacking.float2Half(column.data[r]);
89119
+ }
89118
89120
  }
89121
+ return result;
89122
+ }
89123
+ else {
89124
+ const result = new Float32Array(numColumns * numRows);
89125
+ for (let c = 0; c < numColumns; ++c) {
89126
+ const column = dataTable.columns[c];
89127
+ for (let r = 0; r < numRows; ++r) {
89128
+ result[r * numColumns + c] = column.data[r];
89129
+ }
89130
+ }
89131
+ return result;
89119
89132
  }
89120
- return result;
89121
89133
  };
89122
89134
  class GpuCluster {
89123
89135
  execute;
89124
89136
  destroy;
89125
89137
  constructor(gpuDevice, points, numCentroids) {
89126
89138
  const device = gpuDevice.app.graphicsDevice;
89139
+ // Check if device supports f16
89140
+ const useF16 = !!('supportsShaderF16' in device && device.supportsShaderF16);
89141
+ const bytesPerFloat = useF16 ? 2 : 4;
89127
89142
  const bindGroupFormat = new BindGroupFormat(device, [
89128
89143
  new BindStorageBufferFormat('pointsBuffer', SHADERSTAGE_COMPUTE, true),
89129
89144
  new BindStorageBufferFormat('centroidsBuffer', SHADERSTAGE_COMPUTE, true),
@@ -89134,16 +89149,16 @@ class GpuCluster {
89134
89149
  const shader = new Shader(device, {
89135
89150
  name: 'compute-cluster',
89136
89151
  shaderLanguage: SHADERLANGUAGE_WGSL,
89137
- cshader: clusterWgsl(numColumns, numPoints, numCentroids),
89152
+ cshader: clusterWgsl(numColumns, numPoints, numCentroids, useF16),
89138
89153
  // @ts-ignore
89139
89154
  computeBindGroupFormat: bindGroupFormat
89140
89155
  });
89141
89156
  const compute = new Compute(device, shader, 'compute-cluster');
89142
- const pointsBuffer = new StorageBuffer(device, roundUp(numColumns * numPoints, 2) * 2, BUFFERUSAGE_COPY_DST);
89143
- const centroidsBuffer = new StorageBuffer(device, numColumns * numCentroids * 2, BUFFERUSAGE_COPY_DST);
89157
+ const pointsBuffer = new StorageBuffer(device, useF16 ? roundUp(numColumns * numPoints, 2) * 2 : numColumns * numPoints * 4, BUFFERUSAGE_COPY_DST);
89158
+ const centroidsBuffer = new StorageBuffer(device, numColumns * numCentroids * bytesPerFloat, BUFFERUSAGE_COPY_DST);
89144
89159
  const resultsBuffer = new StorageBuffer(device, numPoints * 4, BUFFERUSAGE_COPY_SRC | BUFFERUSAGE_COPY_DST);
89145
89160
  // interleave the points table data and write to gpu
89146
- const interleavedPoints = interleaveData(points);
89161
+ const interleavedPoints = interleaveData(points, useF16);
89147
89162
  pointsBuffer.write(0, interleavedPoints, 0, interleavedPoints.length);
89148
89163
  compute.setParameter('columns', numColumns);
89149
89164
  compute.setParameter('points', numPoints);
@@ -89153,7 +89168,7 @@ class GpuCluster {
89153
89168
  compute.setParameter('resultsBuffer', resultsBuffer);
89154
89169
  this.execute = async (centroids, labels) => {
89155
89170
  // interleave centroids and write to gpu
89156
- const interleavedCentroids = interleaveData(centroids);
89171
+ const interleavedCentroids = interleaveData(centroids, useF16);
89157
89172
  centroidsBuffer.write(0, interleavedCentroids, 0, interleavedCentroids.length);
89158
89173
  // calculate the workgroup layout to minimize the number of empty workgroups
89159
89174
  const groups = Math.ceil(points.numRows / 64);
@@ -89758,46 +89773,46 @@ const parseArguments = () => {
89758
89773
  }
89759
89774
  return { files, options };
89760
89775
  };
89761
- const usage = `
89762
- Apply geometric transforms & filters to Gaussian-splat point clouds
89763
- ===================================================================
89764
-
89765
- USAGE
89766
- splat-transform [GLOBAL] <input.{ply|splat|ksplat}> [ACTIONS] ... <output.{ply|compressed.ply|meta.json|csv}> [ACTIONS]
89767
-
89768
- • Every time an input file appears, it becomes the current working set; the following
89769
- ACTIONS are applied in the order listed.
89770
- • The last file on the command line is treated as the output; anything after it is
89771
- interpreted as actions that modify the final result.
89772
-
89773
- SUPPORTED INPUTS
89774
- .ply .splat .ksplat
89775
-
89776
- SUPPORTED OUTPUTS
89777
- .ply .compressed.ply meta.json (SOGS) .csv
89778
-
89779
- ACTIONS (can be repeated, in any order)
89780
- -t, --translate x,y,z Translate splats by (x, y, z)
89781
- -r, --rotate x,y,z Rotate splats by Euler angles (deg)
89782
- -s, --scale x Uniformly scale splats by factor x
89783
- -n, --filterNaN Remove any Gaussian containing NaN/Inf
89784
- -c, --filterByValue name,cmp,value Keep splats where <name> <cmp> <value>
89785
- cmp ∈ {lt,lte,gt,gte,eq,neq}
89786
- -b, --filterBands {0|1|2|3} Strip spherical-harmonic bands > N
89787
-
89788
- GLOBAL OPTIONS
89789
- -w, --overwrite Overwrite output file if it already exists. Default is false.
89790
- -h, --help Show this help and exit.
89791
- -v, --version Show version and exit.
89792
- -g, --no-gpu Disable gpu when compressing spherical harmonics.
89793
- -i, --iterations <number> Specify the number of iterations when compressing spherical harmonics. More iterations generally lead to better results. Default is 10.
89794
-
89795
- EXAMPLES
89796
- # Simple scale-then-translate
89797
- splat-transform bunny.ply -s 0.5 -t 0,0,10 bunny_scaled.ply
89798
-
89799
- # Chain two inputs and write compressed output, overwriting if necessary
89800
- splat-transform -w cloudA.ply -r 0,90,0 cloudB.ply -s 2 merged.compressed.ply
89776
+ const usage = `
89777
+ Apply geometric transforms & filters to Gaussian-splat point clouds
89778
+ ===================================================================
89779
+
89780
+ USAGE
89781
+ splat-transform [GLOBAL] <input.{ply|splat|ksplat}> [ACTIONS] ... <output.{ply|compressed.ply|meta.json|csv}> [ACTIONS]
89782
+
89783
+ • Every time an input file appears, it becomes the current working set; the following
89784
+ ACTIONS are applied in the order listed.
89785
+ • The last file on the command line is treated as the output; anything after it is
89786
+ interpreted as actions that modify the final result.
89787
+
89788
+ SUPPORTED INPUTS
89789
+ .ply .splat .ksplat
89790
+
89791
+ SUPPORTED OUTPUTS
89792
+ .ply .compressed.ply meta.json (SOGS) .csv
89793
+
89794
+ ACTIONS (can be repeated, in any order)
89795
+ -t, --translate x,y,z Translate splats by (x, y, z)
89796
+ -r, --rotate x,y,z Rotate splats by Euler angles (deg)
89797
+ -s, --scale x Uniformly scale splats by factor x
89798
+ -n, --filterNaN Remove any Gaussian containing NaN/Inf
89799
+ -c, --filterByValue name,cmp,value Keep splats where <name> <cmp> <value>
89800
+ cmp ∈ {lt,lte,gt,gte,eq,neq}
89801
+ -b, --filterBands {0|1|2|3} Strip spherical-harmonic bands > N
89802
+
89803
+ GLOBAL OPTIONS
89804
+ -w, --overwrite Overwrite output file if it already exists. Default is false.
89805
+ -h, --help Show this help and exit.
89806
+ -v, --version Show version and exit.
89807
+ -g, --no-gpu Disable gpu when compressing spherical harmonics.
89808
+ -i, --iterations <number> Specify the number of iterations when compressing spherical harmonics. More iterations generally lead to better results. Default is 10.
89809
+
89810
+ EXAMPLES
89811
+ # Simple scale-then-translate
89812
+ splat-transform bunny.ply -s 0.5 -t 0,0,10 bunny_scaled.ply
89813
+
89814
+ # Chain two inputs and write compressed output, overwriting if necessary
89815
+ splat-transform -w cloudA.ply -r 0,90,0 cloudB.ply -s 2 merged.compressed.ply
89801
89816
  `;
89802
89817
  const main = async () => {
89803
89818
  console.log(`splat-transform v${version$1}`);