@manycore/aholo-splat-transform 1.2.8 → 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 -113
- package/README.md +39 -39
- package/THIRD_PARTY_LICENSES.txt +1373 -1373
- package/bin/cli.js +125 -118
- package/dist/SplatData.d.ts +67 -67
- package/dist/SplatData.js +167 -150
- 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 -11
- package/dist/file/esz.js +337 -322
- package/dist/file/index.d.ts +8 -8
- package/dist/file/index.js +7 -7
- package/dist/file/ksplat.d.ts +12 -12
- package/dist/file/ksplat.js +293 -231
- package/dist/file/lcc.d.ts +11 -11
- package/dist/file/lcc.js +161 -158
- package/dist/file/ply.d.ts +13 -13
- package/dist/file/ply.js +439 -390
- package/dist/file/sog.d.ts +80 -80
- package/dist/file/sog.js +525 -494
- package/dist/file/splat.d.ts +6 -6
- package/dist/file/splat.js +119 -99
- package/dist/file/spz.d.ts +11 -11
- package/dist/file/spz.js +597 -583
- 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 -129
- 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 -12
- package/dist/tasks/WriteTask.js +70 -70
- package/dist/utils/BufferReader.d.ts +12 -12
- package/dist/utils/BufferReader.js +45 -45
- package/dist/utils/Logger.d.ts +11 -11
- package/dist/utils/Logger.js +40 -40
- package/dist/utils/StreamChunkDecoder.d.ts +16 -16
- package/dist/utils/StreamChunkDecoder.js +31 -31
- 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 -341
- package/dist/utils/math.d.ts +46 -46
- package/dist/utils/math.js +350 -346
- 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 -21
- package/dist/utils/splat.js +397 -387
- 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 -1682
- 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 -656
- 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 -39
- package/dist/native/cpp/bin/linux/binding.node +0 -0
- package/dist/native/cpp/bin/windows/binding.node +0 -0
|
@@ -1,117 +1,117 @@
|
|
|
1
|
-
import { combineSplatData, computeDenseBox } from '../utils/index.js';
|
|
2
|
-
import { BaseTask } from './BaseTask.js';
|
|
3
|
-
import { generateLod } from '../native/index.js';
|
|
4
|
-
const DefaultLevels = [
|
|
5
|
-
{ precision: 1.0, scaleBoost: 1 },
|
|
6
|
-
{ precision: 0.5, scaleBoost: 1 },
|
|
7
|
-
{ precision: 0.25, scaleBoost: 1 },
|
|
8
|
-
{ precision: 0.05, scaleBoost: 1.01 },
|
|
9
|
-
{ precision: 0.01, scaleBoost: 1.02 },
|
|
10
|
-
];
|
|
11
|
-
export class AutoChunkLodTask extends BaseTask {
|
|
12
|
-
async exec(config, { logger, resources }) {
|
|
13
|
-
const { input, output, type, maxChunkCounts = 400000, levels = DefaultLevels } = config;
|
|
14
|
-
const splat = resources.get(input);
|
|
15
|
-
logger.info(`loaded -> "${input}"`);
|
|
16
|
-
const forwardBox = computeDenseBox(splat, 0.8);
|
|
17
|
-
const outputs = [];
|
|
18
|
-
const outputBlocks = [];
|
|
19
|
-
const permanentFiles = [];
|
|
20
|
-
{
|
|
21
|
-
logger.info('generate lod');
|
|
22
|
-
logger.time('generate elapsed');
|
|
23
|
-
const { blocks, splats } = generateLod(splat, levels, Math.min(1, maxChunkCounts / splat.counts), 2000, 20);
|
|
24
|
-
logger.timeEnd('generate elapsed');
|
|
25
|
-
const chunkL3Idx = [];
|
|
26
|
-
const chunkL4Idx = [];
|
|
27
|
-
for (let i = 0; i < blocks.length; i++) {
|
|
28
|
-
const block = blocks[i];
|
|
29
|
-
chunkL4Idx.push(block.refs[4]);
|
|
30
|
-
if (block.refs[3] !== block.refs[4]) {
|
|
31
|
-
chunkL3Idx.push(block.refs[3]);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
const layout = new Map();
|
|
35
|
-
{
|
|
36
|
-
const chunkL4 = combineSplatData(chunkL4Idx.map(idx => splats[idx]));
|
|
37
|
-
outputs.push({ name: `chunk_0.${type}`, content: chunkL4, preserveOrder: true });
|
|
38
|
-
permanentFiles.push(0);
|
|
39
|
-
let offset = 0;
|
|
40
|
-
for (let i = 0; i < chunkL4Idx.length; i++) {
|
|
41
|
-
const idx = chunkL4Idx[i];
|
|
42
|
-
const counts = splats[idx].counts;
|
|
43
|
-
layout.set(idx, { idx: 0, offset, counts });
|
|
44
|
-
offset += counts;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (chunkL3Idx.length > 0) {
|
|
48
|
-
const chunkL3 = combineSplatData(chunkL3Idx.map(idx => splats[idx]));
|
|
49
|
-
outputs.push({ name: `chunk_1.${type}`, content: chunkL3, preserveOrder: true });
|
|
50
|
-
permanentFiles.push(1);
|
|
51
|
-
let offset = 0;
|
|
52
|
-
for (let i = 0; i < chunkL3Idx.length; i++) {
|
|
53
|
-
const idx = chunkL3Idx[i];
|
|
54
|
-
const counts = splats[idx].counts;
|
|
55
|
-
layout.set(idx, { idx: 1, offset, counts });
|
|
56
|
-
offset += counts;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
for (let i = 0; i < splats.length; i++) {
|
|
60
|
-
if (chunkL3Idx.includes(i) || chunkL4Idx.includes(i)) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
const idx = outputs.length;
|
|
64
|
-
const splat = splats[i];
|
|
65
|
-
outputs.push({
|
|
66
|
-
name: `chunk_${idx}.${type}`,
|
|
67
|
-
content: splat,
|
|
68
|
-
});
|
|
69
|
-
layout.set(i, { idx, offset: 0, counts: splat.counts });
|
|
70
|
-
}
|
|
71
|
-
for (const block of blocks) {
|
|
72
|
-
outputBlocks.push({
|
|
73
|
-
bound: block.box,
|
|
74
|
-
lods: block.refs.map(ref => {
|
|
75
|
-
const v = layout.get(ref);
|
|
76
|
-
return {
|
|
77
|
-
file: v.idx,
|
|
78
|
-
offset: v.offset,
|
|
79
|
-
count: v.counts,
|
|
80
|
-
};
|
|
81
|
-
})
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
logger.info(`Total blocks: ${outputBlocks.length}, files: ${outputs.length}`);
|
|
86
|
-
logger.info(`Gaussian per level: `);
|
|
87
|
-
let maxLength = 0;
|
|
88
|
-
for (let i = 0; i < levels.length; i++) {
|
|
89
|
-
const level = levels[i];
|
|
90
|
-
const levelCount = outputBlocks.map(block => block.lods[i].count).reduce((acc, i) => acc + i, 0);
|
|
91
|
-
const levelStr = levelCount.toString().padStart(maxLength, ' ');
|
|
92
|
-
maxLength = levelStr.length;
|
|
93
|
-
logger.info(`\tLevel ${i}${`(${(level.precision * 100).toFixed(2)}%)`.padStart(9, ' ')}: ${levelStr}${`(${(levelCount / splat.counts * 100).toFixed(2)}%)`.padStart(9, ' ')}`);
|
|
94
|
-
}
|
|
95
|
-
resources.set(output, [
|
|
96
|
-
{
|
|
97
|
-
name: 'lod-meta.json',
|
|
98
|
-
content: JSON.stringify({
|
|
99
|
-
magicCode: 0x262834,
|
|
100
|
-
type: 'lod-splat',
|
|
101
|
-
version: '1.0',
|
|
102
|
-
counts: splat.counts,
|
|
103
|
-
shDegree: splat.shDegree,
|
|
104
|
-
levels: levels.length,
|
|
105
|
-
forwardBox,
|
|
106
|
-
files: outputs.map(f => f.name),
|
|
107
|
-
permanentFiles,
|
|
108
|
-
tree: outputBlocks,
|
|
109
|
-
}),
|
|
110
|
-
},
|
|
111
|
-
...outputs,
|
|
112
|
-
]);
|
|
113
|
-
}
|
|
114
|
-
requiresGPU(config) {
|
|
115
|
-
return config.type === 'sog';
|
|
116
|
-
}
|
|
117
|
-
}
|
|
1
|
+
import { combineSplatData, computeDenseBox } from '../utils/index.js';
|
|
2
|
+
import { BaseTask } from './BaseTask.js';
|
|
3
|
+
import { generateLod } from '../native/index.js';
|
|
4
|
+
const DefaultLevels = [
|
|
5
|
+
{ precision: 1.0, scaleBoost: 1 },
|
|
6
|
+
{ precision: 0.5, scaleBoost: 1 },
|
|
7
|
+
{ precision: 0.25, scaleBoost: 1 },
|
|
8
|
+
{ precision: 0.05, scaleBoost: 1.01 },
|
|
9
|
+
{ precision: 0.01, scaleBoost: 1.02 },
|
|
10
|
+
];
|
|
11
|
+
export class AutoChunkLodTask extends BaseTask {
|
|
12
|
+
async exec(config, { logger, resources }) {
|
|
13
|
+
const { input, output, type, maxChunkCounts = 400000, levels = DefaultLevels } = config;
|
|
14
|
+
const splat = resources.get(input);
|
|
15
|
+
logger.info(`loaded -> "${input}"`);
|
|
16
|
+
const forwardBox = computeDenseBox(splat, 0.8);
|
|
17
|
+
const outputs = [];
|
|
18
|
+
const outputBlocks = [];
|
|
19
|
+
const permanentFiles = [];
|
|
20
|
+
{
|
|
21
|
+
logger.info('generate lod');
|
|
22
|
+
logger.time('generate elapsed');
|
|
23
|
+
const { blocks, splats } = generateLod(splat, levels, Math.min(1, maxChunkCounts / splat.counts), 2000, 20);
|
|
24
|
+
logger.timeEnd('generate elapsed');
|
|
25
|
+
const chunkL3Idx = [];
|
|
26
|
+
const chunkL4Idx = [];
|
|
27
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
28
|
+
const block = blocks[i];
|
|
29
|
+
chunkL4Idx.push(block.refs[4]);
|
|
30
|
+
if (block.refs[3] !== block.refs[4]) {
|
|
31
|
+
chunkL3Idx.push(block.refs[3]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const layout = new Map();
|
|
35
|
+
{
|
|
36
|
+
const chunkL4 = combineSplatData(chunkL4Idx.map(idx => splats[idx]));
|
|
37
|
+
outputs.push({ name: `chunk_0.${type}`, content: chunkL4, preserveOrder: true });
|
|
38
|
+
permanentFiles.push(0);
|
|
39
|
+
let offset = 0;
|
|
40
|
+
for (let i = 0; i < chunkL4Idx.length; i++) {
|
|
41
|
+
const idx = chunkL4Idx[i];
|
|
42
|
+
const counts = splats[idx].counts;
|
|
43
|
+
layout.set(idx, { idx: 0, offset, counts });
|
|
44
|
+
offset += counts;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (chunkL3Idx.length > 0) {
|
|
48
|
+
const chunkL3 = combineSplatData(chunkL3Idx.map(idx => splats[idx]));
|
|
49
|
+
outputs.push({ name: `chunk_1.${type}`, content: chunkL3, preserveOrder: true });
|
|
50
|
+
permanentFiles.push(1);
|
|
51
|
+
let offset = 0;
|
|
52
|
+
for (let i = 0; i < chunkL3Idx.length; i++) {
|
|
53
|
+
const idx = chunkL3Idx[i];
|
|
54
|
+
const counts = splats[idx].counts;
|
|
55
|
+
layout.set(idx, { idx: 1, offset, counts });
|
|
56
|
+
offset += counts;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
for (let i = 0; i < splats.length; i++) {
|
|
60
|
+
if (chunkL3Idx.includes(i) || chunkL4Idx.includes(i)) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const idx = outputs.length;
|
|
64
|
+
const splat = splats[i];
|
|
65
|
+
outputs.push({
|
|
66
|
+
name: `chunk_${idx}.${type}`,
|
|
67
|
+
content: splat,
|
|
68
|
+
});
|
|
69
|
+
layout.set(i, { idx, offset: 0, counts: splat.counts });
|
|
70
|
+
}
|
|
71
|
+
for (const block of blocks) {
|
|
72
|
+
outputBlocks.push({
|
|
73
|
+
bound: block.box,
|
|
74
|
+
lods: block.refs.map(ref => {
|
|
75
|
+
const v = layout.get(ref);
|
|
76
|
+
return {
|
|
77
|
+
file: v.idx,
|
|
78
|
+
offset: v.offset,
|
|
79
|
+
count: v.counts,
|
|
80
|
+
};
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
logger.info(`Total blocks: ${outputBlocks.length}, files: ${outputs.length}`);
|
|
86
|
+
logger.info(`Gaussian per level: `);
|
|
87
|
+
let maxLength = 0;
|
|
88
|
+
for (let i = 0; i < levels.length; i++) {
|
|
89
|
+
const level = levels[i];
|
|
90
|
+
const levelCount = outputBlocks.map(block => block.lods[i].count).reduce((acc, i) => acc + i, 0);
|
|
91
|
+
const levelStr = levelCount.toString().padStart(maxLength, ' ');
|
|
92
|
+
maxLength = levelStr.length;
|
|
93
|
+
logger.info(`\tLevel ${i}${`(${(level.precision * 100).toFixed(2)}%)`.padStart(9, ' ')}: ${levelStr}${`(${((levelCount / splat.counts) * 100).toFixed(2)}%)`.padStart(9, ' ')}`);
|
|
94
|
+
}
|
|
95
|
+
resources.set(output, [
|
|
96
|
+
{
|
|
97
|
+
name: 'lod-meta.json',
|
|
98
|
+
content: JSON.stringify({
|
|
99
|
+
magicCode: 0x262834,
|
|
100
|
+
type: 'lod-splat',
|
|
101
|
+
version: '1.0',
|
|
102
|
+
counts: splat.counts,
|
|
103
|
+
shDegree: splat.shDegree,
|
|
104
|
+
levels: levels.length,
|
|
105
|
+
forwardBox,
|
|
106
|
+
files: outputs.map(f => f.name),
|
|
107
|
+
permanentFiles,
|
|
108
|
+
tree: outputBlocks,
|
|
109
|
+
}),
|
|
110
|
+
},
|
|
111
|
+
...outputs,
|
|
112
|
+
]);
|
|
113
|
+
}
|
|
114
|
+
requiresGPU(config) {
|
|
115
|
+
return config.type === 'sog';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Context, BaseTask } from './BaseTask.js';
|
|
2
|
-
export interface Config {
|
|
3
|
-
input: string;
|
|
4
|
-
output: string;
|
|
5
|
-
counts?: number;
|
|
6
|
-
ratio?: number;
|
|
7
|
-
}
|
|
8
|
-
export declare class AutoLodTask extends BaseTask<Config> {
|
|
9
|
-
exec(config: Config, { logger, resources }: Context): Promise<void>;
|
|
10
|
-
}
|
|
1
|
+
import { type Context, BaseTask } from './BaseTask.js';
|
|
2
|
+
export interface Config {
|
|
3
|
+
input: string;
|
|
4
|
+
output: string;
|
|
5
|
+
counts?: number;
|
|
6
|
+
ratio?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class AutoLodTask extends BaseTask<Config> {
|
|
9
|
+
exec(config: Config, { logger, resources }: Context): Promise<void>;
|
|
10
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { combineSplatData } from '../utils/index.js';
|
|
2
|
-
import { generateLod } from '../native/index.js';
|
|
3
|
-
import { BaseTask } from './BaseTask.js';
|
|
4
|
-
export class AutoLodTask extends BaseTask {
|
|
5
|
-
async exec(config, { logger, resources }) {
|
|
6
|
-
const { input, output, counts = Infinity, ratio = 0.3 } = config;
|
|
7
|
-
const splat = resources.get(input);
|
|
8
|
-
logger.info(`loaded -> "${input}"`);
|
|
9
|
-
const target = Math.min(Math.ceil(splat.counts * ratio), counts);
|
|
10
|
-
logger.info(`expected -> ${target}(${((target / splat.counts) * 100).toFixed(2)}%) | ratio=${ratio} counts=${counts}`);
|
|
11
|
-
const { blocks, splats } = generateLod(splat, [
|
|
12
|
-
{ precision: 1.0, scaleBoost: 1.0 },
|
|
13
|
-
{ precision: target / splat.counts, scaleBoost: 1.0 },
|
|
14
|
-
], 0.2, 2000, 20);
|
|
15
|
-
const raw = combineSplatData(blocks.map(item => splats[item.refs[1]]));
|
|
16
|
-
logger.info(`result -> ${raw.counts}(${(raw.counts / target * 100).toFixed(2)}%)`);
|
|
17
|
-
resources.set(output, raw);
|
|
18
|
-
logger.info(`stored -> key="${output}"`);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
1
|
+
import { combineSplatData } from '../utils/index.js';
|
|
2
|
+
import { generateLod } from '../native/index.js';
|
|
3
|
+
import { BaseTask } from './BaseTask.js';
|
|
4
|
+
export class AutoLodTask extends BaseTask {
|
|
5
|
+
async exec(config, { logger, resources }) {
|
|
6
|
+
const { input, output, counts = Infinity, ratio = 0.3 } = config;
|
|
7
|
+
const splat = resources.get(input);
|
|
8
|
+
logger.info(`loaded -> "${input}"`);
|
|
9
|
+
const target = Math.min(Math.ceil(splat.counts * ratio), counts);
|
|
10
|
+
logger.info(`expected -> ${target}(${((target / splat.counts) * 100).toFixed(2)}%) | ratio=${ratio} counts=${counts}`);
|
|
11
|
+
const { blocks, splats } = generateLod(splat, [
|
|
12
|
+
{ precision: 1.0, scaleBoost: 1.0 },
|
|
13
|
+
{ precision: target / splat.counts, scaleBoost: 1.0 },
|
|
14
|
+
], 0.2, 2000, 20);
|
|
15
|
+
const raw = combineSplatData(blocks.map(item => splats[item.refs[1]]));
|
|
16
|
+
logger.info(`result -> ${raw.counts}(${((raw.counts / target) * 100).toFixed(2)}%)`);
|
|
17
|
+
resources.set(output, raw);
|
|
18
|
+
logger.info(`stored -> key="${output}"`);
|
|
19
|
+
}
|
|
20
|
+
}
|
package/dist/tasks/BaseTask.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { SplatData } from '../SplatData.js';
|
|
2
|
-
import { Logger } from '../utils/Logger.js';
|
|
3
|
-
export interface SingleFile {
|
|
4
|
-
name: string;
|
|
5
|
-
content: SplatData | string;
|
|
6
|
-
preserveOrder?: boolean;
|
|
7
|
-
}
|
|
8
|
-
export interface Context {
|
|
9
|
-
logger: Logger;
|
|
10
|
-
resources: Map<string, SplatData | SingleFile[]>;
|
|
11
|
-
}
|
|
12
|
-
export declare abstract class BaseTask<T> {
|
|
13
|
-
abstract exec(config: T, ctx: Context): Promise<void>;
|
|
14
|
-
requiresGPU(_config: T): boolean;
|
|
15
|
-
}
|
|
1
|
+
import type { SplatData } from '../SplatData.js';
|
|
2
|
+
import type { Logger } from '../utils/Logger.js';
|
|
3
|
+
export interface SingleFile {
|
|
4
|
+
name: string;
|
|
5
|
+
content: SplatData | string;
|
|
6
|
+
preserveOrder?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface Context {
|
|
9
|
+
logger: Logger;
|
|
10
|
+
resources: Map<string, SplatData | SingleFile[]>;
|
|
11
|
+
}
|
|
12
|
+
export declare abstract class BaseTask<T> {
|
|
13
|
+
abstract exec(config: T, ctx: Context): Promise<void>;
|
|
14
|
+
requiresGPU(_config: T): boolean;
|
|
15
|
+
}
|
package/dist/tasks/BaseTask.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export class BaseTask {
|
|
2
|
-
requiresGPU(_config) {
|
|
3
|
-
return false;
|
|
4
|
-
}
|
|
5
|
-
}
|
|
1
|
+
export class BaseTask {
|
|
2
|
+
requiresGPU(_config) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Context, BaseTask } from './BaseTask.js';
|
|
2
|
-
export interface Config {
|
|
3
|
-
input: string;
|
|
4
|
-
output: string;
|
|
5
|
-
scorePath: string;
|
|
6
|
-
counts?: number;
|
|
7
|
-
ratio?: number;
|
|
8
|
-
originalIndices?: string;
|
|
9
|
-
}
|
|
10
|
-
export declare class FlexLodTask extends BaseTask<Config> {
|
|
11
|
-
exec(config: Config, { logger, resources }: Context): Promise<void>;
|
|
12
|
-
}
|
|
1
|
+
import { type Context, BaseTask } from './BaseTask.js';
|
|
2
|
+
export interface Config {
|
|
3
|
+
input: string;
|
|
4
|
+
output: string;
|
|
5
|
+
scorePath: string;
|
|
6
|
+
counts?: number;
|
|
7
|
+
ratio?: number;
|
|
8
|
+
originalIndices?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class FlexLodTask extends BaseTask<Config> {
|
|
11
|
+
exec(config: Config, { logger, resources }: Context): Promise<void>;
|
|
12
|
+
}
|
|
@@ -1,44 +1,54 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import { SplatData } from '../SplatData.js';
|
|
3
|
-
import { BaseTask } from './BaseTask.js';
|
|
4
|
-
export class FlexLodTask extends BaseTask {
|
|
5
|
-
async exec(config, { logger, resources }) {
|
|
6
|
-
const { input, output, scorePath, counts = Infinity, ratio = 0.3, originalIndices } = config;
|
|
7
|
-
const splat = resources.get(input);
|
|
8
|
-
logger.info(`loaded -> "${input}"`);
|
|
9
|
-
const target = Math.min(counts, Math.ceil(splat.counts * ratio));
|
|
10
|
-
logger.info(`expected -> ${target}(${((target / splat.counts) * 100).toFixed(2)}%) | ratio=${ratio} counts=${counts}`);
|
|
11
|
-
const scores = new Float32Array(fs.readFileSync(scorePath).buffer);
|
|
12
|
-
let sorted = new Uint32Array(splat.counts);
|
|
13
|
-
for (let i = 0; i < sorted.length; i++) {
|
|
14
|
-
sorted[i] = i;
|
|
15
|
-
}
|
|
16
|
-
sorted.sort((a, b) => scores[b] - scores[a]);
|
|
17
|
-
sorted = sorted.subarray(0, target).sort((a, b) => a - b);
|
|
18
|
-
const raw = new SplatData().init(target, splat.shDegree);
|
|
19
|
-
const single = {
|
|
20
|
-
x: 0,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { SplatData } from '../SplatData.js';
|
|
3
|
+
import { BaseTask } from './BaseTask.js';
|
|
4
|
+
export class FlexLodTask extends BaseTask {
|
|
5
|
+
async exec(config, { logger, resources }) {
|
|
6
|
+
const { input, output, scorePath, counts = Infinity, ratio = 0.3, originalIndices } = config;
|
|
7
|
+
const splat = resources.get(input);
|
|
8
|
+
logger.info(`loaded -> "${input}"`);
|
|
9
|
+
const target = Math.min(counts, Math.ceil(splat.counts * ratio));
|
|
10
|
+
logger.info(`expected -> ${target}(${((target / splat.counts) * 100).toFixed(2)}%) | ratio=${ratio} counts=${counts}`);
|
|
11
|
+
const scores = new Float32Array(fs.readFileSync(scorePath).buffer);
|
|
12
|
+
let sorted = new Uint32Array(splat.counts);
|
|
13
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
14
|
+
sorted[i] = i;
|
|
15
|
+
}
|
|
16
|
+
sorted.sort((a, b) => scores[b] - scores[a]);
|
|
17
|
+
sorted = sorted.subarray(0, target).sort((a, b) => a - b);
|
|
18
|
+
const raw = new SplatData().init(target, splat.shDegree);
|
|
19
|
+
const single = {
|
|
20
|
+
x: 0,
|
|
21
|
+
y: 0,
|
|
22
|
+
z: 0,
|
|
23
|
+
sx: 0,
|
|
24
|
+
sy: 0,
|
|
25
|
+
sz: 0,
|
|
26
|
+
qx: 0,
|
|
27
|
+
qy: 0,
|
|
28
|
+
qz: 0,
|
|
29
|
+
qw: 0,
|
|
30
|
+
r: 0,
|
|
31
|
+
g: 0,
|
|
32
|
+
b: 0,
|
|
33
|
+
a: 0,
|
|
34
|
+
shN: new Array(splat.shCounts),
|
|
35
|
+
};
|
|
36
|
+
const shN = single.shN;
|
|
37
|
+
for (let i = 0; i < target; i++) {
|
|
38
|
+
splat.get(sorted[i], single);
|
|
39
|
+
splat.getShN(sorted[i], shN);
|
|
40
|
+
raw.set(i, single);
|
|
41
|
+
raw.setShN(i, shN);
|
|
42
|
+
}
|
|
43
|
+
if (originalIndices) {
|
|
44
|
+
const originIndices = new Uint32Array(target);
|
|
45
|
+
for (let i = 0; i < target; i++) {
|
|
46
|
+
originIndices[i] = sorted[i];
|
|
47
|
+
}
|
|
48
|
+
fs.writeFileSync(originalIndices, originIndices);
|
|
49
|
+
logger.info(`original indices saved -> "${originalIndices}"`);
|
|
50
|
+
}
|
|
51
|
+
resources.set(output, raw);
|
|
52
|
+
logger.info(`stored -> key="${output}"`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Context, BaseTask } from './BaseTask.js';
|
|
2
|
-
export interface Config {
|
|
3
|
-
input: string;
|
|
4
|
-
output: string;
|
|
5
|
-
modifyPaths?: string[];
|
|
6
|
-
}
|
|
7
|
-
export declare class ModifyTask extends BaseTask<Config> {
|
|
8
|
-
exec(config: Config, { logger, resources }: Context): Promise<void>;
|
|
9
|
-
}
|
|
1
|
+
import { type Context, BaseTask } from './BaseTask.js';
|
|
2
|
+
export interface Config {
|
|
3
|
+
input: string;
|
|
4
|
+
output: string;
|
|
5
|
+
modifyPaths?: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare class ModifyTask extends BaseTask<Config> {
|
|
8
|
+
exec(config: Config, { logger, resources }: Context): Promise<void>;
|
|
9
|
+
}
|