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