@d5techs/3dgs-lib 1.4.5 → 1.4.7
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 +80 -30
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +80 -30
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +4 -0
- package/dist/gs/PLYLoaderMobile.d.ts +4 -3
- package/package.json +1 -1
package/dist/3dgs-lib.js
CHANGED
|
@@ -439,7 +439,7 @@ class Camera {
|
|
|
439
439
|
// 45度
|
|
440
440
|
__publicField(this, "aspect", 1);
|
|
441
441
|
__publicField(this, "near", 0.01);
|
|
442
|
-
__publicField(this, "far",
|
|
442
|
+
__publicField(this, "far", 1e5);
|
|
443
443
|
// 矩阵
|
|
444
444
|
__publicField(this, "viewMatrix", new Float32Array(16));
|
|
445
445
|
__publicField(this, "projectionMatrix", new Float32Array(16));
|
|
@@ -4269,7 +4269,7 @@ function transformSHCoeffsYZSwap$1(sh, base, perChannel) {
|
|
|
4269
4269
|
for (let ch = 0; ch < 3; ch++) {
|
|
4270
4270
|
const a = sh[base + ch];
|
|
4271
4271
|
const b = sh[base + 3 + ch];
|
|
4272
|
-
sh[base + ch] =
|
|
4272
|
+
sh[base + ch] = b;
|
|
4273
4273
|
sh[base + 3 + ch] = -a;
|
|
4274
4274
|
}
|
|
4275
4275
|
}
|
|
@@ -4280,8 +4280,8 @@ function transformSHCoeffsYZSwap$1(sh, base, perChannel) {
|
|
|
4280
4280
|
const g2 = sh[base + 15 + ch];
|
|
4281
4281
|
const g3 = sh[base + 18 + ch];
|
|
4282
4282
|
const g4 = sh[base + 21 + ch];
|
|
4283
|
-
sh[base + 9 + ch] =
|
|
4284
|
-
sh[base + 12 + ch] = g1;
|
|
4283
|
+
sh[base + 9 + ch] = g3;
|
|
4284
|
+
sh[base + 12 + ch] = -g1;
|
|
4285
4285
|
sh[base + 15 + ch] = -0.5 * g2 - SQRT3_2 * g4;
|
|
4286
4286
|
sh[base + 18 + ch] = -g0;
|
|
4287
4287
|
sh[base + 21 + ch] = -SQRT3_2 * g2 + 0.5 * g4;
|
|
@@ -4299,9 +4299,9 @@ function transformSHCoeffsYZSwap$1(sh, base, perChannel) {
|
|
|
4299
4299
|
const g4 = sh[base + 36 + ch];
|
|
4300
4300
|
const g5 = sh[base + 39 + ch];
|
|
4301
4301
|
const g6 = sh[base + 42 + ch];
|
|
4302
|
-
sh[base + 24 + ch] = A * g3
|
|
4303
|
-
sh[base + 27 + ch] = g1;
|
|
4304
|
-
sh[base + 30 + ch] = B * g3
|
|
4302
|
+
sh[base + 24 + ch] = -A * g3 + B * g5;
|
|
4303
|
+
sh[base + 27 + ch] = -g1;
|
|
4304
|
+
sh[base + 30 + ch] = -B * g3 - A * g5;
|
|
4305
4305
|
sh[base + 33 + ch] = A * g0 + B * g2;
|
|
4306
4306
|
sh[base + 36 + ch] = -0.25 * g4 - P * g6;
|
|
4307
4307
|
sh[base + 39 + ch] = -B * g0 + A * g2;
|
|
@@ -4539,13 +4539,13 @@ async function loadPLY(url, options = {}) {
|
|
|
4539
4539
|
transformSHCoeffsYZSwap$1(shRestBuffer, shOffset, perChannel);
|
|
4540
4540
|
}
|
|
4541
4541
|
splats[i] = {
|
|
4542
|
-
mean: swapYZ ? [x, z, y] : [x, y, z],
|
|
4542
|
+
mean: swapYZ ? [x, z, -y] : [x, y, z],
|
|
4543
4543
|
scale: swapYZ ? [scale_0, scale_2, scale_1] : [scale_0, scale_1, scale_2],
|
|
4544
4544
|
rotation: swapYZ ? [
|
|
4545
|
-
|
|
4545
|
+
rot_0 * qnorm,
|
|
4546
4546
|
rot_1 * qnorm,
|
|
4547
4547
|
rot_3 * qnorm,
|
|
4548
|
-
rot_2 * qnorm
|
|
4548
|
+
-rot_2 * qnorm
|
|
4549
4549
|
] : [
|
|
4550
4550
|
rot_0 * qnorm,
|
|
4551
4551
|
rot_1 * qnorm,
|
|
@@ -4583,7 +4583,7 @@ function transformSHCoeffsYZSwap(sh, base, perChannel) {
|
|
|
4583
4583
|
for (let ch = 0; ch < 3; ch++) {
|
|
4584
4584
|
const a = sh[base + ch];
|
|
4585
4585
|
const b = sh[base + 3 + ch];
|
|
4586
|
-
sh[base + ch] =
|
|
4586
|
+
sh[base + ch] = b;
|
|
4587
4587
|
sh[base + 3 + ch] = -a;
|
|
4588
4588
|
}
|
|
4589
4589
|
}
|
|
@@ -4594,8 +4594,8 @@ function transformSHCoeffsYZSwap(sh, base, perChannel) {
|
|
|
4594
4594
|
const g2 = sh[base + 15 + ch];
|
|
4595
4595
|
const g3 = sh[base + 18 + ch];
|
|
4596
4596
|
const g4 = sh[base + 21 + ch];
|
|
4597
|
-
sh[base + 9 + ch] =
|
|
4598
|
-
sh[base + 12 + ch] = g1;
|
|
4597
|
+
sh[base + 9 + ch] = g3;
|
|
4598
|
+
sh[base + 12 + ch] = -g1;
|
|
4599
4599
|
sh[base + 15 + ch] = -0.5 * g2 - SQRT3_2 * g4;
|
|
4600
4600
|
sh[base + 18 + ch] = -g0;
|
|
4601
4601
|
sh[base + 21 + ch] = -SQRT3_2 * g2 + 0.5 * g4;
|
|
@@ -4613,9 +4613,9 @@ function transformSHCoeffsYZSwap(sh, base, perChannel) {
|
|
|
4613
4613
|
const g4 = sh[base + 36 + ch];
|
|
4614
4614
|
const g5 = sh[base + 39 + ch];
|
|
4615
4615
|
const g6 = sh[base + 42 + ch];
|
|
4616
|
-
sh[base + 24 + ch] = A * g3
|
|
4617
|
-
sh[base + 27 + ch] = g1;
|
|
4618
|
-
sh[base + 30 + ch] = B * g3
|
|
4616
|
+
sh[base + 24 + ch] = -A * g3 + B * g5;
|
|
4617
|
+
sh[base + 27 + ch] = -g1;
|
|
4618
|
+
sh[base + 30 + ch] = -B * g3 - A * g5;
|
|
4619
4619
|
sh[base + 33 + ch] = A * g0 + B * g2;
|
|
4620
4620
|
sh[base + 36 + ch] = -0.25 * g4 - P * g6;
|
|
4621
4621
|
sh[base + 39 + ch] = -B * g0 + A * g2;
|
|
@@ -4910,7 +4910,7 @@ async function parsePLYBuffer(buffer, options = {}) {
|
|
|
4910
4910
|
const pz = offsets.z >= 0 ? readProperty(dataView, base + offsets.z, types.z, littleEndian) : 0;
|
|
4911
4911
|
positions[outputIdx * 3 + 0] = px;
|
|
4912
4912
|
positions[outputIdx * 3 + 1] = swapYZ ? pz : py;
|
|
4913
|
-
positions[outputIdx * 3 + 2] = swapYZ ? py : pz;
|
|
4913
|
+
positions[outputIdx * 3 + 2] = swapYZ ? -py : pz;
|
|
4914
4914
|
const sx = offsets.scale_0 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_0, types.scale_0, littleEndian)) : 1;
|
|
4915
4915
|
const sy = offsets.scale_1 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_1, types.scale_1, littleEndian)) : 1;
|
|
4916
4916
|
const sz = offsets.scale_2 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_2, types.scale_2, littleEndian)) : 1;
|
|
@@ -4924,10 +4924,10 @@ async function parsePLYBuffer(buffer, options = {}) {
|
|
|
4924
4924
|
const qlen = Math.sqrt(rot_0 * rot_0 + rot_1 * rot_1 + rot_2 * rot_2 + rot_3 * rot_3);
|
|
4925
4925
|
const qnorm = qlen > 0 ? 1 / qlen : 1;
|
|
4926
4926
|
if (swapYZ) {
|
|
4927
|
-
rotations[outputIdx * 4 + 0] =
|
|
4927
|
+
rotations[outputIdx * 4 + 0] = rot_0 * qnorm;
|
|
4928
4928
|
rotations[outputIdx * 4 + 1] = rot_1 * qnorm;
|
|
4929
4929
|
rotations[outputIdx * 4 + 2] = rot_3 * qnorm;
|
|
4930
|
-
rotations[outputIdx * 4 + 3] = rot_2 * qnorm;
|
|
4930
|
+
rotations[outputIdx * 4 + 3] = -rot_2 * qnorm;
|
|
4931
4931
|
} else {
|
|
4932
4932
|
rotations[outputIdx * 4 + 0] = rot_0 * qnorm;
|
|
4933
4933
|
rotations[outputIdx * 4 + 1] = rot_1 * qnorm;
|
|
@@ -5585,8 +5585,16 @@ async function decodeWebP(bytes) {
|
|
|
5585
5585
|
});
|
|
5586
5586
|
const w = bitmap.width;
|
|
5587
5587
|
const h = bitmap.height;
|
|
5588
|
-
|
|
5589
|
-
|
|
5588
|
+
let ctx;
|
|
5589
|
+
if (typeof OffscreenCanvas !== "undefined") {
|
|
5590
|
+
const oc = new OffscreenCanvas(w, h);
|
|
5591
|
+
ctx = oc.getContext("2d");
|
|
5592
|
+
} else {
|
|
5593
|
+
const hc = document.createElement("canvas");
|
|
5594
|
+
hc.width = w;
|
|
5595
|
+
hc.height = h;
|
|
5596
|
+
ctx = hc.getContext("2d");
|
|
5597
|
+
}
|
|
5590
5598
|
ctx.drawImage(bitmap, 0, 0);
|
|
5591
5599
|
bitmap.close();
|
|
5592
5600
|
return { width: w, height: h, data: ctx.getImageData(0, 0, w, h).data };
|
|
@@ -9413,6 +9421,7 @@ class GSSplatRendererMobile {
|
|
|
9413
9421
|
const memoryMB = (this.compressedTextures.width * this.compressedTextures.height * 52 / // 约 52 bytes per texel (16+16+16+4)
|
|
9414
9422
|
(1024 * 1024)).toFixed(2);
|
|
9415
9423
|
} catch (error) {
|
|
9424
|
+
console.error("[GSSplatRendererMobile] setCompactData failed:", error);
|
|
9416
9425
|
this.splatCount = 0;
|
|
9417
9426
|
this.compressedTextures = null;
|
|
9418
9427
|
this.sorter = null;
|
|
@@ -16346,6 +16355,7 @@ class App {
|
|
|
16346
16355
|
*/
|
|
16347
16356
|
async addSplat(urlOrBuffer, onProgress, isLocalFile = false, coordinateSystem = "blender") {
|
|
16348
16357
|
try {
|
|
16358
|
+
const isMobile = isMobileDevice();
|
|
16349
16359
|
let buffer;
|
|
16350
16360
|
if (typeof urlOrBuffer === "string") {
|
|
16351
16361
|
buffer = await this.fetchWithProgress(urlOrBuffer, (downloadProgress) => {
|
|
@@ -16364,26 +16374,67 @@ class App {
|
|
|
16364
16374
|
if (coordinateSystem === "blender") {
|
|
16365
16375
|
for (const s of splats) {
|
|
16366
16376
|
const [mx, my, mz] = s.mean;
|
|
16367
|
-
s.mean = [mx, mz, my];
|
|
16377
|
+
s.mean = [mx, mz, -my];
|
|
16368
16378
|
const [sx, sy, sz] = s.scale;
|
|
16369
16379
|
s.scale = [sx, sz, sy];
|
|
16370
16380
|
const [rw, rx, ry, rz] = s.rotation;
|
|
16371
|
-
s.rotation = [
|
|
16381
|
+
s.rotation = [rw, rx, rz, -ry];
|
|
16372
16382
|
}
|
|
16373
16383
|
}
|
|
16374
16384
|
if (onProgress) onProgress(90, "parse");
|
|
16375
16385
|
if (onProgress) onProgress(90, "upload");
|
|
16376
|
-
|
|
16377
|
-
|
|
16386
|
+
let gsRenderer;
|
|
16387
|
+
if (isMobile) {
|
|
16388
|
+
const mobileRenderer = new GSSplatRendererMobile(this.renderer, this.camera);
|
|
16389
|
+
this.useMobileRenderer = true;
|
|
16390
|
+
const compactData = App.splatCpuToCompactData(splats);
|
|
16391
|
+
mobileRenderer.setCompactData(compactData);
|
|
16392
|
+
this.lastCompactData = compactData;
|
|
16393
|
+
gsRenderer = mobileRenderer;
|
|
16394
|
+
} else {
|
|
16395
|
+
const desktopRenderer = new GSSplatRenderer(this.renderer, this.camera);
|
|
16396
|
+
this.useMobileRenderer = false;
|
|
16397
|
+
desktopRenderer.setData(splats);
|
|
16398
|
+
gsRenderer = desktopRenderer;
|
|
16399
|
+
}
|
|
16378
16400
|
this.sceneManager.setGSRenderer(gsRenderer);
|
|
16379
16401
|
this.hotspotManager.setGSRenderer(gsRenderer);
|
|
16380
|
-
this.useMobileRenderer = false;
|
|
16381
16402
|
if (onProgress) onProgress(100, "upload");
|
|
16382
16403
|
return splats.length;
|
|
16383
16404
|
} catch (error) {
|
|
16384
16405
|
throw error;
|
|
16385
16406
|
}
|
|
16386
16407
|
}
|
|
16408
|
+
/**
|
|
16409
|
+
* 将 SplatCPU[] 转换为 CompactSplatData(用于移动端渲染器)
|
|
16410
|
+
*/
|
|
16411
|
+
static splatCpuToCompactData(splats) {
|
|
16412
|
+
const count = splats.length;
|
|
16413
|
+
const positions = new Float32Array(count * 3);
|
|
16414
|
+
const scales = new Float32Array(count * 3);
|
|
16415
|
+
const rotations = new Float32Array(count * 4);
|
|
16416
|
+
const colors = new Float32Array(count * 3);
|
|
16417
|
+
const opacities = new Float32Array(count);
|
|
16418
|
+
for (let i = 0; i < count; i++) {
|
|
16419
|
+
const s = splats[i];
|
|
16420
|
+
const i3 = i * 3, i4 = i * 4;
|
|
16421
|
+
positions[i3] = s.mean[0];
|
|
16422
|
+
positions[i3 + 1] = s.mean[1];
|
|
16423
|
+
positions[i3 + 2] = s.mean[2];
|
|
16424
|
+
scales[i3] = s.scale[0];
|
|
16425
|
+
scales[i3 + 1] = s.scale[1];
|
|
16426
|
+
scales[i3 + 2] = s.scale[2];
|
|
16427
|
+
rotations[i4] = s.rotation[0];
|
|
16428
|
+
rotations[i4 + 1] = s.rotation[1];
|
|
16429
|
+
rotations[i4 + 2] = s.rotation[2];
|
|
16430
|
+
rotations[i4 + 3] = s.rotation[3];
|
|
16431
|
+
colors[i3] = s.colorDC[0];
|
|
16432
|
+
colors[i3 + 1] = s.colorDC[1];
|
|
16433
|
+
colors[i3 + 2] = s.colorDC[2];
|
|
16434
|
+
opacities[i] = s.opacity;
|
|
16435
|
+
}
|
|
16436
|
+
return { count, positions, scales, rotations, colors, opacities };
|
|
16437
|
+
}
|
|
16387
16438
|
/**
|
|
16388
16439
|
* 加载 SOG 文件 (Spatially Ordered Gaussians)
|
|
16389
16440
|
* @param coordinateSystem 源数据坐标系,默认 'blender'(Z-up → Y-up 自动转换)
|
|
@@ -16416,14 +16467,13 @@ class App {
|
|
|
16416
16467
|
const i3 = i * 3, i4 = i * 4;
|
|
16417
16468
|
const py = positions[i3 + 1], pz = positions[i3 + 2];
|
|
16418
16469
|
positions[i3 + 1] = pz;
|
|
16419
|
-
positions[i3 + 2] = py;
|
|
16470
|
+
positions[i3 + 2] = -py;
|
|
16420
16471
|
const sy = scales[i3 + 1], sz = scales[i3 + 2];
|
|
16421
16472
|
scales[i3 + 1] = sz;
|
|
16422
16473
|
scales[i3 + 2] = sy;
|
|
16423
|
-
const
|
|
16424
|
-
rotations[i4] = -rw;
|
|
16474
|
+
const ry = rotations[i4 + 2], rz = rotations[i4 + 3];
|
|
16425
16475
|
rotations[i4 + 2] = rz;
|
|
16426
|
-
rotations[i4 + 3] = ry;
|
|
16476
|
+
rotations[i4 + 3] = -ry;
|
|
16427
16477
|
if (shCoeffs) {
|
|
16428
16478
|
transformSHCoeffsYZSwap(shCoeffs, i * 45, 15);
|
|
16429
16479
|
}
|