@manycore/aholo-splat-transform 1.2.7 → 1.2.9

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +120 -106
  2. package/COPYRIGHT.md +17 -0
  3. package/README.md +39 -39
  4. package/THIRD_PARTY_LICENSES.txt +1373 -0
  5. package/bin/cli.js +125 -118
  6. package/dist/SplatData.d.ts +67 -67
  7. package/dist/SplatData.js +167 -156
  8. package/dist/constant.d.ts +3 -3
  9. package/dist/constant.js +13 -13
  10. package/dist/file/IFile.d.ts +5 -5
  11. package/dist/file/IFile.js +1 -1
  12. package/dist/file/esz.d.ts +11 -0
  13. package/dist/file/esz.js +337 -0
  14. package/dist/file/index.d.ts +8 -7
  15. package/dist/file/index.js +7 -6
  16. package/dist/file/ksplat.d.ts +12 -12
  17. package/dist/file/ksplat.js +293 -232
  18. package/dist/file/lcc.d.ts +11 -11
  19. package/dist/file/lcc.js +161 -157
  20. package/dist/file/ply.d.ts +13 -13
  21. package/dist/file/ply.js +439 -388
  22. package/dist/file/sog.d.ts +80 -80
  23. package/dist/file/sog.js +525 -504
  24. package/dist/file/splat.d.ts +6 -6
  25. package/dist/file/splat.js +119 -99
  26. package/dist/file/spz.d.ts +11 -8
  27. package/dist/file/spz.js +597 -400
  28. package/dist/file/voxel.d.ts +43 -37
  29. package/dist/file/voxel.js +411 -280
  30. package/dist/index.d.ts +33 -33
  31. package/dist/index.js +54 -54
  32. package/dist/native/index.d.ts +54 -54
  33. package/dist/native/index.js +122 -128
  34. package/dist/native/utils.d.ts +1 -0
  35. package/dist/native/utils.js +54 -0
  36. package/dist/tasks/AutoChunkLodTask.d.ts +13 -13
  37. package/dist/tasks/AutoChunkLodTask.js +117 -117
  38. package/dist/tasks/AutoLodTask.d.ts +10 -10
  39. package/dist/tasks/AutoLodTask.js +20 -20
  40. package/dist/tasks/BaseTask.d.ts +15 -15
  41. package/dist/tasks/BaseTask.js +5 -5
  42. package/dist/tasks/FlexLodTask.d.ts +12 -12
  43. package/dist/tasks/FlexLodTask.js +54 -44
  44. package/dist/tasks/ModifyTask.d.ts +9 -9
  45. package/dist/tasks/ModifyTask.js +166 -156
  46. package/dist/tasks/ReadTask.d.ts +9 -9
  47. package/dist/tasks/ReadTask.js +29 -29
  48. package/dist/tasks/SkeletonLodTask.d.ts +10 -10
  49. package/dist/tasks/SkeletonLodTask.js +176 -156
  50. package/dist/tasks/VoxelTask.d.ts +35 -30
  51. package/dist/tasks/VoxelTask.js +40 -37
  52. package/dist/tasks/WriteTask.d.ts +12 -11
  53. package/dist/tasks/WriteTask.js +70 -70
  54. package/dist/utils/BufferReader.d.ts +12 -12
  55. package/dist/utils/BufferReader.js +45 -47
  56. package/dist/utils/Logger.d.ts +11 -11
  57. package/dist/utils/Logger.js +40 -38
  58. package/dist/utils/StreamChunkDecoder.d.ts +16 -16
  59. package/dist/utils/StreamChunkDecoder.js +31 -36
  60. package/dist/utils/index.d.ts +27 -27
  61. package/dist/utils/index.js +101 -101
  62. package/dist/utils/k-means.d.ts +4 -4
  63. package/dist/utils/k-means.js +340 -350
  64. package/dist/utils/math.d.ts +46 -46
  65. package/dist/utils/math.js +350 -351
  66. package/dist/utils/quantize-1d.d.ts +4 -4
  67. package/dist/utils/quantize-1d.js +164 -164
  68. package/dist/utils/sh-rotate.d.ts +2 -2
  69. package/dist/utils/sh-rotate.js +236 -175
  70. package/dist/utils/splat.d.ts +21 -20
  71. package/dist/utils/splat.js +397 -378
  72. package/dist/utils/voxel/binary.d.ts +8 -0
  73. package/dist/utils/voxel/binary.js +176 -0
  74. package/dist/utils/voxel/common.d.ts +178 -162
  75. package/dist/utils/voxel/common.js +1752 -1700
  76. package/dist/utils/voxel/coplanar-merge.d.ts +63 -63
  77. package/dist/utils/voxel/coplanar-merge.js +818 -819
  78. package/dist/utils/voxel/filter-cluster.d.ts +20 -0
  79. package/dist/utils/voxel/filter-cluster.js +628 -0
  80. package/dist/utils/voxel/gpu-dilation.d.ts +2 -2
  81. package/dist/utils/voxel/gpu-dilation.js +677 -665
  82. package/dist/utils/voxel/marching-cubes.d.ts +42 -42
  83. package/dist/utils/voxel/marching-cubes.js +1645 -1657
  84. package/dist/utils/voxel/mesh.d.ts +3 -3
  85. package/dist/utils/voxel/mesh.js +130 -130
  86. package/dist/utils/voxel/nav.d.ts +29 -29
  87. package/dist/utils/voxel/nav.js +1068 -1043
  88. package/dist/utils/voxel/postprocess.d.ts +23 -23
  89. package/dist/utils/voxel/postprocess.js +408 -375
  90. package/dist/utils/voxel/voxel-faces.d.ts +18 -18
  91. package/dist/utils/voxel/voxel-faces.js +662 -663
  92. package/dist/utils/voxel/voxelize.d.ts +34 -33
  93. package/dist/utils/voxel/voxelize.js +1208 -1193
  94. package/dist/utils/webgpu.d.ts +8 -8
  95. package/dist/utils/webgpu.js +122 -122
  96. package/package.json +37 -30
  97. package/dist/native/cpp/bin/linux/binding.node +0 -0
  98. package/dist/native/cpp/bin/windows/binding.node +0 -0
@@ -1,156 +1,176 @@
1
- import { SplatData } from '../SplatData.js';
2
- import { BaseTask } from './BaseTask.js';
3
- const VOXEL_CHUNK_SIZE = 0.02;
4
- const VOXEL_CHUNK_SCALE = 1.3;
5
- export class SkeletonLodTask extends BaseTask {
6
- async exec(config, { logger, resources }) {
7
- const { input, output, counts = 85000, ratio = 0.1 } = config;
8
- const splat = resources.get(input);
9
- logger.info(`loaded -> "${input}"`);
10
- const target = Math.min(Math.ceil(splat.counts * ratio), counts);
11
- logger.info(`expected -> ${target}(${((target / splat.counts) * 100).toFixed(2)}%) | ratio=${ratio} counts=${counts}`);
12
- const xCol = splat.table[0 /* ColIdx.x */];
13
- const yCol = splat.table[1 /* ColIdx.y */];
14
- const zCol = splat.table[2 /* ColIdx.z */];
15
- let minX = Infinity;
16
- let minY = Infinity;
17
- let minZ = Infinity;
18
- for (let i = 0; i < splat.counts; i++) {
19
- const x = xCol[i];
20
- const y = yCol[i];
21
- const z = zCol[i];
22
- if (x < minX) {
23
- minX = x;
24
- }
25
- if (y < minY) {
26
- minY = y;
27
- }
28
- if (z < minZ) {
29
- minZ = z;
30
- }
31
- }
32
- const chunkMap = new Map();
33
- for (let i = 0; i < splat.counts; i++) {
34
- const x = ((xCol[i] - minX) / VOXEL_CHUNK_SIZE) | 0;
35
- const y = ((yCol[i] - minY) / VOXEL_CHUNK_SIZE) | 0;
36
- const z = ((zCol[i] - minZ) / VOXEL_CHUNK_SIZE) | 0;
37
- const key = `${x},${y},${z}`;
38
- let arr = chunkMap.get(key);
39
- if (!arr) {
40
- arr = [];
41
- chunkMap.set(key, arr);
42
- }
43
- arr.push(i);
44
- }
45
- const chunks = Array.from(chunkMap.values());
46
- const CHUNK_RATIO = chunks.reduce((p, c) => p + c.length ** VOXEL_CHUNK_SCALE, 0) / (target * 0.1);
47
- const mergeChucks = [];
48
- for (let i = 0; i < chunks.length; i++) {
49
- const chunk = chunks[i];
50
- const size = Math.max(1, Math.ceil((chunk.length ** VOXEL_CHUNK_SCALE) / CHUNK_RATIO));
51
- if (size === 1) {
52
- mergeChucks.push(chunk);
53
- continue;
54
- }
55
- let minX = Infinity;
56
- let minY = Infinity;
57
- let minZ = Infinity;
58
- let maxX = -Infinity;
59
- let maxY = -Infinity;
60
- let maxZ = -Infinity;
61
- for (let j = 0; j < chunk.length; j++) {
62
- const offset = chunk[j];
63
- const x = xCol[offset];
64
- const y = yCol[offset];
65
- const z = zCol[offset];
66
- if (x < minX) {
67
- minX = x;
68
- }
69
- if (y < minY) {
70
- minY = y;
71
- }
72
- if (z < minZ) {
73
- minZ = z;
74
- }
75
- if (x > maxX) {
76
- maxX = x;
77
- }
78
- if (y > maxY) {
79
- maxY = y;
80
- }
81
- if (z > maxZ) {
82
- maxZ = z;
83
- }
84
- }
85
- const subChuckSize = Math.ceil(Math.cbrt(size));
86
- const scaleX = subChuckSize / Math.max(maxX - minX, 1e-9);
87
- const scaleY = subChuckSize / Math.max(maxY - minY, 1e-9);
88
- const scaleZ = subChuckSize / Math.max(maxZ - minZ, 1e-9);
89
- const subChunkMap = new Map();
90
- for (let j = 0; j < chunk.length; j++) {
91
- const idx = chunk[j];
92
- const x = ((xCol[idx] - minX) * scaleX) | 0;
93
- const y = ((yCol[idx] - minY) * scaleY) | 0;
94
- const z = ((zCol[idx] - minZ) * scaleZ) | 0;
95
- const key = `${x},${y},${z}`;
96
- let arr = subChunkMap.get(key);
97
- if (!arr) {
98
- arr = [];
99
- subChunkMap.set(key, arr);
100
- }
101
- arr.push(idx);
102
- }
103
- const subChunks = Array.from(subChunkMap.values());
104
- if (subChunks.length > size) {
105
- subChunks.sort((a, b) => b.length - a.length);
106
- subChunks.length = size;
107
- }
108
- for (let j = 0; j < subChunks.length; j++) {
109
- mergeChucks.push(subChunks[j]);
110
- }
111
- }
112
- if (mergeChucks.length > target) {
113
- mergeChucks.sort((a, b) => b.length - a.length);
114
- mergeChucks.length = target;
115
- }
116
- const raw = new SplatData().init(mergeChucks.length, 0);
117
- const result = {
118
- x: 0, y: 0, z: 0,
119
- sx: 0.005, sy: 0.005, sz: 0.005,
120
- qx: 0, qy: 0, qz: 0, qw: 1,
121
- r: 0, g: 0, b: 0, a: 0,
122
- shN: [],
123
- };
124
- const single = {
125
- x: 0, y: 0, z: 0,
126
- sx: 0, sy: 0, sz: 0,
127
- qx: 0, qy: 0, qz: 0, qw: 0,
128
- r: 0, g: 0, b: 0, a: 0,
129
- shN: [],
130
- };
131
- for (let i = 0; i < mergeChucks.length; i++) {
132
- const chunk = mergeChucks[i];
133
- for (let j = 0; j < chunk.length; j++) {
134
- splat.get(chunk[j], single);
135
- result.x += single.x;
136
- result.y += single.y;
137
- result.z += single.z;
138
- result.r += single.r;
139
- result.g += single.g;
140
- result.b += single.b;
141
- result.a += single.a;
142
- }
143
- result.x /= chunk.length;
144
- result.y /= chunk.length;
145
- result.z /= chunk.length;
146
- result.r /= chunk.length;
147
- result.g /= chunk.length;
148
- result.b /= chunk.length;
149
- result.a /= chunk.length;
150
- raw.set(i, result);
151
- result.x = result.y = result.z = result.r = result.g = result.b = result.a = 0;
152
- }
153
- resources.set(output, raw);
154
- logger.info(`stored -> key="${output}"`);
155
- }
156
- }
1
+ import { ColIdx, SplatData } from '../SplatData.js';
2
+ import { BaseTask } from './BaseTask.js';
3
+ const VOXEL_CHUNK_SIZE = 0.02;
4
+ const VOXEL_CHUNK_SCALE = 1.3;
5
+ export class SkeletonLodTask extends BaseTask {
6
+ async exec(config, { logger, resources }) {
7
+ const { input, output, counts = 85000, ratio = 0.1 } = config;
8
+ const splat = resources.get(input);
9
+ logger.info(`loaded -> "${input}"`);
10
+ const target = Math.min(Math.ceil(splat.counts * ratio), counts);
11
+ logger.info(`expected -> ${target}(${((target / splat.counts) * 100).toFixed(2)}%) | ratio=${ratio} counts=${counts}`);
12
+ const xCol = splat.table[ColIdx.x];
13
+ const yCol = splat.table[ColIdx.y];
14
+ const zCol = splat.table[ColIdx.z];
15
+ let minX = Infinity;
16
+ let minY = Infinity;
17
+ let minZ = Infinity;
18
+ for (let i = 0; i < splat.counts; i++) {
19
+ const x = xCol[i];
20
+ const y = yCol[i];
21
+ const z = zCol[i];
22
+ if (x < minX) {
23
+ minX = x;
24
+ }
25
+ if (y < minY) {
26
+ minY = y;
27
+ }
28
+ if (z < minZ) {
29
+ minZ = z;
30
+ }
31
+ }
32
+ const chunkMap = new Map();
33
+ for (let i = 0; i < splat.counts; i++) {
34
+ const x = ((xCol[i] - minX) / VOXEL_CHUNK_SIZE) | 0;
35
+ const y = ((yCol[i] - minY) / VOXEL_CHUNK_SIZE) | 0;
36
+ const z = ((zCol[i] - minZ) / VOXEL_CHUNK_SIZE) | 0;
37
+ const key = `${x},${y},${z}`;
38
+ let arr = chunkMap.get(key);
39
+ if (!arr) {
40
+ arr = [];
41
+ chunkMap.set(key, arr);
42
+ }
43
+ arr.push(i);
44
+ }
45
+ const chunks = Array.from(chunkMap.values());
46
+ const CHUNK_RATIO = chunks.reduce((p, c) => p + c.length ** VOXEL_CHUNK_SCALE, 0) / (target * 0.1);
47
+ const mergeChucks = [];
48
+ for (let i = 0; i < chunks.length; i++) {
49
+ const chunk = chunks[i];
50
+ const size = Math.max(1, Math.ceil(chunk.length ** VOXEL_CHUNK_SCALE / CHUNK_RATIO));
51
+ if (size === 1) {
52
+ mergeChucks.push(chunk);
53
+ continue;
54
+ }
55
+ let minX = Infinity;
56
+ let minY = Infinity;
57
+ let minZ = Infinity;
58
+ let maxX = -Infinity;
59
+ let maxY = -Infinity;
60
+ let maxZ = -Infinity;
61
+ for (let j = 0; j < chunk.length; j++) {
62
+ const offset = chunk[j];
63
+ const x = xCol[offset];
64
+ const y = yCol[offset];
65
+ const z = zCol[offset];
66
+ if (x < minX) {
67
+ minX = x;
68
+ }
69
+ if (y < minY) {
70
+ minY = y;
71
+ }
72
+ if (z < minZ) {
73
+ minZ = z;
74
+ }
75
+ if (x > maxX) {
76
+ maxX = x;
77
+ }
78
+ if (y > maxY) {
79
+ maxY = y;
80
+ }
81
+ if (z > maxZ) {
82
+ maxZ = z;
83
+ }
84
+ }
85
+ const subChuckSize = Math.ceil(Math.cbrt(size));
86
+ const scaleX = subChuckSize / Math.max(maxX - minX, 1e-9);
87
+ const scaleY = subChuckSize / Math.max(maxY - minY, 1e-9);
88
+ const scaleZ = subChuckSize / Math.max(maxZ - minZ, 1e-9);
89
+ const subChunkMap = new Map();
90
+ for (let j = 0; j < chunk.length; j++) {
91
+ const idx = chunk[j];
92
+ const x = ((xCol[idx] - minX) * scaleX) | 0;
93
+ const y = ((yCol[idx] - minY) * scaleY) | 0;
94
+ const z = ((zCol[idx] - minZ) * scaleZ) | 0;
95
+ const key = `${x},${y},${z}`;
96
+ let arr = subChunkMap.get(key);
97
+ if (!arr) {
98
+ arr = [];
99
+ subChunkMap.set(key, arr);
100
+ }
101
+ arr.push(idx);
102
+ }
103
+ const subChunks = Array.from(subChunkMap.values());
104
+ if (subChunks.length > size) {
105
+ subChunks.sort((a, b) => b.length - a.length);
106
+ subChunks.length = size;
107
+ }
108
+ for (let j = 0; j < subChunks.length; j++) {
109
+ mergeChucks.push(subChunks[j]);
110
+ }
111
+ }
112
+ if (mergeChucks.length > target) {
113
+ mergeChucks.sort((a, b) => b.length - a.length);
114
+ mergeChucks.length = target;
115
+ }
116
+ const raw = new SplatData().init(mergeChucks.length, 0);
117
+ const result = {
118
+ x: 0,
119
+ y: 0,
120
+ z: 0,
121
+ sx: 0.005,
122
+ sy: 0.005,
123
+ sz: 0.005,
124
+ qx: 0,
125
+ qy: 0,
126
+ qz: 0,
127
+ qw: 1,
128
+ r: 0,
129
+ g: 0,
130
+ b: 0,
131
+ a: 0,
132
+ shN: [],
133
+ };
134
+ const single = {
135
+ x: 0,
136
+ y: 0,
137
+ z: 0,
138
+ sx: 0,
139
+ sy: 0,
140
+ sz: 0,
141
+ qx: 0,
142
+ qy: 0,
143
+ qz: 0,
144
+ qw: 0,
145
+ r: 0,
146
+ g: 0,
147
+ b: 0,
148
+ a: 0,
149
+ shN: [],
150
+ };
151
+ for (let i = 0; i < mergeChucks.length; i++) {
152
+ const chunk = mergeChucks[i];
153
+ for (let j = 0; j < chunk.length; j++) {
154
+ splat.get(chunk[j], single);
155
+ result.x += single.x;
156
+ result.y += single.y;
157
+ result.z += single.z;
158
+ result.r += single.r;
159
+ result.g += single.g;
160
+ result.b += single.b;
161
+ result.a += single.a;
162
+ }
163
+ result.x /= chunk.length;
164
+ result.y /= chunk.length;
165
+ result.z /= chunk.length;
166
+ result.r /= chunk.length;
167
+ result.g /= chunk.length;
168
+ result.b /= chunk.length;
169
+ result.a /= chunk.length;
170
+ raw.set(i, result);
171
+ result.x = result.y = result.z = result.r = result.g = result.b = result.a = 0;
172
+ }
173
+ resources.set(output, raw);
174
+ logger.info(`stored -> key="${output}"`);
175
+ }
176
+ }
@@ -1,30 +1,35 @@
1
- import { Context, BaseTask } from './BaseTask.js';
2
- export interface VoxelTaskConfig {
3
- input: string;
4
- output: string;
5
- voxelResolution?: number;
6
- opacityCutoff?: number;
7
- backend?: 'cpu' | 'gpu';
8
- collisionMesh?: boolean | 'smooth' | 'faces';
9
- navExteriorRadius?: number;
10
- floorFill?: boolean;
11
- floorFillDilation?: number;
12
- cpuWorkerCount?: number;
13
- box?: {
14
- minCorner: [number, number, number];
15
- maxCorner: [number, number, number];
16
- };
17
- navCapsule?: {
18
- height: number;
19
- radius: number;
20
- };
21
- navSeed?: {
22
- x: number;
23
- y: number;
24
- z: number;
25
- };
26
- }
27
- export declare class VoxelTask extends BaseTask<VoxelTaskConfig> {
28
- exec(config: VoxelTaskConfig, { logger, resources }: Context): Promise<void>;
29
- requiresGPU(_config: VoxelTaskConfig): boolean;
30
- }
1
+ import type { FilterClusterOptions } from '../utils/voxel/filter-cluster.js';
2
+ import type { VoxelNodeEncoding } from '../utils/voxel/binary.js';
3
+ import { type Context, BaseTask } from './BaseTask.js';
4
+ export interface VoxelTaskConfig {
5
+ input: string;
6
+ output: string;
7
+ voxelResolution?: number;
8
+ opacityCutoff?: number;
9
+ backend?: 'cpu' | 'gpu';
10
+ collisionMesh?: boolean | 'smooth' | 'faces';
11
+ navExteriorRadius?: number;
12
+ floorFill?: boolean;
13
+ floorFillDilation?: number;
14
+ cpuWorkerCount?: number;
15
+ box?: {
16
+ minCorner: [number, number, number];
17
+ maxCorner: [number, number, number];
18
+ };
19
+ navCapsule?: {
20
+ height: number;
21
+ radius: number;
22
+ };
23
+ navSeed?: {
24
+ x: number;
25
+ y: number;
26
+ z: number;
27
+ };
28
+ gzip?: boolean;
29
+ nodeEncoding?: VoxelNodeEncoding;
30
+ filterCluster?: boolean | FilterClusterOptions;
31
+ }
32
+ export declare class VoxelTask extends BaseTask<VoxelTaskConfig> {
33
+ exec(config: VoxelTaskConfig, { logger, resources }: Context): Promise<void>;
34
+ requiresGPU(_config: VoxelTaskConfig): boolean;
35
+ }
@@ -1,37 +1,40 @@
1
- import { SplatData } from '../SplatData.js';
2
- import { writeVoxelFiles } from '../file/voxel.js';
3
- import { BaseTask } from './BaseTask.js';
4
- export class VoxelTask extends BaseTask {
5
- async exec(config, { logger, resources }) {
6
- const { input, output, voxelResolution = 0.05, opacityCutoff = 0.1, backend = 'gpu', collisionMesh = false, navExteriorRadius, floorFill = false, floorFillDilation = 0, cpuWorkerCount = -1, box = { minCorner: [-100, -100, -100], maxCorner: [100, 100, 100] }, navCapsule, navSeed } = config;
7
- const source = resources.get(input);
8
- if (!(source instanceof SplatData)) {
9
- throw new Error(`VoxelTask: resource "${input}" must be SplatData`);
10
- }
11
- const options = {
12
- voxelResolution,
13
- opacityCutoff,
14
- backend,
15
- collisionMesh,
16
- floorFill,
17
- floorFillDilation,
18
- cpuWorkerCount,
19
- box
20
- };
21
- if (navExteriorRadius !== undefined) {
22
- options.navExteriorRadius = navExteriorRadius;
23
- }
24
- if (navCapsule !== undefined) {
25
- options.navCapsule = navCapsule;
26
- }
27
- if (navSeed !== undefined) {
28
- options.navSeed = navSeed;
29
- }
30
- logger.info(`writing voxel -> dir="${output}" count=${source.counts} SH=${source.shDegree}`);
31
- await writeVoxelFiles(output, source, options);
32
- logger.info('voxelizing done');
33
- }
34
- requiresGPU(_config) {
35
- return (_config.backend ?? 'gpu') === 'gpu';
36
- }
37
- }
1
+ import { SplatData } from '../SplatData.js';
2
+ import { writeVoxelFiles } from '../file/voxel.js';
3
+ import { BaseTask } from './BaseTask.js';
4
+ export class VoxelTask extends BaseTask {
5
+ async exec(config, { logger, resources }) {
6
+ const { input, output, voxelResolution = 0.05, opacityCutoff = 0.1, backend = 'gpu', collisionMesh = false, navExteriorRadius, floorFill = false, floorFillDilation = 0, cpuWorkerCount = -1, box = { minCorner: [-100, -100, -100], maxCorner: [100, 100, 100] }, navCapsule, navSeed, gzip = false, nodeEncoding = 'raw', filterCluster = true, } = config;
7
+ const source = resources.get(input);
8
+ if (!(source instanceof SplatData)) {
9
+ throw new Error(`VoxelTask: resource "${input}" must be SplatData`);
10
+ }
11
+ const options = {
12
+ voxelResolution,
13
+ opacityCutoff,
14
+ backend,
15
+ collisionMesh,
16
+ floorFill,
17
+ floorFillDilation,
18
+ cpuWorkerCount,
19
+ box,
20
+ gzip,
21
+ nodeEncoding,
22
+ filterCluster,
23
+ };
24
+ if (navExteriorRadius !== undefined) {
25
+ options.navExteriorRadius = navExteriorRadius;
26
+ }
27
+ if (navCapsule !== undefined) {
28
+ options.navCapsule = navCapsule;
29
+ }
30
+ if (navSeed !== undefined) {
31
+ options.navSeed = navSeed;
32
+ }
33
+ logger.info(`writing voxel -> dir="${output}" count=${source.counts} SH=${source.shDegree}`);
34
+ await writeVoxelFiles(output, source, options);
35
+ logger.info('voxelizing done');
36
+ }
37
+ requiresGPU(_config) {
38
+ return (_config.backend ?? 'gpu') === 'gpu';
39
+ }
40
+ }
@@ -1,11 +1,12 @@
1
- import { Context, BaseTask } from './BaseTask.js';
2
- export interface Config {
3
- input: string;
4
- output: string;
5
- enableMortonSort?: boolean;
6
- compressLevel?: number;
7
- }
8
- export declare class WriteTask extends BaseTask<Config> {
9
- exec(config: Config, { logger, resources }: Context): Promise<void>;
10
- requiresGPU(config: Config): boolean;
11
- }
1
+ import { type Context, BaseTask } from './BaseTask.js';
2
+ export interface Config {
3
+ input: string;
4
+ output: string;
5
+ enableMortonSort?: boolean;
6
+ compressLevel?: number;
7
+ spzVersion?: number;
8
+ }
9
+ export declare class WriteTask extends BaseTask<Config> {
10
+ exec(config: Config, { logger, resources }: Context): Promise<void>;
11
+ requiresGPU(config: Config): boolean;
12
+ }
@@ -1,70 +1,70 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { Writable } from 'node:stream';
4
- import { SplatData } from '../SplatData.js';
5
- import { createSplatFile, detectSplatFileType, SplatFileType } from '../utils/index.js';
6
- import { BaseTask } from './BaseTask.js';
7
- async function writeSplatFile(filepath, data, enableMortonSort, compressLevel) {
8
- let indices;
9
- if (!enableMortonSort) {
10
- indices = new Uint32Array(data.counts);
11
- for (let i = 0; i < data.counts; i++) {
12
- indices[i] = i;
13
- }
14
- }
15
- const file = createSplatFile(filepath, undefined, compressLevel);
16
- const stream = Writable.toWeb(fs.createWriteStream(filepath));
17
- await file.write(stream, data, indices);
18
- }
19
- export class WriteTask extends BaseTask {
20
- async exec(config, { logger, resources }) {
21
- const { input, output, enableMortonSort = true, compressLevel } = config;
22
- const source = resources.get(input);
23
- if (source instanceof SplatData) {
24
- logger.info(`writing splat -> file="${output}" count=${source.counts} SH=${source.shDegree}`);
25
- await writeSplatFile(output, source, enableMortonSort, compressLevel);
26
- logger.info(`writing done`);
27
- return;
28
- }
29
- if (fs.existsSync(output)) {
30
- fs.rmSync(output, { recursive: true });
31
- logger.info(`exist dir ${output}, removed`);
32
- }
33
- fs.mkdirSync(output);
34
- logger.info(`writing bundle -> dir="${output}" files=${source.length}`);
35
- logger.silent = true;
36
- const sogList = [];
37
- const promises = [];
38
- let idx = 1;
39
- const totals = source.length;
40
- for (let i = 0; i < source.length; i++) {
41
- const { name, content, preserveOrder = false } = source[i];
42
- const filepath = path.join(output, name);
43
- if (typeof content === 'string') {
44
- logger.info(`- ${filepath} (${idx++}/${totals})`, true);
45
- fs.writeFileSync(filepath, content);
46
- continue;
47
- }
48
- const type = detectSplatFileType(filepath);
49
- if (type === SplatFileType.SOG) {
50
- sogList.push({ name, content: content });
51
- continue;
52
- }
53
- logger.info(`- ${filepath} (${idx++}/${totals})`, true);
54
- const promise = writeSplatFile(filepath, content, enableMortonSort && !preserveOrder, compressLevel);
55
- promises.push(promise);
56
- }
57
- await Promise.all(promises);
58
- for (let i = 0; i < sogList.length; i++) {
59
- const { name, content } = sogList[i];
60
- const filepath = path.join(output, name);
61
- logger.info(`- ${filepath} (${idx++}/${totals})`, true);
62
- await writeSplatFile(filepath, content, false);
63
- }
64
- logger.silent = false;
65
- logger.info(`writing bundle done -> dir="${output}" files=${source.length}`);
66
- }
67
- requiresGPU(config) {
68
- return config.output.endsWith('sog');
69
- }
70
- }
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { Writable } from 'node:stream';
4
+ import { SplatData } from '../SplatData.js';
5
+ import { createSplatFile, detectSplatFileType, SplatFileType } from '../utils/index.js';
6
+ import { BaseTask } from './BaseTask.js';
7
+ async function writeSplatFile(filepath, data, enableMortonSort, compressLevel, spzVersion) {
8
+ let indices;
9
+ if (!enableMortonSort) {
10
+ indices = new Uint32Array(data.counts);
11
+ for (let i = 0; i < data.counts; i++) {
12
+ indices[i] = i;
13
+ }
14
+ }
15
+ const file = createSplatFile(filepath, undefined, compressLevel, spzVersion);
16
+ const stream = Writable.toWeb(fs.createWriteStream(filepath));
17
+ await file.write(stream, data, indices);
18
+ }
19
+ export class WriteTask extends BaseTask {
20
+ async exec(config, { logger, resources }) {
21
+ const { input, output, enableMortonSort = true, compressLevel, spzVersion } = config;
22
+ const source = resources.get(input);
23
+ if (source instanceof SplatData) {
24
+ logger.info(`writing splat -> file="${output}" count=${source.counts} SH=${source.shDegree}`);
25
+ await writeSplatFile(output, source, enableMortonSort, compressLevel, spzVersion);
26
+ logger.info(`writing done`);
27
+ return;
28
+ }
29
+ if (fs.existsSync(output)) {
30
+ fs.rmSync(output, { recursive: true });
31
+ logger.info(`exist dir ${output}, removed`);
32
+ }
33
+ fs.mkdirSync(output, { recursive: true });
34
+ logger.info(`writing bundle -> dir="${output}" files=${source.length}`);
35
+ logger.silent = true;
36
+ const sogList = [];
37
+ const promises = [];
38
+ let idx = 1;
39
+ const totals = source.length;
40
+ for (let i = 0; i < source.length; i++) {
41
+ const { name, content, preserveOrder = false } = source[i];
42
+ const filepath = path.join(output, name);
43
+ if (typeof content === 'string') {
44
+ logger.info(`- ${filepath} (${idx++}/${totals})`, true);
45
+ fs.writeFileSync(filepath, content);
46
+ continue;
47
+ }
48
+ const type = detectSplatFileType(filepath);
49
+ if (type === SplatFileType.SOG) {
50
+ sogList.push({ name, content: content });
51
+ continue;
52
+ }
53
+ logger.info(`- ${filepath} (${idx++}/${totals})`, true);
54
+ const promise = writeSplatFile(filepath, content, enableMortonSort && !preserveOrder, compressLevel, spzVersion);
55
+ promises.push(promise);
56
+ }
57
+ await Promise.all(promises);
58
+ for (let i = 0; i < sogList.length; i++) {
59
+ const { name, content } = sogList[i];
60
+ const filepath = path.join(output, name);
61
+ logger.info(`- ${filepath} (${idx++}/${totals})`, true);
62
+ await writeSplatFile(filepath, content, false);
63
+ }
64
+ logger.silent = false;
65
+ logger.info(`writing bundle done -> dir="${output}" files=${source.length}`);
66
+ }
67
+ requiresGPU(config) {
68
+ return config.output.endsWith('sog');
69
+ }
70
+ }