@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.
Files changed (97) hide show
  1. package/CHANGELOG.md +120 -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 +37 -39
  96. package/dist/native/cpp/bin/linux/binding.node +0 -0
  97. package/dist/native/cpp/bin/windows/binding.node +0 -0
@@ -1,8 +1,8 @@
1
- export { IFile } from './IFile.js';
2
- export { KsplatFile } from './ksplat.js';
3
- export { PlyFile } from './ply.js';
4
- export { SogFile } from './sog.js';
5
- export { SplatFile } from './splat.js';
6
- export { SpzFile } from './spz.js';
7
- export { LccFile } from './lcc.js';
8
- export { EszFile } from './esz.js';
1
+ export type { IFile } from './IFile.js';
2
+ export { KsplatFile } from './ksplat.js';
3
+ export { PlyFile } from './ply.js';
4
+ export { SogFile } from './sog.js';
5
+ export { SplatFile } from './splat.js';
6
+ export { SpzFile } from './spz.js';
7
+ export { LccFile } from './lcc.js';
8
+ export { EszFile } from './esz.js';
@@ -1,7 +1,7 @@
1
- export { KsplatFile } from './ksplat.js';
2
- export { PlyFile } from './ply.js';
3
- export { SogFile } from './sog.js';
4
- export { SplatFile } from './splat.js';
5
- export { SpzFile } from './spz.js';
6
- export { LccFile } from './lcc.js';
7
- export { EszFile } from './esz.js';
1
+ export { KsplatFile } from './ksplat.js';
2
+ export { PlyFile } from './ply.js';
3
+ export { SogFile } from './sog.js';
4
+ export { SplatFile } from './splat.js';
5
+ export { SpzFile } from './spz.js';
6
+ export { LccFile } from './lcc.js';
7
+ export { EszFile } from './esz.js';
@@ -1,12 +1,12 @@
1
- import { SplatData } from '../SplatData.js';
2
- import { IFile } from './IFile.js';
3
- export declare class KsplatFile implements IFile {
4
- private counts;
5
- private shDegree;
6
- private header;
7
- private sections;
8
- private buffer;
9
- private load;
10
- read(stream: ReadableStream<Uint8Array>, contentLength: number, data: SplatData): Promise<void>;
11
- write(_stream: WritableStream<Uint8Array>, _data: SplatData): Promise<void>;
12
- }
1
+ import type { SplatData } from '../SplatData.js';
2
+ import type { IFile } from './IFile.js';
3
+ export declare class KsplatFile implements IFile {
4
+ private counts;
5
+ private shDegree;
6
+ private header;
7
+ private sections;
8
+ private buffer;
9
+ private load;
10
+ read(stream: ReadableStream<Uint8Array>, contentLength: number, data: SplatData): Promise<void>;
11
+ write(_stream: WritableStream<Uint8Array>, _data: SplatData): Promise<void>;
12
+ }
@@ -1,231 +1,293 @@
1
- import { SH_MAPS } from '../constant.js';
2
- import { fromHalf } from '../utils/index.js';
3
- const KSPLAT_COMPRESSION = {
4
- 0: {
5
- bytesPerCenter: 12,
6
- bytesPerScale: 12,
7
- bytesPerRotation: 16,
8
- bytesPerColor: 4,
9
- bytesPerSphericalHarmonicsComponent: 4,
10
- scaleOffsetBytes: 12,
11
- rotationOffsetBytes: 24,
12
- colorOffsetBytes: 40,
13
- sphericalHarmonicsOffsetBytes: 44,
14
- scaleRange: 1,
15
- },
16
- 1: {
17
- bytesPerCenter: 6,
18
- bytesPerScale: 6,
19
- bytesPerRotation: 8,
20
- bytesPerColor: 4,
21
- bytesPerSphericalHarmonicsComponent: 2,
22
- scaleOffsetBytes: 6,
23
- rotationOffsetBytes: 12,
24
- colorOffsetBytes: 20,
25
- sphericalHarmonicsOffsetBytes: 24,
26
- scaleRange: 32767,
27
- },
28
- 2: {
29
- bytesPerCenter: 6,
30
- bytesPerScale: 6,
31
- bytesPerRotation: 8,
32
- bytesPerColor: 4,
33
- bytesPerSphericalHarmonicsComponent: 1,
34
- scaleOffsetBytes: 6,
35
- rotationOffsetBytes: 12,
36
- colorOffsetBytes: 20,
37
- sphericalHarmonicsOffsetBytes: 24,
38
- scaleRange: 32767,
39
- },
40
- };
41
- const SHIndex = [
42
- 0, 3, 6, 1, 4, 7, 2, 5, 8, // sh1
43
- 9, 14, 19, 10, 15, 20, 11, 16, 21, 12, 17, 22, 13, 18, 23, // sh2
44
- 24, 31, 38, 25, 32, 39, 26, 33, 40, 27, 34, 41, 28, 35, 42, 29, 36, 43, 30, 37, 44, // sh3
45
- ];
46
- const HEADER_BYTES = 4096;
47
- const SECTION_BYTES = 1024;
48
- export class KsplatFile {
49
- constructor() {
50
- this.counts = 0;
51
- this.shDegree = 0;
52
- }
53
- load(buffer) {
54
- this.buffer = buffer;
55
- const header = new DataView(buffer.buffer, 0, HEADER_BYTES);
56
- const versionMajor = header.getUint8(0);
57
- const versionMinor = header.getUint8(1);
58
- if (versionMajor !== 0 || versionMinor < 1) {
59
- throw new Error(`Unsupported .ksplat version: ${versionMajor}.${versionMinor}`);
60
- }
61
- const maxSectionCount = header.getUint32(4, true);
62
- const sectionCount = header.getUint32(8, true);
63
- const maxSplatCount = header.getUint32(12, true);
64
- const splatCount = header.getUint32(16, true);
65
- const compressionLevel = header.getUint16(20, true);
66
- if (compressionLevel < 0 || compressionLevel > 2) {
67
- throw new Error(`Invalid .ksplat compression level: ${compressionLevel}`);
68
- }
69
- const sceneCenterX = header.getFloat32(24, true);
70
- const sceneCenterY = header.getFloat32(28, true);
71
- const sceneCenterZ = header.getFloat32(32, true);
72
- const minSH = header.getFloat32(36, true) || -1.5;
73
- const maxSH = header.getFloat32(40, true) || 1.5;
74
- let maxSHDegree = 0;
75
- const sections = [];
76
- for (let i = 0; i < maxSectionCount; i++) {
77
- const section = new DataView(buffer.buffer, HEADER_BYTES + i * SECTION_BYTES, SECTION_BYTES);
78
- const sectionSplatCount = section.getUint32(0, true);
79
- const sectionMaxSplatCount = section.getUint32(4, true);
80
- const bucketSize = section.getUint32(8, true);
81
- const bucketCount = section.getUint32(12, true);
82
- const bucketBlockSize = section.getFloat32(16, true);
83
- const bucketStorageSizeBytes = section.getUint16(20, true);
84
- const compressionScaleRange = section.getUint32(24, true);
85
- const fullBucketCount = section.getUint32(32, true);
86
- const partiallyFilledBucketCount = section.getUint32(36, true);
87
- const shDegree = section.getUint16(40, true);
88
- maxSHDegree = Math.max(maxSHDegree, shDegree);
89
- sections.push({
90
- sectionSplatCount,
91
- sectionMaxSplatCount,
92
- bucketSize,
93
- bucketCount,
94
- bucketBlockSize,
95
- bucketStorageSizeBytes,
96
- compressionScaleRange: compressionScaleRange || KSPLAT_COMPRESSION[compressionLevel].scaleRange,
97
- fullBucketCount,
98
- partiallyFilledBucketCount,
99
- shDegree,
100
- });
101
- }
102
- this.header = {
103
- versionMajor,
104
- versionMinor,
105
- maxSectionCount,
106
- sectionCount,
107
- maxSplatCount,
108
- splatCount,
109
- compressionLevel,
110
- sceneCenter: [sceneCenterX, sceneCenterY, sceneCenterZ],
111
- shRange: [minSH, maxSH],
112
- };
113
- this.sections = sections;
114
- this.counts = splatCount;
115
- this.shDegree = maxSHDegree;
116
- }
117
- async read(stream, contentLength, data) {
118
- let BlockOffset = 0;
119
- {
120
- const buffer = new Uint8Array(contentLength);
121
- const reader = stream.getReader();
122
- let offset = 0;
123
- while (true) {
124
- const { done, value } = await reader.read();
125
- if (done) {
126
- break;
127
- }
128
- buffer.set(value, offset);
129
- offset += value.length;
130
- }
131
- this.load(buffer);
132
- BlockOffset = await data.initBlock(this.counts, this.shDegree);
133
- }
134
- const setFn = data.set.bind(data);
135
- const setShFn = data.setShN.bind(data);
136
- const { buffer, header, sections, shDegree: maxSHDegree } = this;
137
- const { maxSectionCount, compressionLevel, shRange: [minSH, maxSH] } = header;
138
- const isHighQualitySplatData = compressionLevel === 0;
139
- const single = {
140
- x: 0, y: 0, z: 0,
141
- sx: 0, sy: 0, sz: 0,
142
- qx: 0, qy: 0, qz: 0, qw: 0,
143
- r: 0, g: 0, b: 0, a: 0,
144
- shN: [],
145
- };
146
- const maxSHSize = SH_MAPS[maxSHDegree];
147
- const shData = new Array(maxSHSize);
148
- let sectionBase = HEADER_BYTES + maxSectionCount * SECTION_BYTES;
149
- for (let i = 0; i < maxSectionCount; i++) {
150
- const { sectionSplatCount, sectionMaxSplatCount, bucketSize, bucketCount, bucketBlockSize, bucketStorageSizeBytes, fullBucketCount, partiallyFilledBucketCount, compressionScaleRange, shDegree, } = sections[i];
151
- const fullBucketSplats = fullBucketCount * bucketSize;
152
- const bucketsMetaDataSizeBytes = partiallyFilledBucketCount * 4;
153
- const bucketsStorageSizeBytes = bucketStorageSizeBytes * bucketCount + bucketsMetaDataSizeBytes;
154
- const shComponents = SH_MAPS[shDegree];
155
- const { bytesPerCenter, bytesPerScale, bytesPerRotation, bytesPerColor, bytesPerSphericalHarmonicsComponent, scaleOffsetBytes, rotationOffsetBytes, colorOffsetBytes, sphericalHarmonicsOffsetBytes, } = KSPLAT_COMPRESSION[compressionLevel];
156
- const bytesPerSplat = bytesPerCenter + bytesPerScale + bytesPerRotation + bytesPerColor +
157
- shComponents * bytesPerSphericalHarmonicsComponent;
158
- const splatDataStorageSizeBytes = bytesPerSplat * sectionMaxSplatCount;
159
- const storageSizeBytes = splatDataStorageSizeBytes + bucketsStorageSizeBytes;
160
- const compressionScaleFactor = bucketBlockSize / 2 / compressionScaleRange;
161
- const bucketsBase = sectionBase + bucketsMetaDataSizeBytes;
162
- const dataBase = sectionBase + bucketsStorageSizeBytes;
163
- const data = new DataView(buffer.buffer, dataBase, splatDataStorageSizeBytes);
164
- const bucketArray = new Float32Array(buffer.buffer, bucketsBase, bucketCount * 3);
165
- const partiallyFilledBucketLengths = new Uint32Array(buffer.buffer, sectionBase, partiallyFilledBucketCount);
166
- let partialBucketIndex = fullBucketCount;
167
- let partialBucketBase = fullBucketSplats;
168
- for (let j = 0; j < sectionSplatCount; j++) {
169
- const splatOffset = j * bytesPerSplat;
170
- let bucketIndex;
171
- if (j < fullBucketSplats) {
172
- bucketIndex = Math.floor(j / bucketSize);
173
- }
174
- else {
175
- const bucketLength = partiallyFilledBucketLengths[partialBucketIndex - fullBucketCount];
176
- if (j >= partialBucketBase + bucketLength) {
177
- partialBucketIndex += 1;
178
- partialBucketBase += bucketLength;
179
- }
180
- bucketIndex = partialBucketIndex;
181
- }
182
- if (isHighQualitySplatData) {
183
- single.x = data.getFloat32(splatOffset + 0, true);
184
- single.y = data.getFloat32(splatOffset + 4, true);
185
- single.z = data.getFloat32(splatOffset + 8, true);
186
- single.sx = data.getFloat32(splatOffset + scaleOffsetBytes + 0, true);
187
- single.sy = data.getFloat32(splatOffset + scaleOffsetBytes + 4, true);
188
- single.sz = data.getFloat32(splatOffset + scaleOffsetBytes + 8, true);
189
- single.qw = data.getFloat32(splatOffset + rotationOffsetBytes + 0, true);
190
- single.qx = data.getFloat32(splatOffset + rotationOffsetBytes + 4, true);
191
- single.qy = data.getFloat32(splatOffset + rotationOffsetBytes + 8, true);
192
- single.qz = data.getFloat32(splatOffset + rotationOffsetBytes + 12, true);
193
- }
194
- else {
195
- single.x = (data.getUint16(splatOffset + 0, true) - compressionScaleRange) * compressionScaleFactor + bucketArray[3 * bucketIndex + 0];
196
- single.y = (data.getUint16(splatOffset + 2, true) - compressionScaleRange) * compressionScaleFactor + bucketArray[3 * bucketIndex + 1];
197
- single.z = (data.getUint16(splatOffset + 4, true) - compressionScaleRange) * compressionScaleFactor + bucketArray[3 * bucketIndex + 2];
198
- single.sx = fromHalf(data.getUint16(splatOffset + scaleOffsetBytes + 0, true));
199
- single.sy = fromHalf(data.getUint16(splatOffset + scaleOffsetBytes + 2, true));
200
- single.sz = fromHalf(data.getUint16(splatOffset + scaleOffsetBytes + 4, true));
201
- single.qw = fromHalf(data.getUint16(splatOffset + rotationOffsetBytes + 0, true));
202
- single.qx = fromHalf(data.getUint16(splatOffset + rotationOffsetBytes + 2, true));
203
- single.qy = fromHalf(data.getUint16(splatOffset + rotationOffsetBytes + 4, true));
204
- single.qz = fromHalf(data.getUint16(splatOffset + rotationOffsetBytes + 6, true));
205
- }
206
- single.r = data.getUint8(splatOffset + colorOffsetBytes + 0) / 255;
207
- single.g = data.getUint8(splatOffset + colorOffsetBytes + 1) / 255;
208
- single.b = data.getUint8(splatOffset + colorOffsetBytes + 2) / 255;
209
- single.a = data.getUint8(splatOffset + colorOffsetBytes + 3) / 255;
210
- setFn(j + BlockOffset, single);
211
- const shOffsetBytes = splatOffset + sphericalHarmonicsOffsetBytes;
212
- for (let k = 0; k < shComponents; k++) {
213
- shData[k] = compressionLevel === 0 ?
214
- data.getFloat32(shOffsetBytes + SHIndex[k] * 4, true) :
215
- compressionLevel === 1 ?
216
- fromHalf(data.getUint16(shOffsetBytes + SHIndex[k] * 2, true)) :
217
- (minSH + data.getUint8(shOffsetBytes + SHIndex[k]) / 255 * (maxSH - minSH));
218
- }
219
- for (let k = maxSHSize - 1; k >= shComponents; k--) {
220
- shData[k] = 0;
221
- }
222
- setShFn(j + BlockOffset, shData);
223
- }
224
- sectionBase += storageSizeBytes;
225
- }
226
- data.finishBlock();
227
- }
228
- async write(_stream, _data) {
229
- throw new Error('Method not implemented.');
230
- }
231
- }
1
+ import { SH_MAPS } from '../constant.js';
2
+ import { fromHalf } from '../utils/index.js';
3
+ const KSPLAT_COMPRESSION = {
4
+ 0: {
5
+ bytesPerCenter: 12,
6
+ bytesPerScale: 12,
7
+ bytesPerRotation: 16,
8
+ bytesPerColor: 4,
9
+ bytesPerSphericalHarmonicsComponent: 4,
10
+ scaleOffsetBytes: 12,
11
+ rotationOffsetBytes: 24,
12
+ colorOffsetBytes: 40,
13
+ sphericalHarmonicsOffsetBytes: 44,
14
+ scaleRange: 1,
15
+ },
16
+ 1: {
17
+ bytesPerCenter: 6,
18
+ bytesPerScale: 6,
19
+ bytesPerRotation: 8,
20
+ bytesPerColor: 4,
21
+ bytesPerSphericalHarmonicsComponent: 2,
22
+ scaleOffsetBytes: 6,
23
+ rotationOffsetBytes: 12,
24
+ colorOffsetBytes: 20,
25
+ sphericalHarmonicsOffsetBytes: 24,
26
+ scaleRange: 32767,
27
+ },
28
+ 2: {
29
+ bytesPerCenter: 6,
30
+ bytesPerScale: 6,
31
+ bytesPerRotation: 8,
32
+ bytesPerColor: 4,
33
+ bytesPerSphericalHarmonicsComponent: 1,
34
+ scaleOffsetBytes: 6,
35
+ rotationOffsetBytes: 12,
36
+ colorOffsetBytes: 20,
37
+ sphericalHarmonicsOffsetBytes: 24,
38
+ scaleRange: 32767,
39
+ },
40
+ };
41
+ const SHIndex = [
42
+ 0,
43
+ 3,
44
+ 6,
45
+ 1,
46
+ 4,
47
+ 7,
48
+ 2,
49
+ 5,
50
+ 8, // sh1
51
+ 9,
52
+ 14,
53
+ 19,
54
+ 10,
55
+ 15,
56
+ 20,
57
+ 11,
58
+ 16,
59
+ 21,
60
+ 12,
61
+ 17,
62
+ 22,
63
+ 13,
64
+ 18,
65
+ 23, // sh2
66
+ 24,
67
+ 31,
68
+ 38,
69
+ 25,
70
+ 32,
71
+ 39,
72
+ 26,
73
+ 33,
74
+ 40,
75
+ 27,
76
+ 34,
77
+ 41,
78
+ 28,
79
+ 35,
80
+ 42,
81
+ 29,
82
+ 36,
83
+ 43,
84
+ 30,
85
+ 37,
86
+ 44, // sh3
87
+ ];
88
+ const HEADER_BYTES = 4096;
89
+ const SECTION_BYTES = 1024;
90
+ export class KsplatFile {
91
+ constructor() {
92
+ this.counts = 0;
93
+ this.shDegree = 0;
94
+ }
95
+ load(buffer) {
96
+ this.buffer = buffer;
97
+ const header = new DataView(buffer.buffer, 0, HEADER_BYTES);
98
+ const versionMajor = header.getUint8(0);
99
+ const versionMinor = header.getUint8(1);
100
+ if (versionMajor !== 0 || versionMinor < 1) {
101
+ throw new Error(`Unsupported .ksplat version: ${versionMajor}.${versionMinor}`);
102
+ }
103
+ const maxSectionCount = header.getUint32(4, true);
104
+ const sectionCount = header.getUint32(8, true);
105
+ const maxSplatCount = header.getUint32(12, true);
106
+ const splatCount = header.getUint32(16, true);
107
+ const compressionLevel = header.getUint16(20, true);
108
+ if (compressionLevel < 0 || compressionLevel > 2) {
109
+ throw new Error(`Invalid .ksplat compression level: ${compressionLevel}`);
110
+ }
111
+ const sceneCenterX = header.getFloat32(24, true);
112
+ const sceneCenterY = header.getFloat32(28, true);
113
+ const sceneCenterZ = header.getFloat32(32, true);
114
+ const minSH = header.getFloat32(36, true) || -1.5;
115
+ const maxSH = header.getFloat32(40, true) || 1.5;
116
+ let maxSHDegree = 0;
117
+ const sections = [];
118
+ for (let i = 0; i < maxSectionCount; i++) {
119
+ const section = new DataView(buffer.buffer, HEADER_BYTES + i * SECTION_BYTES, SECTION_BYTES);
120
+ const sectionSplatCount = section.getUint32(0, true);
121
+ const sectionMaxSplatCount = section.getUint32(4, true);
122
+ const bucketSize = section.getUint32(8, true);
123
+ const bucketCount = section.getUint32(12, true);
124
+ const bucketBlockSize = section.getFloat32(16, true);
125
+ const bucketStorageSizeBytes = section.getUint16(20, true);
126
+ const compressionScaleRange = section.getUint32(24, true);
127
+ const fullBucketCount = section.getUint32(32, true);
128
+ const partiallyFilledBucketCount = section.getUint32(36, true);
129
+ const shDegree = section.getUint16(40, true);
130
+ maxSHDegree = Math.max(maxSHDegree, shDegree);
131
+ sections.push({
132
+ sectionSplatCount,
133
+ sectionMaxSplatCount,
134
+ bucketSize,
135
+ bucketCount,
136
+ bucketBlockSize,
137
+ bucketStorageSizeBytes,
138
+ compressionScaleRange: compressionScaleRange || KSPLAT_COMPRESSION[compressionLevel].scaleRange,
139
+ fullBucketCount,
140
+ partiallyFilledBucketCount,
141
+ shDegree,
142
+ });
143
+ }
144
+ this.header = {
145
+ versionMajor,
146
+ versionMinor,
147
+ maxSectionCount,
148
+ sectionCount,
149
+ maxSplatCount,
150
+ splatCount,
151
+ compressionLevel,
152
+ sceneCenter: [sceneCenterX, sceneCenterY, sceneCenterZ],
153
+ shRange: [minSH, maxSH],
154
+ };
155
+ this.sections = sections;
156
+ this.counts = splatCount;
157
+ this.shDegree = maxSHDegree;
158
+ }
159
+ async read(stream, contentLength, data) {
160
+ let BlockOffset = 0;
161
+ {
162
+ const buffer = new Uint8Array(contentLength);
163
+ const reader = stream.getReader();
164
+ let offset = 0;
165
+ while (true) {
166
+ const { done, value } = await reader.read();
167
+ if (done) {
168
+ break;
169
+ }
170
+ buffer.set(value, offset);
171
+ offset += value.length;
172
+ }
173
+ this.load(buffer);
174
+ BlockOffset = await data.initBlock(this.counts, this.shDegree);
175
+ }
176
+ const setFn = data.set.bind(data);
177
+ const setShFn = data.setShN.bind(data);
178
+ const { buffer, header, sections, shDegree: maxSHDegree } = this;
179
+ const { maxSectionCount, compressionLevel, shRange: [minSH, maxSH], } = header;
180
+ const isHighQualitySplatData = compressionLevel === 0;
181
+ const single = {
182
+ x: 0,
183
+ y: 0,
184
+ z: 0,
185
+ sx: 0,
186
+ sy: 0,
187
+ sz: 0,
188
+ qx: 0,
189
+ qy: 0,
190
+ qz: 0,
191
+ qw: 0,
192
+ r: 0,
193
+ g: 0,
194
+ b: 0,
195
+ a: 0,
196
+ shN: [],
197
+ };
198
+ const maxSHSize = SH_MAPS[maxSHDegree];
199
+ const shData = new Array(maxSHSize);
200
+ let sectionBase = HEADER_BYTES + maxSectionCount * SECTION_BYTES;
201
+ for (let i = 0; i < maxSectionCount; i++) {
202
+ const { sectionSplatCount, sectionMaxSplatCount, bucketSize, bucketCount, bucketBlockSize, bucketStorageSizeBytes, fullBucketCount, partiallyFilledBucketCount, compressionScaleRange, shDegree, } = sections[i];
203
+ const fullBucketSplats = fullBucketCount * bucketSize;
204
+ const bucketsMetaDataSizeBytes = partiallyFilledBucketCount * 4;
205
+ const bucketsStorageSizeBytes = bucketStorageSizeBytes * bucketCount + bucketsMetaDataSizeBytes;
206
+ const shComponents = SH_MAPS[shDegree];
207
+ const { bytesPerCenter, bytesPerScale, bytesPerRotation, bytesPerColor, bytesPerSphericalHarmonicsComponent, scaleOffsetBytes, rotationOffsetBytes, colorOffsetBytes, sphericalHarmonicsOffsetBytes, } = KSPLAT_COMPRESSION[compressionLevel];
208
+ const bytesPerSplat = bytesPerCenter +
209
+ bytesPerScale +
210
+ bytesPerRotation +
211
+ bytesPerColor +
212
+ shComponents * bytesPerSphericalHarmonicsComponent;
213
+ const splatDataStorageSizeBytes = bytesPerSplat * sectionMaxSplatCount;
214
+ const storageSizeBytes = splatDataStorageSizeBytes + bucketsStorageSizeBytes;
215
+ const compressionScaleFactor = bucketBlockSize / 2 / compressionScaleRange;
216
+ const bucketsBase = sectionBase + bucketsMetaDataSizeBytes;
217
+ const dataBase = sectionBase + bucketsStorageSizeBytes;
218
+ const data = new DataView(buffer.buffer, dataBase, splatDataStorageSizeBytes);
219
+ const bucketArray = new Float32Array(buffer.buffer, bucketsBase, bucketCount * 3);
220
+ const partiallyFilledBucketLengths = new Uint32Array(buffer.buffer, sectionBase, partiallyFilledBucketCount);
221
+ let partialBucketIndex = fullBucketCount;
222
+ let partialBucketBase = fullBucketSplats;
223
+ for (let j = 0; j < sectionSplatCount; j++) {
224
+ const splatOffset = j * bytesPerSplat;
225
+ let bucketIndex;
226
+ if (j < fullBucketSplats) {
227
+ bucketIndex = Math.floor(j / bucketSize);
228
+ }
229
+ else {
230
+ const bucketLength = partiallyFilledBucketLengths[partialBucketIndex - fullBucketCount];
231
+ if (j >= partialBucketBase + bucketLength) {
232
+ partialBucketIndex += 1;
233
+ partialBucketBase += bucketLength;
234
+ }
235
+ bucketIndex = partialBucketIndex;
236
+ }
237
+ if (isHighQualitySplatData) {
238
+ single.x = data.getFloat32(splatOffset + 0, true);
239
+ single.y = data.getFloat32(splatOffset + 4, true);
240
+ single.z = data.getFloat32(splatOffset + 8, true);
241
+ single.sx = data.getFloat32(splatOffset + scaleOffsetBytes + 0, true);
242
+ single.sy = data.getFloat32(splatOffset + scaleOffsetBytes + 4, true);
243
+ single.sz = data.getFloat32(splatOffset + scaleOffsetBytes + 8, true);
244
+ single.qw = data.getFloat32(splatOffset + rotationOffsetBytes + 0, true);
245
+ single.qx = data.getFloat32(splatOffset + rotationOffsetBytes + 4, true);
246
+ single.qy = data.getFloat32(splatOffset + rotationOffsetBytes + 8, true);
247
+ single.qz = data.getFloat32(splatOffset + rotationOffsetBytes + 12, true);
248
+ }
249
+ else {
250
+ single.x =
251
+ (data.getUint16(splatOffset + 0, true) - compressionScaleRange) * compressionScaleFactor +
252
+ bucketArray[3 * bucketIndex + 0];
253
+ single.y =
254
+ (data.getUint16(splatOffset + 2, true) - compressionScaleRange) * compressionScaleFactor +
255
+ bucketArray[3 * bucketIndex + 1];
256
+ single.z =
257
+ (data.getUint16(splatOffset + 4, true) - compressionScaleRange) * compressionScaleFactor +
258
+ bucketArray[3 * bucketIndex + 2];
259
+ single.sx = fromHalf(data.getUint16(splatOffset + scaleOffsetBytes + 0, true));
260
+ single.sy = fromHalf(data.getUint16(splatOffset + scaleOffsetBytes + 2, true));
261
+ single.sz = fromHalf(data.getUint16(splatOffset + scaleOffsetBytes + 4, true));
262
+ single.qw = fromHalf(data.getUint16(splatOffset + rotationOffsetBytes + 0, true));
263
+ single.qx = fromHalf(data.getUint16(splatOffset + rotationOffsetBytes + 2, true));
264
+ single.qy = fromHalf(data.getUint16(splatOffset + rotationOffsetBytes + 4, true));
265
+ single.qz = fromHalf(data.getUint16(splatOffset + rotationOffsetBytes + 6, true));
266
+ }
267
+ single.r = data.getUint8(splatOffset + colorOffsetBytes + 0) / 255;
268
+ single.g = data.getUint8(splatOffset + colorOffsetBytes + 1) / 255;
269
+ single.b = data.getUint8(splatOffset + colorOffsetBytes + 2) / 255;
270
+ single.a = data.getUint8(splatOffset + colorOffsetBytes + 3) / 255;
271
+ setFn(j + BlockOffset, single);
272
+ const shOffsetBytes = splatOffset + sphericalHarmonicsOffsetBytes;
273
+ for (let k = 0; k < shComponents; k++) {
274
+ shData[k] =
275
+ compressionLevel === 0
276
+ ? data.getFloat32(shOffsetBytes + SHIndex[k] * 4, true)
277
+ : compressionLevel === 1
278
+ ? fromHalf(data.getUint16(shOffsetBytes + SHIndex[k] * 2, true))
279
+ : minSH + (data.getUint8(shOffsetBytes + SHIndex[k]) / 255) * (maxSH - minSH);
280
+ }
281
+ for (let k = maxSHSize - 1; k >= shComponents; k--) {
282
+ shData[k] = 0;
283
+ }
284
+ setShFn(j + BlockOffset, shData);
285
+ }
286
+ sectionBase += storageSizeBytes;
287
+ }
288
+ data.finishBlock();
289
+ }
290
+ async write(_stream, _data) {
291
+ throw new Error('Method not implemented.');
292
+ }
293
+ }
@@ -1,11 +1,11 @@
1
- import { SplatData } from '../SplatData.js';
2
- import { IFile } from './IFile.js';
3
- export declare class LccFile implements IFile {
4
- private counts;
5
- private shDegree;
6
- private meta;
7
- private refs;
8
- private load;
9
- read(stream: ReadableStream<Uint8Array>, contentLength: number, data: SplatData): Promise<void>;
10
- write(_stream: WritableStream<Uint8Array>, _data: SplatData): Promise<void>;
11
- }
1
+ import type { SplatData } from '../SplatData.js';
2
+ import type { IFile } from './IFile.js';
3
+ export declare class LccFile implements IFile {
4
+ private counts;
5
+ private shDegree;
6
+ private meta;
7
+ private refs;
8
+ private load;
9
+ read(stream: ReadableStream<Uint8Array>, contentLength: number, data: SplatData): Promise<void>;
10
+ write(_stream: WritableStream<Uint8Array>, _data: SplatData): Promise<void>;
11
+ }