@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.
- package/CHANGELOG.md +120 -106
- package/COPYRIGHT.md +17 -0
- package/README.md +39 -39
- package/THIRD_PARTY_LICENSES.txt +1373 -0
- package/bin/cli.js +125 -118
- package/dist/SplatData.d.ts +67 -67
- package/dist/SplatData.js +167 -156
- package/dist/constant.d.ts +3 -3
- package/dist/constant.js +13 -13
- package/dist/file/IFile.d.ts +5 -5
- package/dist/file/IFile.js +1 -1
- package/dist/file/esz.d.ts +11 -0
- package/dist/file/esz.js +337 -0
- package/dist/file/index.d.ts +8 -7
- package/dist/file/index.js +7 -6
- package/dist/file/ksplat.d.ts +12 -12
- package/dist/file/ksplat.js +293 -232
- package/dist/file/lcc.d.ts +11 -11
- package/dist/file/lcc.js +161 -157
- package/dist/file/ply.d.ts +13 -13
- package/dist/file/ply.js +439 -388
- package/dist/file/sog.d.ts +80 -80
- package/dist/file/sog.js +525 -504
- package/dist/file/splat.d.ts +6 -6
- package/dist/file/splat.js +119 -99
- package/dist/file/spz.d.ts +11 -8
- package/dist/file/spz.js +597 -400
- package/dist/file/voxel.d.ts +43 -37
- package/dist/file/voxel.js +411 -280
- package/dist/index.d.ts +33 -33
- package/dist/index.js +54 -54
- package/dist/native/index.d.ts +54 -54
- package/dist/native/index.js +122 -128
- package/dist/native/utils.d.ts +1 -0
- package/dist/native/utils.js +54 -0
- package/dist/tasks/AutoChunkLodTask.d.ts +13 -13
- package/dist/tasks/AutoChunkLodTask.js +117 -117
- package/dist/tasks/AutoLodTask.d.ts +10 -10
- package/dist/tasks/AutoLodTask.js +20 -20
- package/dist/tasks/BaseTask.d.ts +15 -15
- package/dist/tasks/BaseTask.js +5 -5
- package/dist/tasks/FlexLodTask.d.ts +12 -12
- package/dist/tasks/FlexLodTask.js +54 -44
- package/dist/tasks/ModifyTask.d.ts +9 -9
- package/dist/tasks/ModifyTask.js +166 -156
- package/dist/tasks/ReadTask.d.ts +9 -9
- package/dist/tasks/ReadTask.js +29 -29
- package/dist/tasks/SkeletonLodTask.d.ts +10 -10
- package/dist/tasks/SkeletonLodTask.js +176 -156
- package/dist/tasks/VoxelTask.d.ts +35 -30
- package/dist/tasks/VoxelTask.js +40 -37
- package/dist/tasks/WriteTask.d.ts +12 -11
- package/dist/tasks/WriteTask.js +70 -70
- package/dist/utils/BufferReader.d.ts +12 -12
- package/dist/utils/BufferReader.js +45 -47
- package/dist/utils/Logger.d.ts +11 -11
- package/dist/utils/Logger.js +40 -38
- package/dist/utils/StreamChunkDecoder.d.ts +16 -16
- package/dist/utils/StreamChunkDecoder.js +31 -36
- package/dist/utils/index.d.ts +27 -27
- package/dist/utils/index.js +101 -101
- package/dist/utils/k-means.d.ts +4 -4
- package/dist/utils/k-means.js +340 -350
- package/dist/utils/math.d.ts +46 -46
- package/dist/utils/math.js +350 -351
- package/dist/utils/quantize-1d.d.ts +4 -4
- package/dist/utils/quantize-1d.js +164 -164
- package/dist/utils/sh-rotate.d.ts +2 -2
- package/dist/utils/sh-rotate.js +236 -175
- package/dist/utils/splat.d.ts +21 -20
- package/dist/utils/splat.js +397 -378
- package/dist/utils/voxel/binary.d.ts +8 -0
- package/dist/utils/voxel/binary.js +176 -0
- package/dist/utils/voxel/common.d.ts +178 -162
- package/dist/utils/voxel/common.js +1752 -1700
- package/dist/utils/voxel/coplanar-merge.d.ts +63 -63
- package/dist/utils/voxel/coplanar-merge.js +818 -819
- package/dist/utils/voxel/filter-cluster.d.ts +20 -0
- package/dist/utils/voxel/filter-cluster.js +628 -0
- package/dist/utils/voxel/gpu-dilation.d.ts +2 -2
- package/dist/utils/voxel/gpu-dilation.js +677 -665
- package/dist/utils/voxel/marching-cubes.d.ts +42 -42
- package/dist/utils/voxel/marching-cubes.js +1645 -1657
- package/dist/utils/voxel/mesh.d.ts +3 -3
- package/dist/utils/voxel/mesh.js +130 -130
- package/dist/utils/voxel/nav.d.ts +29 -29
- package/dist/utils/voxel/nav.js +1068 -1043
- package/dist/utils/voxel/postprocess.d.ts +23 -23
- package/dist/utils/voxel/postprocess.js +408 -375
- package/dist/utils/voxel/voxel-faces.d.ts +18 -18
- package/dist/utils/voxel/voxel-faces.js +662 -663
- package/dist/utils/voxel/voxelize.d.ts +34 -33
- package/dist/utils/voxel/voxelize.js +1208 -1193
- package/dist/utils/webgpu.d.ts +8 -8
- package/dist/utils/webgpu.js +122 -122
- package/package.json +37 -30
- package/dist/native/cpp/bin/linux/binding.node +0 -0
- 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[
|
|
13
|
-
const yCol = splat.table[
|
|
14
|
-
const zCol = splat.table[
|
|
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(
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
r: 0,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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 {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
+
}
|
package/dist/tasks/VoxelTask.js
CHANGED
|
@@ -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
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
if (
|
|
25
|
-
options.
|
|
26
|
-
}
|
|
27
|
-
if (
|
|
28
|
-
options.
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
+
}
|
package/dist/tasks/WriteTask.js
CHANGED
|
@@ -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
|
+
}
|