@manycore/aholo-splat-transform 1.2.8 → 1.2.10

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 (97) hide show
  1. package/CHANGELOG.md +124 -113
  2. package/README.md +39 -39
  3. package/THIRD_PARTY_LICENSES.txt +1373 -1373
  4. package/bin/cli.js +125 -118
  5. package/dist/SplatData.d.ts +67 -67
  6. package/dist/SplatData.js +167 -150
  7. package/dist/constant.d.ts +3 -3
  8. package/dist/constant.js +13 -13
  9. package/dist/file/IFile.d.ts +5 -5
  10. package/dist/file/IFile.js +1 -1
  11. package/dist/file/esz.d.ts +11 -11
  12. package/dist/file/esz.js +337 -322
  13. package/dist/file/index.d.ts +8 -8
  14. package/dist/file/index.js +7 -7
  15. package/dist/file/ksplat.d.ts +12 -12
  16. package/dist/file/ksplat.js +293 -231
  17. package/dist/file/lcc.d.ts +11 -11
  18. package/dist/file/lcc.js +161 -158
  19. package/dist/file/ply.d.ts +13 -13
  20. package/dist/file/ply.js +439 -390
  21. package/dist/file/sog.d.ts +80 -80
  22. package/dist/file/sog.js +525 -494
  23. package/dist/file/splat.d.ts +6 -6
  24. package/dist/file/splat.js +119 -99
  25. package/dist/file/spz.d.ts +11 -11
  26. package/dist/file/spz.js +597 -583
  27. package/dist/file/voxel.d.ts +43 -37
  28. package/dist/file/voxel.js +411 -280
  29. package/dist/index.d.ts +33 -33
  30. package/dist/index.js +54 -54
  31. package/dist/native/index.d.ts +54 -54
  32. package/dist/native/index.js +122 -129
  33. package/dist/native/utils.d.ts +1 -0
  34. package/dist/native/utils.js +54 -0
  35. package/dist/tasks/AutoChunkLodTask.d.ts +13 -13
  36. package/dist/tasks/AutoChunkLodTask.js +117 -117
  37. package/dist/tasks/AutoLodTask.d.ts +10 -10
  38. package/dist/tasks/AutoLodTask.js +20 -20
  39. package/dist/tasks/BaseTask.d.ts +15 -15
  40. package/dist/tasks/BaseTask.js +5 -5
  41. package/dist/tasks/FlexLodTask.d.ts +12 -12
  42. package/dist/tasks/FlexLodTask.js +54 -44
  43. package/dist/tasks/ModifyTask.d.ts +9 -9
  44. package/dist/tasks/ModifyTask.js +166 -156
  45. package/dist/tasks/ReadTask.d.ts +9 -9
  46. package/dist/tasks/ReadTask.js +29 -29
  47. package/dist/tasks/SkeletonLodTask.d.ts +10 -10
  48. package/dist/tasks/SkeletonLodTask.js +176 -156
  49. package/dist/tasks/VoxelTask.d.ts +35 -30
  50. package/dist/tasks/VoxelTask.js +40 -37
  51. package/dist/tasks/WriteTask.d.ts +12 -12
  52. package/dist/tasks/WriteTask.js +70 -70
  53. package/dist/utils/BufferReader.d.ts +12 -12
  54. package/dist/utils/BufferReader.js +45 -45
  55. package/dist/utils/Logger.d.ts +11 -11
  56. package/dist/utils/Logger.js +40 -40
  57. package/dist/utils/StreamChunkDecoder.d.ts +16 -16
  58. package/dist/utils/StreamChunkDecoder.js +31 -31
  59. package/dist/utils/index.d.ts +27 -27
  60. package/dist/utils/index.js +101 -101
  61. package/dist/utils/k-means.d.ts +4 -4
  62. package/dist/utils/k-means.js +340 -341
  63. package/dist/utils/math.d.ts +46 -46
  64. package/dist/utils/math.js +350 -346
  65. package/dist/utils/quantize-1d.d.ts +4 -4
  66. package/dist/utils/quantize-1d.js +164 -164
  67. package/dist/utils/sh-rotate.d.ts +2 -2
  68. package/dist/utils/sh-rotate.js +236 -175
  69. package/dist/utils/splat.d.ts +21 -21
  70. package/dist/utils/splat.js +397 -387
  71. package/dist/utils/voxel/binary.d.ts +8 -0
  72. package/dist/utils/voxel/binary.js +176 -0
  73. package/dist/utils/voxel/common.d.ts +178 -162
  74. package/dist/utils/voxel/common.js +1752 -1682
  75. package/dist/utils/voxel/coplanar-merge.d.ts +63 -63
  76. package/dist/utils/voxel/coplanar-merge.js +818 -819
  77. package/dist/utils/voxel/filter-cluster.d.ts +20 -0
  78. package/dist/utils/voxel/filter-cluster.js +628 -0
  79. package/dist/utils/voxel/gpu-dilation.d.ts +2 -2
  80. package/dist/utils/voxel/gpu-dilation.js +677 -656
  81. package/dist/utils/voxel/marching-cubes.d.ts +42 -42
  82. package/dist/utils/voxel/marching-cubes.js +1645 -1657
  83. package/dist/utils/voxel/mesh.d.ts +3 -3
  84. package/dist/utils/voxel/mesh.js +130 -130
  85. package/dist/utils/voxel/nav.d.ts +29 -29
  86. package/dist/utils/voxel/nav.js +1068 -1043
  87. package/dist/utils/voxel/postprocess.d.ts +23 -23
  88. package/dist/utils/voxel/postprocess.js +408 -375
  89. package/dist/utils/voxel/voxel-faces.d.ts +18 -18
  90. package/dist/utils/voxel/voxel-faces.js +662 -663
  91. package/dist/utils/voxel/voxelize.d.ts +34 -33
  92. package/dist/utils/voxel/voxelize.js +1208 -1193
  93. package/dist/utils/webgpu.d.ts +8 -8
  94. package/dist/utils/webgpu.js +122 -122
  95. package/package.json +38 -39
  96. package/dist/native/cpp/bin/linux/binding.node +0 -0
  97. 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,12 +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
- 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
+ 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, 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
- }
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
+ }