@d5techs/3dgs-lib 1.2.0 → 1.3.0
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 +46 -18
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +46 -18
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +6 -1
- package/dist/gs/PLYLoader.d.ts +7 -1
- package/dist/gs/PLYLoaderMobile.d.ts +8 -0
- package/dist/index.d.ts +2 -2
- package/package.json +1 -1
package/dist/3dgs-lib.cjs
CHANGED
|
@@ -4413,7 +4413,8 @@ function readProperty$1(dataView, baseOffset, prop, littleEndian) {
|
|
|
4413
4413
|
function sigmoid$1(x) {
|
|
4414
4414
|
return 1 / (1 + Math.exp(-x));
|
|
4415
4415
|
}
|
|
4416
|
-
async function loadPLY(url) {
|
|
4416
|
+
async function loadPLY(url, options = {}) {
|
|
4417
|
+
const { coordinateSystem = "blender" } = options;
|
|
4417
4418
|
const response = await fetch(url);
|
|
4418
4419
|
if (!response.ok) {
|
|
4419
4420
|
throw new Error(`无法加载 PLY 文件: ${url}`);
|
|
@@ -4425,6 +4426,7 @@ async function loadPLY(url) {
|
|
|
4425
4426
|
throw new Error("不支持 ASCII 格式的 PLY 文件,请使用 binary_little_endian 或 binary_big_endian 格式");
|
|
4426
4427
|
}
|
|
4427
4428
|
const littleEndian = format === "binary_little_endian";
|
|
4429
|
+
const swapYZ = coordinateSystem === "blender";
|
|
4428
4430
|
const propMap = buildPropertyMap(properties);
|
|
4429
4431
|
const props = {
|
|
4430
4432
|
x: propMap.get("x"),
|
|
@@ -4490,9 +4492,14 @@ async function loadPLY(url) {
|
|
|
4490
4492
|
shRest[dstBase + 2] = srcB < shRestProps.length ? readProperty$1(dataView, base, shRestProps[srcB], littleEndian) : 0;
|
|
4491
4493
|
}
|
|
4492
4494
|
splats[i] = {
|
|
4493
|
-
mean: [x, y, z],
|
|
4494
|
-
scale: [scale_0, scale_1, scale_2],
|
|
4495
|
-
rotation: [
|
|
4495
|
+
mean: swapYZ ? [x, z, y] : [x, y, z],
|
|
4496
|
+
scale: swapYZ ? [scale_0, scale_2, scale_1] : [scale_0, scale_1, scale_2],
|
|
4497
|
+
rotation: swapYZ ? [
|
|
4498
|
+
-rot_0 * qnorm,
|
|
4499
|
+
rot_1 * qnorm,
|
|
4500
|
+
rot_3 * qnorm,
|
|
4501
|
+
rot_2 * qnorm
|
|
4502
|
+
] : [
|
|
4496
4503
|
rot_0 * qnorm,
|
|
4497
4504
|
rot_1 * qnorm,
|
|
4498
4505
|
rot_2 * qnorm,
|
|
@@ -4708,7 +4715,8 @@ async function parsePLYBuffer(buffer, options = {}) {
|
|
|
4708
4715
|
const {
|
|
4709
4716
|
maxSplats = 2e5,
|
|
4710
4717
|
loadSH = false,
|
|
4711
|
-
onProgress
|
|
4718
|
+
onProgress,
|
|
4719
|
+
coordinateSystem = "blender"
|
|
4712
4720
|
} = options;
|
|
4713
4721
|
const seed = options.seed ?? buffer.byteLength;
|
|
4714
4722
|
const { headerText, dataOffset } = extractHeader(buffer);
|
|
@@ -4798,27 +4806,41 @@ async function parsePLYBuffer(buffer, options = {}) {
|
|
|
4798
4806
|
const opacities = new Float32Array(actualCount);
|
|
4799
4807
|
const shCoeffs = loadSH ? new Float32Array(actualCount * 45) : void 0;
|
|
4800
4808
|
const dataView = new DataView(buffer, dataOffset);
|
|
4809
|
+
const swapYZ = coordinateSystem === "blender";
|
|
4801
4810
|
let outputIdx = 0;
|
|
4802
4811
|
let lastProgress = 0;
|
|
4803
4812
|
for (let i = 0; i < actualCount; i++) {
|
|
4804
4813
|
const srcIdx = sampleIndices ? sampleIndices[i] : i;
|
|
4805
4814
|
const base = srcIdx * stride;
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4815
|
+
const px = offsets.x >= 0 ? readProperty(dataView, base + offsets.x, types.x, littleEndian) : 0;
|
|
4816
|
+
const py = offsets.y >= 0 ? readProperty(dataView, base + offsets.y, types.y, littleEndian) : 0;
|
|
4817
|
+
const pz = offsets.z >= 0 ? readProperty(dataView, base + offsets.z, types.z, littleEndian) : 0;
|
|
4818
|
+
positions[outputIdx * 3 + 0] = px;
|
|
4819
|
+
positions[outputIdx * 3 + 1] = swapYZ ? pz : py;
|
|
4820
|
+
positions[outputIdx * 3 + 2] = swapYZ ? py : pz;
|
|
4821
|
+
const sx = offsets.scale_0 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_0, types.scale_0, littleEndian)) : 1;
|
|
4822
|
+
const sy = offsets.scale_1 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_1, types.scale_1, littleEndian)) : 1;
|
|
4823
|
+
const sz = offsets.scale_2 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_2, types.scale_2, littleEndian)) : 1;
|
|
4824
|
+
scales[outputIdx * 3 + 0] = sx;
|
|
4825
|
+
scales[outputIdx * 3 + 1] = swapYZ ? sz : sy;
|
|
4826
|
+
scales[outputIdx * 3 + 2] = swapYZ ? sy : sz;
|
|
4812
4827
|
const rot_0 = offsets.rot_0 >= 0 ? readProperty(dataView, base + offsets.rot_0, types.rot_0, littleEndian) : 1;
|
|
4813
4828
|
const rot_1 = offsets.rot_1 >= 0 ? readProperty(dataView, base + offsets.rot_1, types.rot_1, littleEndian) : 0;
|
|
4814
4829
|
const rot_2 = offsets.rot_2 >= 0 ? readProperty(dataView, base + offsets.rot_2, types.rot_2, littleEndian) : 0;
|
|
4815
4830
|
const rot_3 = offsets.rot_3 >= 0 ? readProperty(dataView, base + offsets.rot_3, types.rot_3, littleEndian) : 0;
|
|
4816
4831
|
const qlen = Math.sqrt(rot_0 * rot_0 + rot_1 * rot_1 + rot_2 * rot_2 + rot_3 * rot_3);
|
|
4817
4832
|
const qnorm = qlen > 0 ? 1 / qlen : 1;
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4833
|
+
if (swapYZ) {
|
|
4834
|
+
rotations[outputIdx * 4 + 0] = -rot_0 * qnorm;
|
|
4835
|
+
rotations[outputIdx * 4 + 1] = rot_1 * qnorm;
|
|
4836
|
+
rotations[outputIdx * 4 + 2] = rot_3 * qnorm;
|
|
4837
|
+
rotations[outputIdx * 4 + 3] = rot_2 * qnorm;
|
|
4838
|
+
} else {
|
|
4839
|
+
rotations[outputIdx * 4 + 0] = rot_0 * qnorm;
|
|
4840
|
+
rotations[outputIdx * 4 + 1] = rot_1 * qnorm;
|
|
4841
|
+
rotations[outputIdx * 4 + 2] = rot_2 * qnorm;
|
|
4842
|
+
rotations[outputIdx * 4 + 3] = rot_3 * qnorm;
|
|
4843
|
+
}
|
|
4822
4844
|
const f_dc_0 = offsets.f_dc_0 >= 0 ? readProperty(dataView, base + offsets.f_dc_0, types.f_dc_0, littleEndian) : 0;
|
|
4823
4845
|
const f_dc_1 = offsets.f_dc_1 >= 0 ? readProperty(dataView, base + offsets.f_dc_1, types.f_dc_1, littleEndian) : 0;
|
|
4824
4846
|
const f_dc_2 = offsets.f_dc_2 >= 0 ? readProperty(dataView, base + offsets.f_dc_2, types.f_dc_2, littleEndian) : 0;
|
|
@@ -13970,8 +13992,12 @@ class App {
|
|
|
13970
13992
|
}
|
|
13971
13993
|
/**
|
|
13972
13994
|
* 加载 PLY 文件 (3D Gaussian Splatting)
|
|
13995
|
+
* @param urlOrBuffer PLY 文件 URL 或 ArrayBuffer
|
|
13996
|
+
* @param onProgress 进度回调
|
|
13997
|
+
* @param isLocalFile 是否为本地文件
|
|
13998
|
+
* @param coordinateSystem 源数据坐标系,默认 'blender'(Z-up → Y-up 自动转换)
|
|
13973
13999
|
*/
|
|
13974
|
-
async addPLY(urlOrBuffer, onProgress, isLocalFile = false) {
|
|
14000
|
+
async addPLY(urlOrBuffer, onProgress, isLocalFile = false, coordinateSystem = "blender") {
|
|
13975
14001
|
try {
|
|
13976
14002
|
const isMobile = isMobileDevice();
|
|
13977
14003
|
let buffer;
|
|
@@ -14000,7 +14026,8 @@ class App {
|
|
|
14000
14026
|
const compactData = await this.parsePLYBuffer(buffer, {
|
|
14001
14027
|
maxSplats: Infinity,
|
|
14002
14028
|
loadSH: false,
|
|
14003
|
-
onProgress: parseProgressCallback
|
|
14029
|
+
onProgress: parseProgressCallback,
|
|
14030
|
+
coordinateSystem
|
|
14004
14031
|
});
|
|
14005
14032
|
if (onProgress) onProgress(90, "upload");
|
|
14006
14033
|
gsRenderer.setCompactData(compactData);
|
|
@@ -14014,7 +14041,8 @@ class App {
|
|
|
14014
14041
|
const compactData = await this.parsePLYBuffer(buffer, {
|
|
14015
14042
|
maxSplats: Infinity,
|
|
14016
14043
|
loadSH: true,
|
|
14017
|
-
onProgress: parseProgressCallback
|
|
14044
|
+
onProgress: parseProgressCallback,
|
|
14045
|
+
coordinateSystem
|
|
14018
14046
|
});
|
|
14019
14047
|
if (onProgress) onProgress(90, "upload");
|
|
14020
14048
|
gsRenderer.setCompactData(compactData);
|