@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.
- package/CHANGELOG.md +124 -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 +38 -39
- package/dist/native/cpp/bin/linux/binding.node +0 -0
- package/dist/native/cpp/bin/windows/binding.node +0 -0
package/dist/utils/splat.js
CHANGED
|
@@ -1,387 +1,397 @@
|
|
|
1
|
-
import { unzipSync } from 'fflate';
|
|
2
|
-
import { PlyFile, SpzFile, KsplatFile, SplatFile, SogFile, LccFile, EszFile } from '../file/index.js';
|
|
3
|
-
import { SplatData } from '../SplatData.js';
|
|
4
|
-
import { SH_MAPS } from '../constant.js';
|
|
5
|
-
export var SplatFileType;
|
|
6
|
-
(function (SplatFileType) {
|
|
7
|
-
SplatFileType[SplatFileType["PLY"] = 0] = "PLY";
|
|
8
|
-
SplatFileType[SplatFileType["SPZ"] = 1] = "SPZ";
|
|
9
|
-
SplatFileType[SplatFileType["USPZ"] = 2] = "USPZ";
|
|
10
|
-
SplatFileType[SplatFileType["SPLAT"] = 3] = "SPLAT";
|
|
11
|
-
SplatFileType[SplatFileType["KSPLAT"] = 4] = "KSPLAT";
|
|
12
|
-
SplatFileType[SplatFileType["SOG"] = 5] = "SOG";
|
|
13
|
-
SplatFileType[SplatFileType["LCC"] = 6] = "LCC";
|
|
14
|
-
SplatFileType[SplatFileType["ESZ"] = 7] = "ESZ";
|
|
15
|
-
})(SplatFileType || (SplatFileType = {}));
|
|
16
|
-
export function detectSplatFileType(filename, buffer = new Uint8Array()) {
|
|
17
|
-
let ext = filename.split('.').pop();
|
|
18
|
-
if (ext === 'zip') {
|
|
19
|
-
unzipSync(buffer, {
|
|
20
|
-
filter: file => {
|
|
21
|
-
const { name } = file;
|
|
22
|
-
if (name.endsWith('meta.json')) {
|
|
23
|
-
ext = 'sog';
|
|
24
|
-
}
|
|
25
|
-
else if (name.endsWith('meta.lcc')) {
|
|
26
|
-
ext = 'lcc';
|
|
27
|
-
}
|
|
28
|
-
return false;
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
else if (ext === 'json') {
|
|
33
|
-
// fast check sog json
|
|
34
|
-
const json = JSON.parse(new TextDecoder().decode(buffer));
|
|
35
|
-
const isSogMetadata = ['means', 'scales', 'quats', 'sh0'].every(k => !!json[k]);
|
|
36
|
-
if (isSogMetadata) {
|
|
37
|
-
ext = 'sog';
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
let type;
|
|
41
|
-
switch (ext) {
|
|
42
|
-
case 'ply': {
|
|
43
|
-
type = SplatFileType.PLY;
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
case 'spz': {
|
|
47
|
-
type = SplatFileType.SPZ;
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
case 'uspz': {
|
|
51
|
-
type = SplatFileType.USPZ;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
case 'splat': {
|
|
55
|
-
type = SplatFileType.SPLAT;
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
case 'ksplat': {
|
|
59
|
-
type = SplatFileType.KSPLAT;
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
case 'sog': {
|
|
63
|
-
type = SplatFileType.SOG;
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
case 'lcc': {
|
|
67
|
-
type = SplatFileType.LCC;
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
case 'esz': {
|
|
71
|
-
type = SplatFileType.ESZ;
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
default: {
|
|
75
|
-
break;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return type;
|
|
79
|
-
}
|
|
80
|
-
export function createSplatFile(path, buffer = new Uint8Array(), compressLevel = 6, spzVersion = 3) {
|
|
81
|
-
const type = detectSplatFileType(path, buffer);
|
|
82
|
-
if (type === undefined) {
|
|
83
|
-
throw new Error(`Unsupported file format: ${path}`);
|
|
84
|
-
}
|
|
85
|
-
let file;
|
|
86
|
-
switch (type) {
|
|
87
|
-
case SplatFileType.PLY: {
|
|
88
|
-
file = new PlyFile();
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
case SplatFileType.SPZ: {
|
|
92
|
-
file = new SpzFile(compressLevel, spzVersion);
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
case SplatFileType.USPZ: {
|
|
96
|
-
file = new SpzFile(-1);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
case SplatFileType.KSPLAT: {
|
|
100
|
-
file = new KsplatFile();
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
case SplatFileType.SPLAT: {
|
|
104
|
-
file = new SplatFile();
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
case SplatFileType.SOG: {
|
|
108
|
-
file = new SogFile();
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
case SplatFileType.LCC: {
|
|
112
|
-
file = new LccFile();
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
case SplatFileType.ESZ: {
|
|
116
|
-
file = new EszFile();
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return file;
|
|
121
|
-
}
|
|
122
|
-
export function combineSplatData(source) {
|
|
123
|
-
const target = new SplatData().init(source.reduce((p, c) => p + c.counts, 0), Math.max(...source.map(v => v.shDegree)));
|
|
124
|
-
const single = {
|
|
125
|
-
x: 0,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
let
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
// sort
|
|
350
|
-
|
|
351
|
-
let
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
1
|
+
import { unzipSync } from 'fflate';
|
|
2
|
+
import { PlyFile, SpzFile, KsplatFile, SplatFile, SogFile, LccFile, EszFile } from '../file/index.js';
|
|
3
|
+
import { ColIdx, SplatData } from '../SplatData.js';
|
|
4
|
+
import { SH_MAPS } from '../constant.js';
|
|
5
|
+
export var SplatFileType;
|
|
6
|
+
(function (SplatFileType) {
|
|
7
|
+
SplatFileType[SplatFileType["PLY"] = 0] = "PLY";
|
|
8
|
+
SplatFileType[SplatFileType["SPZ"] = 1] = "SPZ";
|
|
9
|
+
SplatFileType[SplatFileType["USPZ"] = 2] = "USPZ";
|
|
10
|
+
SplatFileType[SplatFileType["SPLAT"] = 3] = "SPLAT";
|
|
11
|
+
SplatFileType[SplatFileType["KSPLAT"] = 4] = "KSPLAT";
|
|
12
|
+
SplatFileType[SplatFileType["SOG"] = 5] = "SOG";
|
|
13
|
+
SplatFileType[SplatFileType["LCC"] = 6] = "LCC";
|
|
14
|
+
SplatFileType[SplatFileType["ESZ"] = 7] = "ESZ";
|
|
15
|
+
})(SplatFileType || (SplatFileType = {}));
|
|
16
|
+
export function detectSplatFileType(filename, buffer = new Uint8Array()) {
|
|
17
|
+
let ext = filename.split('.').pop();
|
|
18
|
+
if (ext === 'zip') {
|
|
19
|
+
unzipSync(buffer, {
|
|
20
|
+
filter: file => {
|
|
21
|
+
const { name } = file;
|
|
22
|
+
if (name.endsWith('meta.json')) {
|
|
23
|
+
ext = 'sog';
|
|
24
|
+
}
|
|
25
|
+
else if (name.endsWith('meta.lcc')) {
|
|
26
|
+
ext = 'lcc';
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
else if (ext === 'json') {
|
|
33
|
+
// fast check sog json
|
|
34
|
+
const json = JSON.parse(new TextDecoder().decode(buffer));
|
|
35
|
+
const isSogMetadata = ['means', 'scales', 'quats', 'sh0'].every(k => !!json[k]);
|
|
36
|
+
if (isSogMetadata) {
|
|
37
|
+
ext = 'sog';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
let type;
|
|
41
|
+
switch (ext) {
|
|
42
|
+
case 'ply': {
|
|
43
|
+
type = SplatFileType.PLY;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
case 'spz': {
|
|
47
|
+
type = SplatFileType.SPZ;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case 'uspz': {
|
|
51
|
+
type = SplatFileType.USPZ;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case 'splat': {
|
|
55
|
+
type = SplatFileType.SPLAT;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case 'ksplat': {
|
|
59
|
+
type = SplatFileType.KSPLAT;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'sog': {
|
|
63
|
+
type = SplatFileType.SOG;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case 'lcc': {
|
|
67
|
+
type = SplatFileType.LCC;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case 'esz': {
|
|
71
|
+
type = SplatFileType.ESZ;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
default: {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return type;
|
|
79
|
+
}
|
|
80
|
+
export function createSplatFile(path, buffer = new Uint8Array(), compressLevel = 6, spzVersion = 3) {
|
|
81
|
+
const type = detectSplatFileType(path, buffer);
|
|
82
|
+
if (type === undefined) {
|
|
83
|
+
throw new Error(`Unsupported file format: ${path}`);
|
|
84
|
+
}
|
|
85
|
+
let file;
|
|
86
|
+
switch (type) {
|
|
87
|
+
case SplatFileType.PLY: {
|
|
88
|
+
file = new PlyFile();
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case SplatFileType.SPZ: {
|
|
92
|
+
file = new SpzFile(compressLevel, spzVersion);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case SplatFileType.USPZ: {
|
|
96
|
+
file = new SpzFile(-1);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
case SplatFileType.KSPLAT: {
|
|
100
|
+
file = new KsplatFile();
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case SplatFileType.SPLAT: {
|
|
104
|
+
file = new SplatFile();
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case SplatFileType.SOG: {
|
|
108
|
+
file = new SogFile();
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
case SplatFileType.LCC: {
|
|
112
|
+
file = new LccFile();
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case SplatFileType.ESZ: {
|
|
116
|
+
file = new EszFile();
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return file;
|
|
121
|
+
}
|
|
122
|
+
export function combineSplatData(source) {
|
|
123
|
+
const target = new SplatData().init(source.reduce((p, c) => p + c.counts, 0), Math.max(...source.map(v => v.shDegree)));
|
|
124
|
+
const single = {
|
|
125
|
+
x: 0,
|
|
126
|
+
y: 0,
|
|
127
|
+
z: 0,
|
|
128
|
+
sx: 0,
|
|
129
|
+
sy: 0,
|
|
130
|
+
sz: 0,
|
|
131
|
+
qx: 0,
|
|
132
|
+
qy: 0,
|
|
133
|
+
qz: 0,
|
|
134
|
+
qw: 0,
|
|
135
|
+
r: 0,
|
|
136
|
+
g: 0,
|
|
137
|
+
b: 0,
|
|
138
|
+
a: 0,
|
|
139
|
+
shN: new Array(SH_MAPS[target.shDegree]),
|
|
140
|
+
};
|
|
141
|
+
const shN = single.shN;
|
|
142
|
+
let index = 0;
|
|
143
|
+
for (let i = 0; i < source.length; i++) {
|
|
144
|
+
const splat = source[i];
|
|
145
|
+
const { counts } = splat;
|
|
146
|
+
for (let j = 0; j < counts; j++) {
|
|
147
|
+
splat.get(j, single);
|
|
148
|
+
splat.getShN(j, shN);
|
|
149
|
+
target.set(index, single);
|
|
150
|
+
target.setShN(index, shN);
|
|
151
|
+
index++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return target;
|
|
155
|
+
}
|
|
156
|
+
const VOXEL_COUNTS = 65535;
|
|
157
|
+
export function computeDenseBox(data, ratio = 0.98) {
|
|
158
|
+
if (data.counts === 0) {
|
|
159
|
+
return { min: [0, 0, 0], max: [0, 0, 0] };
|
|
160
|
+
}
|
|
161
|
+
const xCol = data.table[ColIdx.x];
|
|
162
|
+
const yCol = data.table[ColIdx.y];
|
|
163
|
+
const zCol = data.table[ColIdx.z];
|
|
164
|
+
let minX = Infinity;
|
|
165
|
+
let minY = Infinity;
|
|
166
|
+
let minZ = Infinity;
|
|
167
|
+
let maxX = -Infinity;
|
|
168
|
+
let maxY = -Infinity;
|
|
169
|
+
let maxZ = -Infinity;
|
|
170
|
+
for (let i = 0; i < data.counts; i++) {
|
|
171
|
+
const x = xCol[i];
|
|
172
|
+
const y = yCol[i];
|
|
173
|
+
const z = zCol[i];
|
|
174
|
+
if (x < minX) {
|
|
175
|
+
minX = x;
|
|
176
|
+
}
|
|
177
|
+
if (x > maxX) {
|
|
178
|
+
maxX = x;
|
|
179
|
+
}
|
|
180
|
+
if (y < minY) {
|
|
181
|
+
minY = y;
|
|
182
|
+
}
|
|
183
|
+
if (y > maxY) {
|
|
184
|
+
maxY = y;
|
|
185
|
+
}
|
|
186
|
+
if (z < minZ) {
|
|
187
|
+
minZ = z;
|
|
188
|
+
}
|
|
189
|
+
if (z > maxZ) {
|
|
190
|
+
maxZ = z;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const scaleX = VOXEL_COUNTS / Math.max(maxX - minX, 1e-9);
|
|
194
|
+
const scaleY = VOXEL_COUNTS / Math.max(maxY - minY, 1e-9);
|
|
195
|
+
const scaleZ = VOXEL_COUNTS / Math.max(maxZ - minZ, 1e-9);
|
|
196
|
+
const xChunks = new Uint32Array(VOXEL_COUNTS);
|
|
197
|
+
const yChunks = new Uint32Array(VOXEL_COUNTS);
|
|
198
|
+
const zChunks = new Uint32Array(VOXEL_COUNTS);
|
|
199
|
+
for (let i = 0; i < data.counts; i++) {
|
|
200
|
+
xChunks[((xCol[i] - minX) * scaleX) | 0]++;
|
|
201
|
+
yChunks[((yCol[i] - minY) * scaleY) | 0]++;
|
|
202
|
+
zChunks[((zCol[i] - minZ) * scaleZ) | 0]++;
|
|
203
|
+
}
|
|
204
|
+
const K = Math.ceil(data.counts * (1 - ratio));
|
|
205
|
+
let startX = 0;
|
|
206
|
+
let endX = VOXEL_COUNTS - 1;
|
|
207
|
+
let startY = 0;
|
|
208
|
+
let endY = VOXEL_COUNTS - 1;
|
|
209
|
+
let startZ = 0;
|
|
210
|
+
let endZ = VOXEL_COUNTS - 1;
|
|
211
|
+
let count = data.counts;
|
|
212
|
+
while (count > K) {
|
|
213
|
+
const xs = xChunks[startX];
|
|
214
|
+
const xe = xChunks[endX];
|
|
215
|
+
const ys = yChunks[startY];
|
|
216
|
+
const ye = yChunks[endY];
|
|
217
|
+
const zs = zChunks[startZ];
|
|
218
|
+
const ze = zChunks[endZ];
|
|
219
|
+
let min = xs;
|
|
220
|
+
let minKey = 'startX';
|
|
221
|
+
if (xe < min) {
|
|
222
|
+
min = xe;
|
|
223
|
+
minKey = 'endX';
|
|
224
|
+
}
|
|
225
|
+
if (ys < min) {
|
|
226
|
+
min = ys;
|
|
227
|
+
minKey = 'startY';
|
|
228
|
+
}
|
|
229
|
+
if (ye < min) {
|
|
230
|
+
min = ye;
|
|
231
|
+
minKey = 'endY';
|
|
232
|
+
}
|
|
233
|
+
if (zs < min) {
|
|
234
|
+
min = zs;
|
|
235
|
+
minKey = 'startZ';
|
|
236
|
+
}
|
|
237
|
+
if (ze < min) {
|
|
238
|
+
min = ze;
|
|
239
|
+
minKey = 'endZ';
|
|
240
|
+
}
|
|
241
|
+
switch (minKey) {
|
|
242
|
+
case 'startX':
|
|
243
|
+
startX++;
|
|
244
|
+
break;
|
|
245
|
+
case 'endX':
|
|
246
|
+
endX--;
|
|
247
|
+
break;
|
|
248
|
+
case 'startY':
|
|
249
|
+
startY++;
|
|
250
|
+
break;
|
|
251
|
+
case 'endY':
|
|
252
|
+
endY--;
|
|
253
|
+
break;
|
|
254
|
+
case 'startZ':
|
|
255
|
+
startZ++;
|
|
256
|
+
break;
|
|
257
|
+
case 'endZ':
|
|
258
|
+
endZ--;
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
count -= min;
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
min: [startX / scaleX + minX, startY / scaleY + minY, startZ / scaleZ + minZ],
|
|
265
|
+
max: [endX / scaleX + minX, endY / scaleY + minY, endZ / scaleZ + minZ],
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// https://github.com/playcanvas/splat-transform/blob/main/src/lib/data-table/data-table.ts
|
|
269
|
+
export function mortonSort(splat) {
|
|
270
|
+
const result = new Uint32Array(splat.counts);
|
|
271
|
+
const xCol = splat.table[ColIdx.x];
|
|
272
|
+
const yCol = splat.table[ColIdx.y];
|
|
273
|
+
const zCol = splat.table[ColIdx.z];
|
|
274
|
+
for (let i = 0; i < result.length; ++i) {
|
|
275
|
+
result[i] = i;
|
|
276
|
+
}
|
|
277
|
+
const generate = (indices) => {
|
|
278
|
+
if (indices.length === 0) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
|
|
282
|
+
const encodeMorton3 = (x, y, z) => {
|
|
283
|
+
const Part1By2 = (x) => {
|
|
284
|
+
x &= 0x000003ff;
|
|
285
|
+
x = (x ^ (x << 16)) & 0xff0000ff;
|
|
286
|
+
x = (x ^ (x << 8)) & 0x0300f00f;
|
|
287
|
+
x = (x ^ (x << 4)) & 0x030c30c3;
|
|
288
|
+
x = (x ^ (x << 2)) & 0x09249249;
|
|
289
|
+
return x;
|
|
290
|
+
};
|
|
291
|
+
return (Part1By2(z) << 2) + (Part1By2(y) << 1) + Part1By2(x);
|
|
292
|
+
};
|
|
293
|
+
let mx = Infinity;
|
|
294
|
+
let my = Infinity;
|
|
295
|
+
let mz = Infinity;
|
|
296
|
+
let Mx = -Infinity;
|
|
297
|
+
let My = -Infinity;
|
|
298
|
+
let Mz = -Infinity;
|
|
299
|
+
// calculate scene extents across all splats (using sort centers, because they're in world space)
|
|
300
|
+
for (let i = 0; i < indices.length; ++i) {
|
|
301
|
+
const ri = indices[i];
|
|
302
|
+
const x = xCol[ri];
|
|
303
|
+
const y = yCol[ri];
|
|
304
|
+
const z = zCol[ri];
|
|
305
|
+
if (x < mx) {
|
|
306
|
+
mx = x;
|
|
307
|
+
}
|
|
308
|
+
if (x > Mx) {
|
|
309
|
+
Mx = x;
|
|
310
|
+
}
|
|
311
|
+
if (y < my) {
|
|
312
|
+
my = y;
|
|
313
|
+
}
|
|
314
|
+
if (y > My) {
|
|
315
|
+
My = y;
|
|
316
|
+
}
|
|
317
|
+
if (z < mz) {
|
|
318
|
+
mz = z;
|
|
319
|
+
}
|
|
320
|
+
if (z > Mz) {
|
|
321
|
+
Mz = z;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
const xlen = Mx - mx;
|
|
325
|
+
const ylen = My - my;
|
|
326
|
+
const zlen = Mz - mz;
|
|
327
|
+
if (!isFinite(xlen) || !isFinite(ylen) || !isFinite(zlen)) {
|
|
328
|
+
console.debug('invalid extents', xlen, ylen, zlen);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
// all points are identical
|
|
332
|
+
if (xlen === 0 && ylen === 0 && zlen === 0) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const xmul = xlen === 0 ? 0 : 1024 / xlen;
|
|
336
|
+
const ymul = ylen === 0 ? 0 : 1024 / ylen;
|
|
337
|
+
const zmul = zlen === 0 ? 0 : 1024 / zlen;
|
|
338
|
+
const morton = new Uint32Array(indices.length);
|
|
339
|
+
for (let i = 0; i < indices.length; ++i) {
|
|
340
|
+
const ri = indices[i];
|
|
341
|
+
const x = xCol[ri];
|
|
342
|
+
const y = yCol[ri];
|
|
343
|
+
const z = zCol[ri];
|
|
344
|
+
const ix = Math.min(1023, (x - mx) * xmul) >>> 0;
|
|
345
|
+
const iy = Math.min(1023, (y - my) * ymul) >>> 0;
|
|
346
|
+
const iz = Math.min(1023, (z - mz) * zmul) >>> 0;
|
|
347
|
+
morton[i] = encodeMorton3(ix, iy, iz);
|
|
348
|
+
}
|
|
349
|
+
// sort indices by morton code
|
|
350
|
+
const order = new Uint32Array(indices.length);
|
|
351
|
+
for (let i = 0; i < order.length; i++) {
|
|
352
|
+
order[i] = i;
|
|
353
|
+
}
|
|
354
|
+
order.sort((a, b) => morton[a] - morton[b]);
|
|
355
|
+
const tmpIndices = indices.slice();
|
|
356
|
+
for (let i = 0; i < indices.length; ++i) {
|
|
357
|
+
indices[i] = tmpIndices[order[i]];
|
|
358
|
+
}
|
|
359
|
+
// sort the largest buckets recursively
|
|
360
|
+
let start = 0;
|
|
361
|
+
let end = 1;
|
|
362
|
+
while (start < indices.length) {
|
|
363
|
+
while (end < indices.length && morton[order[end]] === morton[order[start]]) {
|
|
364
|
+
++end;
|
|
365
|
+
}
|
|
366
|
+
if (end - start > 256) {
|
|
367
|
+
generate(indices.subarray(start, end));
|
|
368
|
+
}
|
|
369
|
+
start = end;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
generate(result);
|
|
373
|
+
return result;
|
|
374
|
+
}
|
|
375
|
+
export function fastDeleteSplat(splat, indices) {
|
|
376
|
+
const { counts, table } = splat;
|
|
377
|
+
const map = new Uint32Array(counts - indices.length);
|
|
378
|
+
let write = 0;
|
|
379
|
+
let removeIdx = 0;
|
|
380
|
+
for (let read = 0; read < counts; read++) {
|
|
381
|
+
if (removeIdx < indices.length && read === indices[removeIdx]) {
|
|
382
|
+
removeIdx++;
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
map[write++] = read;
|
|
386
|
+
}
|
|
387
|
+
for (let i = 0; i < table.length; i++) {
|
|
388
|
+
const col = table[i];
|
|
389
|
+
for (let j = 0; j < map.length; j++) {
|
|
390
|
+
col[j] = col[map[j]];
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
splat.counts -= indices.length;
|
|
394
|
+
for (let i = 0; i < table.length; i++) {
|
|
395
|
+
table[i] = table[i].subarray(0, splat.counts);
|
|
396
|
+
}
|
|
397
|
+
}
|