@playcanvas/splat-transform 0.14.0 → 0.14.1
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 +2 -0
- package/dist/index.mjs +91 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -67,6 +67,7 @@ Actions can be repeated and applied in any order:
|
|
|
67
67
|
-V, --filter-value <name,cmp,value> Keep splats where <name> <cmp> <value>
|
|
68
68
|
cmp ∈ {lt,lte,gt,gte,eq,neq}
|
|
69
69
|
-p, --params <key=val,...> Pass parameters to .mjs generator script
|
|
70
|
+
-l, --lod <n> Specify the level of detail of this model, n >= 0.
|
|
70
71
|
```
|
|
71
72
|
|
|
72
73
|
## Global Options
|
|
@@ -74,6 +75,7 @@ Actions can be repeated and applied in any order:
|
|
|
74
75
|
```none
|
|
75
76
|
-h, --help Show this help and exit
|
|
76
77
|
-v, --version Show version and exit
|
|
78
|
+
-q, --quiet Suppress non-error output
|
|
77
79
|
-w, --overwrite Overwrite output file if it exists
|
|
78
80
|
-c, --cpu Use CPU for SOG spherical harmonic compression
|
|
79
81
|
-i, --iterations <n> Iterations for SOG SH compression (more=better). Default: 10
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from 'crypto';
|
|
2
2
|
import { open, readFile as readFile$1, unlink, mkdir, lstat, rename } from 'node:fs/promises';
|
|
3
3
|
import { join, dirname, resolve as resolve$2, basename } from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { hrtime, exit } from 'node:process';
|
|
5
5
|
import { parseArgs } from 'node:util';
|
|
6
6
|
import { Buffer as Buffer$1 } from 'node:buffer';
|
|
7
7
|
import os from 'node:os';
|
|
@@ -58527,7 +58527,7 @@ class TextureHandler extends ResourceHandler {
|
|
|
58527
58527
|
}
|
|
58528
58528
|
}
|
|
58529
58529
|
|
|
58530
|
-
var version = "0.14.
|
|
58530
|
+
var version = "0.14.1";
|
|
58531
58531
|
|
|
58532
58532
|
class Column {
|
|
58533
58533
|
name;
|
|
@@ -58644,6 +58644,73 @@ class DataTable {
|
|
|
58644
58644
|
}
|
|
58645
58645
|
}
|
|
58646
58646
|
|
|
58647
|
+
/**
|
|
58648
|
+
* Simple logger utility. Currently supports quiet mode. Designed to be extended for multiple log
|
|
58649
|
+
* levels in the future.
|
|
58650
|
+
*/
|
|
58651
|
+
class Logger {
|
|
58652
|
+
level = 'normal';
|
|
58653
|
+
setLevel(level) {
|
|
58654
|
+
this.level = level;
|
|
58655
|
+
}
|
|
58656
|
+
setQuiet(quiet) {
|
|
58657
|
+
this.level = quiet ? 'silent' : 'normal';
|
|
58658
|
+
}
|
|
58659
|
+
/**
|
|
58660
|
+
* Log informational messages (file operations, progress, etc.). Suppressed in quiet mode.
|
|
58661
|
+
* @param {...any} args - The arguments to log.
|
|
58662
|
+
*/
|
|
58663
|
+
info(...args) {
|
|
58664
|
+
if (this.level !== 'silent') {
|
|
58665
|
+
console.log(...args);
|
|
58666
|
+
}
|
|
58667
|
+
}
|
|
58668
|
+
/**
|
|
58669
|
+
* Log warning messages. Suppressed in quiet mode.
|
|
58670
|
+
* @param {...any} args - The arguments to log.
|
|
58671
|
+
*/
|
|
58672
|
+
warn(...args) {
|
|
58673
|
+
if (this.level !== 'silent') {
|
|
58674
|
+
console.warn(...args);
|
|
58675
|
+
}
|
|
58676
|
+
}
|
|
58677
|
+
/**
|
|
58678
|
+
* Log error messages. Always shown, even in quiet mode.
|
|
58679
|
+
* @param {...any} args - The arguments to log.
|
|
58680
|
+
*/
|
|
58681
|
+
error(...args) {
|
|
58682
|
+
console.error(...args);
|
|
58683
|
+
}
|
|
58684
|
+
/**
|
|
58685
|
+
* Log debug/verbose messages. Currently treated the same as info, but can be filtered
|
|
58686
|
+
* separately in the future.
|
|
58687
|
+
* @param {...any} args - The arguments to log.
|
|
58688
|
+
*/
|
|
58689
|
+
debug(...args) {
|
|
58690
|
+
if (this.level !== 'silent') {
|
|
58691
|
+
console.log(...args);
|
|
58692
|
+
}
|
|
58693
|
+
}
|
|
58694
|
+
/**
|
|
58695
|
+
* Write progress indicators directly to stdout (without newline). Suppressed in quiet mode.
|
|
58696
|
+
* @param text - The text to write.
|
|
58697
|
+
*/
|
|
58698
|
+
progress(text) {
|
|
58699
|
+
if (this.level !== 'silent') {
|
|
58700
|
+
process.stdout.write(text);
|
|
58701
|
+
}
|
|
58702
|
+
}
|
|
58703
|
+
/**
|
|
58704
|
+
* Check if logger is in quiet/silent mode.
|
|
58705
|
+
* @returns True if the logger is in quiet/silent mode, false otherwise.
|
|
58706
|
+
*/
|
|
58707
|
+
isQuiet() {
|
|
58708
|
+
return this.level === 'silent';
|
|
58709
|
+
}
|
|
58710
|
+
}
|
|
58711
|
+
// Export singleton instance
|
|
58712
|
+
const logger = new Logger();
|
|
58713
|
+
|
|
58647
58714
|
/* eslint-disable indent */
|
|
58648
58715
|
const kSqrt03_02 = Math.sqrt(3.0 / 2.0);
|
|
58649
58716
|
const kSqrt01_03 = Math.sqrt(1.0 / 3.0);
|
|
@@ -60853,7 +60920,7 @@ const generateOrdering = (dataTable, indices) => {
|
|
|
60853
60920
|
const ylen = My - my;
|
|
60854
60921
|
const zlen = Mz - mz;
|
|
60855
60922
|
if (!isFinite(xlen) || !isFinite(ylen) || !isFinite(zlen)) {
|
|
60856
|
-
|
|
60923
|
+
logger.debug('invalid extents', xlen, ylen, zlen);
|
|
60857
60924
|
return;
|
|
60858
60925
|
}
|
|
60859
60926
|
// all points are identical
|
|
@@ -60889,7 +60956,7 @@ const generateOrdering = (dataTable, indices) => {
|
|
|
60889
60956
|
++end;
|
|
60890
60957
|
}
|
|
60891
60958
|
if (end - start > 256) {
|
|
60892
|
-
//
|
|
60959
|
+
// logger.debug('sorting', end - start);
|
|
60893
60960
|
generate(indices.subarray(start, end));
|
|
60894
60961
|
}
|
|
60895
60962
|
start = end;
|
|
@@ -61096,7 +61163,7 @@ const createDevice = async () => {
|
|
|
61096
61163
|
await graphicsDevice.createDevice();
|
|
61097
61164
|
// print gpu info
|
|
61098
61165
|
const info = graphicsDevice.gpuAdapter.info;
|
|
61099
|
-
|
|
61166
|
+
logger.debug(`Created gpu device="${info.device || '-'}" arch="${info.architecture || '-'}" descr="${info.description || '-'}"`);
|
|
61100
61167
|
// create the application
|
|
61101
61168
|
const app = new Application(canvas, { graphicsDevice });
|
|
61102
61169
|
// create external backbuffer
|
|
@@ -61639,7 +61706,7 @@ const kmeans = async (points, k, iterations, device) => {
|
|
|
61639
61706
|
const labels = new Uint32Array(points.numRows);
|
|
61640
61707
|
let converged = false;
|
|
61641
61708
|
let steps = 0;
|
|
61642
|
-
|
|
61709
|
+
logger.debug(`Running k-means clustering: dims=${points.numColumns} points=${points.numRows} clusters=${k} iterations=${iterations}...`);
|
|
61643
61710
|
while (!converged) {
|
|
61644
61711
|
if (gpuClustering) {
|
|
61645
61712
|
await gpuClustering.execute(points, centroids, labels);
|
|
@@ -61665,12 +61732,12 @@ const kmeans = async (points, k, iterations, device) => {
|
|
|
61665
61732
|
if (steps >= iterations) {
|
|
61666
61733
|
converged = true;
|
|
61667
61734
|
}
|
|
61668
|
-
|
|
61735
|
+
logger.progress('#');
|
|
61669
61736
|
}
|
|
61670
61737
|
if (gpuClustering) {
|
|
61671
61738
|
gpuClustering.destroy();
|
|
61672
61739
|
}
|
|
61673
|
-
|
|
61740
|
+
logger.debug(' done 🎉');
|
|
61674
61741
|
return { centroids, labels };
|
|
61675
61742
|
};
|
|
61676
61743
|
|
|
@@ -61766,7 +61833,7 @@ const writeSog = async (fileHandle, dataTable, outputFilename, options, indices
|
|
|
61766
61833
|
const layout = identity; // rectChunks;
|
|
61767
61834
|
const write = async (filename, data, w = width, h = height) => {
|
|
61768
61835
|
const pathname = resolve$2(dirname(outputFilename), filename);
|
|
61769
|
-
|
|
61836
|
+
logger.info(`writing '${pathname}'...`);
|
|
61770
61837
|
// construct the encoder on first use
|
|
61771
61838
|
if (!webPCodec) {
|
|
61772
61839
|
webPCodec = await WebPCodec.create();
|
|
@@ -62192,7 +62259,7 @@ const calcBound = (dataTable, indices) => {
|
|
|
62192
62259
|
const m = b.getMin();
|
|
62193
62260
|
const M = b.getMax();
|
|
62194
62261
|
if (!isFinite(m.x) || !isFinite(m.y) || !isFinite(m.z) || !isFinite(M.x) || !isFinite(M.y) || !isFinite(M.z)) {
|
|
62195
|
-
|
|
62262
|
+
logger.warn('Skipping invalid bounding box:', { m, M, index });
|
|
62196
62263
|
continue;
|
|
62197
62264
|
}
|
|
62198
62265
|
min[0] = Math.min(min[0], m.x);
|
|
@@ -62336,7 +62403,7 @@ const writeLod = async (fileHandle, dataTable, outputFilename, options) => {
|
|
|
62336
62403
|
}
|
|
62337
62404
|
// write file unit to sog
|
|
62338
62405
|
const outputFile = await open(pathname, 'w');
|
|
62339
|
-
|
|
62406
|
+
logger.info(`writing ${pathname}...`);
|
|
62340
62407
|
await writeSog(outputFile, unitDataTable, pathname, options, indices);
|
|
62341
62408
|
await outputFile.close();
|
|
62342
62409
|
}
|
|
@@ -62461,7 +62528,7 @@ const getOutputFormat = (filename) => {
|
|
|
62461
62528
|
const readFile = async (filename, options, params) => {
|
|
62462
62529
|
const inputFormat = getInputFormat(filename);
|
|
62463
62530
|
let result;
|
|
62464
|
-
|
|
62531
|
+
logger.info(`reading '${filename}'...`);
|
|
62465
62532
|
if (inputFormat === 'mjs') {
|
|
62466
62533
|
result = [await readMjs(filename, params)];
|
|
62467
62534
|
}
|
|
@@ -62501,7 +62568,7 @@ const readFile = async (filename, options, params) => {
|
|
|
62501
62568
|
const writeFile = async (filename, dataTable, options) => {
|
|
62502
62569
|
// get the output format, throws on failure
|
|
62503
62570
|
const outputFormat = getOutputFormat(filename);
|
|
62504
|
-
|
|
62571
|
+
logger.info(`writing '${filename}'...`);
|
|
62505
62572
|
// write to a temporary file and rename on success
|
|
62506
62573
|
const tmpFilename = `.${basename(filename)}.${process.pid}.${Date.now()}.${randomBytes(6).toString('hex')}.tmp`;
|
|
62507
62574
|
const tmpPathname = join(dirname(filename), tmpFilename);
|
|
@@ -62614,6 +62681,7 @@ const parseArguments = () => {
|
|
|
62614
62681
|
overwrite: { type: 'boolean', short: 'w', default: false },
|
|
62615
62682
|
help: { type: 'boolean', short: 'h', default: false },
|
|
62616
62683
|
version: { type: 'boolean', short: 'v', default: false },
|
|
62684
|
+
quiet: { type: 'boolean', short: 'q', default: false },
|
|
62617
62685
|
cpu: { type: 'boolean', short: 'c', default: false },
|
|
62618
62686
|
iterations: { type: 'string', short: 'i', default: '10' },
|
|
62619
62687
|
'lod-select': { type: 'string', short: 'O', default: '' },
|
|
@@ -62671,6 +62739,7 @@ const parseArguments = () => {
|
|
|
62671
62739
|
overwrite: v.overwrite,
|
|
62672
62740
|
help: v.help,
|
|
62673
62741
|
version: v.version,
|
|
62742
|
+
quiet: v.quiet,
|
|
62674
62743
|
cpu: v.cpu,
|
|
62675
62744
|
iterations: parseInteger(v.iterations),
|
|
62676
62745
|
lodSelect: v['lod-select'].split(',').filter(v => !!v).map(parseInteger),
|
|
@@ -62830,6 +62899,7 @@ ACTIONS (can be repeated, in any order)
|
|
|
62830
62899
|
GLOBAL OPTIONS
|
|
62831
62900
|
-h, --help Show this help and exit
|
|
62832
62901
|
-v, --version Show version and exit
|
|
62902
|
+
-q, --quiet Suppress non-error output
|
|
62833
62903
|
-w, --overwrite Overwrite output file if it exists
|
|
62834
62904
|
-c, --cpu Use CPU for SOG spherical harmonic compression
|
|
62835
62905
|
-i, --iterations <n> Iterations for SOG SH compression (more=better). Default: 10
|
|
@@ -62855,17 +62925,19 @@ EXAMPLES
|
|
|
62855
62925
|
splat-transform -O 0,1,2 -C 1024 -X 32 input.lcc output/lod-meta.json
|
|
62856
62926
|
`;
|
|
62857
62927
|
const main = async () => {
|
|
62858
|
-
console.log(`splat-transform v${version}`);
|
|
62859
62928
|
const startTime = hrtime();
|
|
62860
62929
|
// read args
|
|
62861
62930
|
const { files, options } = parseArguments();
|
|
62931
|
+
// configure logger
|
|
62932
|
+
logger.setQuiet(options.quiet);
|
|
62933
|
+
logger.info(`splat-transform v${version}`);
|
|
62862
62934
|
// show version and exit
|
|
62863
62935
|
if (options.version) {
|
|
62864
62936
|
exit(0);
|
|
62865
62937
|
}
|
|
62866
62938
|
// invalid args or show help
|
|
62867
62939
|
if (files.length < 2 || options.help) {
|
|
62868
|
-
|
|
62940
|
+
logger.error(usage);
|
|
62869
62941
|
exit(1);
|
|
62870
62942
|
}
|
|
62871
62943
|
const inputArgs = files.slice(0, -1);
|
|
@@ -62878,7 +62950,7 @@ const main = async () => {
|
|
|
62878
62950
|
else {
|
|
62879
62951
|
// check overwrite before doing any work
|
|
62880
62952
|
if (await fileExists(outputFilename)) {
|
|
62881
|
-
|
|
62953
|
+
logger.error(`File '${outputFilename}' already exists. Use -w option to overwrite.`);
|
|
62882
62954
|
exit(1);
|
|
62883
62955
|
}
|
|
62884
62956
|
}
|
|
@@ -62905,17 +62977,17 @@ const main = async () => {
|
|
|
62905
62977
|
if (dataTable.numRows === 0) {
|
|
62906
62978
|
throw new Error('No splats to write');
|
|
62907
62979
|
}
|
|
62908
|
-
|
|
62980
|
+
logger.info(`Loaded ${dataTable.numRows} gaussians`);
|
|
62909
62981
|
// write file
|
|
62910
62982
|
await writeFile(outputFilename, dataTable, options);
|
|
62911
62983
|
}
|
|
62912
62984
|
catch (err) {
|
|
62913
62985
|
// handle errors
|
|
62914
|
-
|
|
62986
|
+
logger.error(err);
|
|
62915
62987
|
exit(1);
|
|
62916
62988
|
}
|
|
62917
62989
|
const endTime = hrtime(startTime);
|
|
62918
|
-
|
|
62990
|
+
logger.info(`done in ${endTime[0] + endTime[1] / 1e9}s`);
|
|
62919
62991
|
// something in webgpu seems to keep the process alive after returning
|
|
62920
62992
|
// from main so force exit
|
|
62921
62993
|
exit(0);
|