@d5techs/3dgs-lib 1.4.18 → 1.4.19
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/dist/3dgs-lib.cjs +136 -29
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +136 -29
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/gs/SOGEncoder.d.ts +5 -4
- package/package.json +1 -1
package/dist/3dgs-lib.cjs
CHANGED
|
@@ -6150,14 +6150,43 @@ const SH_C0 = 0.28209479177387814;
|
|
|
6150
6150
|
function symLog(x) {
|
|
6151
6151
|
return Math.sign(x) * Math.log(1 + Math.abs(x));
|
|
6152
6152
|
}
|
|
6153
|
-
function
|
|
6153
|
+
function kmeansppInit(values, k) {
|
|
6154
|
+
const n = values.length;
|
|
6155
|
+
const centers = new Float64Array(k);
|
|
6156
|
+
centers[0] = values[Math.floor(Math.random() * n)];
|
|
6157
|
+
const dist = new Float64Array(n);
|
|
6158
|
+
dist.fill(Infinity);
|
|
6159
|
+
for (let c = 1; c < k; c++) {
|
|
6160
|
+
let totalDist = 0;
|
|
6161
|
+
for (let i = 0; i < n; i++) {
|
|
6162
|
+
const d = (values[i] - centers[c - 1]) ** 2;
|
|
6163
|
+
if (d < dist[i]) dist[i] = d;
|
|
6164
|
+
totalDist += dist[i];
|
|
6165
|
+
}
|
|
6166
|
+
let target = Math.random() * totalDist;
|
|
6167
|
+
let chosen = 0;
|
|
6168
|
+
for (let i = 0; i < n; i++) {
|
|
6169
|
+
target -= dist[i];
|
|
6170
|
+
if (target <= 0) {
|
|
6171
|
+
chosen = i;
|
|
6172
|
+
break;
|
|
6173
|
+
}
|
|
6174
|
+
}
|
|
6175
|
+
centers[c] = values[chosen];
|
|
6176
|
+
}
|
|
6177
|
+
return centers;
|
|
6178
|
+
}
|
|
6179
|
+
function buildCodebook(values, size = 256, iterations = 20) {
|
|
6154
6180
|
if (values.length === 0) return new Array(size).fill(0);
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6181
|
+
if (values.length <= size) {
|
|
6182
|
+
const cb = Array.from(new Set(Array.from(values))).sort((a, b) => a - b);
|
|
6183
|
+
while (cb.length < size) cb.push(cb[cb.length - 1]);
|
|
6184
|
+
return cb.slice(0, size);
|
|
6159
6185
|
}
|
|
6186
|
+
const codebook = kmeansppInit(values, size);
|
|
6160
6187
|
const assignments = new Uint8Array(values.length);
|
|
6188
|
+
const sums = new Float64Array(size);
|
|
6189
|
+
const counts = new Uint32Array(size);
|
|
6161
6190
|
for (let iter = 0; iter < iterations; iter++) {
|
|
6162
6191
|
for (let i = 0; i < values.length; i++) {
|
|
6163
6192
|
let bestIdx = 0;
|
|
@@ -6171,29 +6200,74 @@ function buildCodebook(values, size = 256, iterations = 8) {
|
|
|
6171
6200
|
}
|
|
6172
6201
|
assignments[i] = bestIdx;
|
|
6173
6202
|
}
|
|
6174
|
-
|
|
6175
|
-
|
|
6203
|
+
sums.fill(0);
|
|
6204
|
+
counts.fill(0);
|
|
6176
6205
|
for (let i = 0; i < values.length; i++) {
|
|
6177
6206
|
sums[assignments[i]] += values[i];
|
|
6178
6207
|
counts[assignments[i]]++;
|
|
6179
6208
|
}
|
|
6209
|
+
let changed = false;
|
|
6180
6210
|
for (let j = 0; j < size; j++) {
|
|
6181
|
-
if (counts[j] > 0)
|
|
6211
|
+
if (counts[j] > 0) {
|
|
6212
|
+
const newVal = sums[j] / counts[j];
|
|
6213
|
+
if (newVal !== codebook[j]) {
|
|
6214
|
+
codebook[j] = newVal;
|
|
6215
|
+
changed = true;
|
|
6216
|
+
}
|
|
6217
|
+
}
|
|
6182
6218
|
}
|
|
6219
|
+
if (!changed) break;
|
|
6183
6220
|
}
|
|
6184
|
-
|
|
6221
|
+
const result = Array.from(codebook);
|
|
6222
|
+
result.sort((a, b) => a - b);
|
|
6223
|
+
return result;
|
|
6185
6224
|
}
|
|
6186
|
-
function findNearest(
|
|
6187
|
-
let
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6225
|
+
function findNearest(sortedCodebook, value) {
|
|
6226
|
+
let lo = 0, hi = sortedCodebook.length - 1;
|
|
6227
|
+
while (lo < hi) {
|
|
6228
|
+
const mid = lo + hi >> 1;
|
|
6229
|
+
if (sortedCodebook[mid] < value) lo = mid + 1;
|
|
6230
|
+
else hi = mid;
|
|
6231
|
+
}
|
|
6232
|
+
if (lo > 0 && Math.abs(sortedCodebook[lo - 1] - value) <= Math.abs(sortedCodebook[lo] - value)) {
|
|
6233
|
+
return lo - 1;
|
|
6195
6234
|
}
|
|
6196
|
-
return
|
|
6235
|
+
return lo;
|
|
6236
|
+
}
|
|
6237
|
+
function mortonSort(positions, count) {
|
|
6238
|
+
let minx = Infinity, miny = Infinity, minz = Infinity;
|
|
6239
|
+
let maxx = -Infinity, maxy = -Infinity, maxz = -Infinity;
|
|
6240
|
+
for (let i = 0; i < count; i++) {
|
|
6241
|
+
const x = positions[i * 3], y = positions[i * 3 + 1], z = positions[i * 3 + 2];
|
|
6242
|
+
if (x < minx) minx = x;
|
|
6243
|
+
if (x > maxx) maxx = x;
|
|
6244
|
+
if (y < miny) miny = y;
|
|
6245
|
+
if (y > maxy) maxy = y;
|
|
6246
|
+
if (z < minz) minz = z;
|
|
6247
|
+
if (z > maxz) maxz = z;
|
|
6248
|
+
}
|
|
6249
|
+
const xlen = maxx - minx || 1;
|
|
6250
|
+
const ylen = maxy - miny || 1;
|
|
6251
|
+
const zlen = maxz - minz || 1;
|
|
6252
|
+
const part1By2 = (x) => {
|
|
6253
|
+
x &= 1023;
|
|
6254
|
+
x = (x ^ x << 16) & 4278190335;
|
|
6255
|
+
x = (x ^ x << 8) & 50393103;
|
|
6256
|
+
x = (x ^ x << 4) & 51130563;
|
|
6257
|
+
x = (x ^ x << 2) & 153391689;
|
|
6258
|
+
return x;
|
|
6259
|
+
};
|
|
6260
|
+
const morton = new Uint32Array(count);
|
|
6261
|
+
const indices = new Uint32Array(count);
|
|
6262
|
+
for (let i = 0; i < count; i++) {
|
|
6263
|
+
const ix = Math.min(1023, Math.floor(1024 * (positions[i * 3] - minx) / xlen));
|
|
6264
|
+
const iy = Math.min(1023, Math.floor(1024 * (positions[i * 3 + 1] - miny) / ylen));
|
|
6265
|
+
const iz = Math.min(1023, Math.floor(1024 * (positions[i * 3 + 2] - minz) / zlen));
|
|
6266
|
+
morton[i] = (part1By2(iz) << 2) + (part1By2(iy) << 1) + part1By2(ix);
|
|
6267
|
+
indices[i] = i;
|
|
6268
|
+
}
|
|
6269
|
+
indices.sort((a, b) => morton[a] - morton[b]);
|
|
6270
|
+
return indices;
|
|
6197
6271
|
}
|
|
6198
6272
|
function calcImageDimensions(count) {
|
|
6199
6273
|
const width = Math.ceil(Math.sqrt(count));
|
|
@@ -6249,11 +6323,36 @@ async function serializeSOG(data, coordinateSystem = "blender") {
|
|
|
6249
6323
|
rotations[i4 + 3] = ry;
|
|
6250
6324
|
}
|
|
6251
6325
|
}
|
|
6326
|
+
const sortOrder = mortonSort(positions, count);
|
|
6327
|
+
const sortedPositions = new Float32Array(count * 3);
|
|
6328
|
+
const sortedScales = new Float32Array(count * 3);
|
|
6329
|
+
const sortedRotations = new Float32Array(count * 4);
|
|
6330
|
+
const sortedColors = new Float32Array(count * 3);
|
|
6331
|
+
const sortedOpacities = new Float32Array(count);
|
|
6332
|
+
for (let dst = 0; dst < count; dst++) {
|
|
6333
|
+
const src = sortOrder[dst];
|
|
6334
|
+
const s3 = src * 3, d3 = dst * 3;
|
|
6335
|
+
sortedPositions[d3] = positions[s3];
|
|
6336
|
+
sortedPositions[d3 + 1] = positions[s3 + 1];
|
|
6337
|
+
sortedPositions[d3 + 2] = positions[s3 + 2];
|
|
6338
|
+
sortedScales[d3] = scales[s3];
|
|
6339
|
+
sortedScales[d3 + 1] = scales[s3 + 1];
|
|
6340
|
+
sortedScales[d3 + 2] = scales[s3 + 2];
|
|
6341
|
+
sortedColors[d3] = colors[s3];
|
|
6342
|
+
sortedColors[d3 + 1] = colors[s3 + 1];
|
|
6343
|
+
sortedColors[d3 + 2] = colors[s3 + 2];
|
|
6344
|
+
const s4 = src * 4, d4 = dst * 4;
|
|
6345
|
+
sortedRotations[d4] = rotations[s4];
|
|
6346
|
+
sortedRotations[d4 + 1] = rotations[s4 + 1];
|
|
6347
|
+
sortedRotations[d4 + 2] = rotations[s4 + 2];
|
|
6348
|
+
sortedRotations[d4 + 3] = rotations[s4 + 3];
|
|
6349
|
+
sortedOpacities[dst] = opacities[src];
|
|
6350
|
+
}
|
|
6252
6351
|
const { width, height } = calcImageDimensions(count);
|
|
6253
6352
|
const totalPixels = width * height;
|
|
6254
6353
|
const logPositions = new Float32Array(count * 3);
|
|
6255
6354
|
for (let i = 0; i < count * 3; i++) {
|
|
6256
|
-
logPositions[i] = symLog(
|
|
6355
|
+
logPositions[i] = symLog(sortedPositions[i]);
|
|
6257
6356
|
}
|
|
6258
6357
|
const mins = [Infinity, Infinity, Infinity];
|
|
6259
6358
|
const maxs = [-Infinity, -Infinity, -Infinity];
|
|
@@ -6282,7 +6381,7 @@ async function serializeSOG(data, coordinateSystem = "blender") {
|
|
|
6282
6381
|
}
|
|
6283
6382
|
const logScales = new Float32Array(count * 3);
|
|
6284
6383
|
for (let i = 0; i < count * 3; i++) {
|
|
6285
|
-
logScales[i] = Math.log(Math.max(1e-8,
|
|
6384
|
+
logScales[i] = Math.log(Math.max(1e-8, sortedScales[i]));
|
|
6286
6385
|
}
|
|
6287
6386
|
const scaleCodebook = buildCodebook(logScales);
|
|
6288
6387
|
const scalesData = new Uint8ClampedArray(totalPixels * 4);
|
|
@@ -6299,10 +6398,18 @@ async function serializeSOG(data, coordinateSystem = "blender") {
|
|
|
6299
6398
|
const SQRT2 = Math.SQRT2;
|
|
6300
6399
|
for (let i = 0; i < count; i++) {
|
|
6301
6400
|
const off = i * 4;
|
|
6302
|
-
let qw =
|
|
6303
|
-
let qx =
|
|
6304
|
-
let qy =
|
|
6305
|
-
let qz =
|
|
6401
|
+
let qw = sortedRotations[i * 4 + 0];
|
|
6402
|
+
let qx = sortedRotations[i * 4 + 1];
|
|
6403
|
+
let qy = sortedRotations[i * 4 + 2];
|
|
6404
|
+
let qz = sortedRotations[i * 4 + 3];
|
|
6405
|
+
const len = Math.sqrt(qw * qw + qx * qx + qy * qy + qz * qz);
|
|
6406
|
+
if (len > 0) {
|
|
6407
|
+
const inv = 1 / len;
|
|
6408
|
+
qw *= inv;
|
|
6409
|
+
qx *= inv;
|
|
6410
|
+
qy *= inv;
|
|
6411
|
+
qz *= inv;
|
|
6412
|
+
}
|
|
6306
6413
|
const comps = [qw, qx, qy, qz];
|
|
6307
6414
|
let largest = 0;
|
|
6308
6415
|
let largestAbs = Math.abs(comps[0]);
|
|
@@ -6344,9 +6451,9 @@ async function serializeSOG(data, coordinateSystem = "blender") {
|
|
|
6344
6451
|
}
|
|
6345
6452
|
const dcValues = new Float32Array(count * 3);
|
|
6346
6453
|
for (let i = 0; i < count; i++) {
|
|
6347
|
-
dcValues[i * 3 + 0] = (
|
|
6348
|
-
dcValues[i * 3 + 1] = (
|
|
6349
|
-
dcValues[i * 3 + 2] = (
|
|
6454
|
+
dcValues[i * 3 + 0] = (sortedColors[i * 3 + 0] - 0.5) / SH_C0;
|
|
6455
|
+
dcValues[i * 3 + 1] = (sortedColors[i * 3 + 1] - 0.5) / SH_C0;
|
|
6456
|
+
dcValues[i * 3 + 2] = (sortedColors[i * 3 + 2] - 0.5) / SH_C0;
|
|
6350
6457
|
}
|
|
6351
6458
|
const dcCodebook = buildCodebook(dcValues);
|
|
6352
6459
|
const sh0Data = new Uint8ClampedArray(totalPixels * 4);
|
|
@@ -6356,7 +6463,7 @@ async function serializeSOG(data, coordinateSystem = "blender") {
|
|
|
6356
6463
|
sh0Data[off + 0] = findNearest(dcCodebook, dcValues[i * 3 + 0]);
|
|
6357
6464
|
sh0Data[off + 1] = findNearest(dcCodebook, dcValues[i * 3 + 1]);
|
|
6358
6465
|
sh0Data[off + 2] = findNearest(dcCodebook, dcValues[i * 3 + 2]);
|
|
6359
|
-
sh0Data[off + 3] = Math.round(Math.max(0, Math.min(255,
|
|
6466
|
+
sh0Data[off + 3] = Math.round(Math.max(0, Math.min(255, sortedOpacities[i] * 255)));
|
|
6360
6467
|
}
|
|
6361
6468
|
const [meansLWebP, meansUWebP, scalesWebP, quatsWebP, sh0WebP] = await Promise.all([
|
|
6362
6469
|
encodeWebP(width, height, meansLData),
|