@d5techs/3dgs-lib 1.4.11 → 1.4.13
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 +120 -8
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +120 -8
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +1 -0
- package/dist/interaction/HotspotManager.d.ts +7 -0
- package/dist/types/material.d.ts +2 -0
- package/package.json +1 -1
package/dist/3dgs-lib.js
CHANGED
|
@@ -2474,10 +2474,16 @@ class MeshRenderer {
|
|
|
2474
2474
|
this.lightDir[2],
|
|
2475
2475
|
this.ambientIntensity
|
|
2476
2476
|
]);
|
|
2477
|
-
|
|
2478
|
-
|
|
2477
|
+
const unlitLightData = new Float32Array([
|
|
2478
|
+
this.lightDir[0],
|
|
2479
|
+
this.lightDir[1],
|
|
2480
|
+
this.lightDir[2],
|
|
2481
|
+
1
|
|
2482
|
+
]);
|
|
2483
|
+
this.renderItems(pass, this.items, device, vpMatrix, lightData, unlitLightData, false);
|
|
2484
|
+
this.renderItems(pass, this.overlayItems, device, vpMatrix, lightData, unlitLightData, true);
|
|
2479
2485
|
}
|
|
2480
|
-
renderItems(pass, items, device, vpMatrix, lightData, overlay) {
|
|
2486
|
+
renderItems(pass, items, device, vpMatrix, lightData, unlitLightData, overlay) {
|
|
2481
2487
|
if (items.length === 0) return;
|
|
2482
2488
|
for (const item of items) {
|
|
2483
2489
|
const { mesh, material, uniformBuffer, bindGroup } = item;
|
|
@@ -2485,7 +2491,11 @@ class MeshRenderer {
|
|
|
2485
2491
|
device.queue.writeBuffer(uniformBuffer, 64, mesh.modelMatrix.buffer);
|
|
2486
2492
|
const colorData = new Float32Array(material.baseColorFactor);
|
|
2487
2493
|
device.queue.writeBuffer(uniformBuffer, 128, colorData.buffer);
|
|
2488
|
-
|
|
2494
|
+
if (material.unlit) {
|
|
2495
|
+
device.queue.writeBuffer(uniformBuffer, 144, unlitLightData.buffer);
|
|
2496
|
+
} else {
|
|
2497
|
+
device.queue.writeBuffer(uniformBuffer, 144, lightData.buffer);
|
|
2498
|
+
}
|
|
2489
2499
|
let pipeline;
|
|
2490
2500
|
if (overlay) {
|
|
2491
2501
|
if (mesh.hasUV) {
|
|
@@ -13999,6 +14009,77 @@ class HotspotManager {
|
|
|
13999
14009
|
this.indicatorMesh.hasUV = false;
|
|
14000
14010
|
this.indicatorMesh.indexFormat = "uint16";
|
|
14001
14011
|
}
|
|
14012
|
+
/**
|
|
14013
|
+
* 在 OBJ 本地坐标系中创建背景圆盘 Mesh,
|
|
14014
|
+
* 使其与 OBJ 图标共享同一 model matrix,billboard/缩放自动生效。
|
|
14015
|
+
*/
|
|
14016
|
+
createBackgroundDisk(objBbox) {
|
|
14017
|
+
const device = this.renderer.device;
|
|
14018
|
+
const segments = 48;
|
|
14019
|
+
const cx = (objBbox.min[0] + objBbox.max[0]) / 2;
|
|
14020
|
+
const cy = (objBbox.min[1] + objBbox.max[1]) / 2;
|
|
14021
|
+
const cz = Math.min(objBbox.min[2], objBbox.max[2]) - 5e-4;
|
|
14022
|
+
const dx = objBbox.max[0] - objBbox.min[0];
|
|
14023
|
+
const dy = objBbox.max[1] - objBbox.min[1];
|
|
14024
|
+
const maxDim2D = Math.max(dx, dy, 1e-6);
|
|
14025
|
+
const radius = maxDim2D * 0.85;
|
|
14026
|
+
const vertexCount = segments + 1;
|
|
14027
|
+
const stride = 6;
|
|
14028
|
+
const vertexData = new Float32Array(vertexCount * stride);
|
|
14029
|
+
vertexData[0] = cx;
|
|
14030
|
+
vertexData[1] = cy;
|
|
14031
|
+
vertexData[2] = cz;
|
|
14032
|
+
vertexData[3] = 0;
|
|
14033
|
+
vertexData[4] = 0;
|
|
14034
|
+
vertexData[5] = 1;
|
|
14035
|
+
for (let i = 0; i < segments; i++) {
|
|
14036
|
+
const angle = i / segments * Math.PI * 2;
|
|
14037
|
+
const off = (i + 1) * stride;
|
|
14038
|
+
vertexData[off + 0] = cx + Math.cos(angle) * radius;
|
|
14039
|
+
vertexData[off + 1] = cy + Math.sin(angle) * radius;
|
|
14040
|
+
vertexData[off + 2] = cz;
|
|
14041
|
+
vertexData[off + 3] = 0;
|
|
14042
|
+
vertexData[off + 4] = 0;
|
|
14043
|
+
vertexData[off + 5] = 1;
|
|
14044
|
+
}
|
|
14045
|
+
const indices = [];
|
|
14046
|
+
for (let i = 0; i < segments; i++) {
|
|
14047
|
+
indices.push(0, i + 1, (i + 1) % segments + 1);
|
|
14048
|
+
}
|
|
14049
|
+
const vertexBuffer = device.createBuffer({
|
|
14050
|
+
size: vertexData.byteLength,
|
|
14051
|
+
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
14052
|
+
});
|
|
14053
|
+
device.queue.writeBuffer(vertexBuffer, 0, vertexData);
|
|
14054
|
+
const indexData = new Uint16Array(indices);
|
|
14055
|
+
const alignedSize = Math.ceil(indexData.byteLength / 4) * 4;
|
|
14056
|
+
const alignedBuf = new Uint8Array(alignedSize);
|
|
14057
|
+
alignedBuf.set(
|
|
14058
|
+
new Uint8Array(indexData.buffer, indexData.byteOffset, indexData.byteLength)
|
|
14059
|
+
);
|
|
14060
|
+
const indexBuffer = device.createBuffer({
|
|
14061
|
+
size: alignedSize,
|
|
14062
|
+
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST
|
|
14063
|
+
});
|
|
14064
|
+
device.queue.writeBuffer(indexBuffer, 0, alignedBuf);
|
|
14065
|
+
const bbox = {
|
|
14066
|
+
min: [cx - radius, cy - radius, cz],
|
|
14067
|
+
max: [cx + radius, cy + radius, cz],
|
|
14068
|
+
center: [cx, cy, cz],
|
|
14069
|
+
radius
|
|
14070
|
+
};
|
|
14071
|
+
const mesh = new Mesh(vertexBuffer, vertexCount, indexBuffer, indices.length, bbox);
|
|
14072
|
+
mesh.hasUV = false;
|
|
14073
|
+
mesh.indexFormat = "uint16";
|
|
14074
|
+
const material = {
|
|
14075
|
+
baseColorFactor: [0.13, 0.59, 0.95, 1],
|
|
14076
|
+
baseColorTexture: null,
|
|
14077
|
+
metallicFactor: 0,
|
|
14078
|
+
roughnessFactor: 0.5,
|
|
14079
|
+
doubleSided: true
|
|
14080
|
+
};
|
|
14081
|
+
return { mesh, material };
|
|
14082
|
+
}
|
|
14002
14083
|
showIndicator() {
|
|
14003
14084
|
if (!this.indicatorMesh || this.indicatorAdded) return;
|
|
14004
14085
|
const material = {
|
|
@@ -14119,15 +14200,27 @@ class HotspotManager {
|
|
|
14119
14200
|
(firstBbox.min[2] + firstBbox.max[2]) / 2
|
|
14120
14201
|
];
|
|
14121
14202
|
}
|
|
14122
|
-
for (const { mesh
|
|
14203
|
+
for (const { mesh } of loadedMeshes) {
|
|
14123
14204
|
this.applyIndicatorTransform(mesh, snap);
|
|
14205
|
+
}
|
|
14206
|
+
let bgDiskMeshCount = 0;
|
|
14207
|
+
if (firstBbox) {
|
|
14208
|
+
const disk = this.createBackgroundDisk(firstBbox);
|
|
14209
|
+
disk.mesh.modelMatrix.set(loadedMeshes[0].mesh.modelMatrix);
|
|
14210
|
+
this.decomposeModelMatrix(disk.mesh);
|
|
14211
|
+
this.meshRenderer.addOverlayMesh(disk.mesh, disk.material);
|
|
14212
|
+
bgDiskMeshCount = 1;
|
|
14213
|
+
}
|
|
14214
|
+
for (const { mesh, material } of loadedMeshes) {
|
|
14215
|
+
material.unlit = true;
|
|
14124
14216
|
this.meshRenderer.addOverlayMesh(mesh, material);
|
|
14125
14217
|
}
|
|
14126
14218
|
const info = {
|
|
14127
14219
|
position: [...snap.point],
|
|
14128
14220
|
normal: [...snap.normal],
|
|
14129
14221
|
meshStartIndex,
|
|
14130
|
-
meshCount: loadedMeshes.length,
|
|
14222
|
+
meshCount: bgDiskMeshCount + loadedMeshes.length,
|
|
14223
|
+
bgDiskMeshCount,
|
|
14131
14224
|
billboard: false,
|
|
14132
14225
|
placedScale,
|
|
14133
14226
|
placedNormalOffset: snap.normalOffset,
|
|
@@ -14326,7 +14419,7 @@ class HotspotManager {
|
|
|
14326
14419
|
(firstBbox.min[2] + firstBbox.max[2]) / 2
|
|
14327
14420
|
];
|
|
14328
14421
|
}
|
|
14329
|
-
for (const { mesh
|
|
14422
|
+
for (const { mesh } of loadedMeshes) {
|
|
14330
14423
|
const bbox = mesh.getLocalBoundingBox();
|
|
14331
14424
|
let s = placedScale;
|
|
14332
14425
|
let lcx = 0, lcy = 0, lcz = 0;
|
|
@@ -14362,13 +14455,25 @@ class HotspotManager {
|
|
|
14362
14455
|
m[14] = position[2] + nz * normalOffset - owz;
|
|
14363
14456
|
m[15] = 1;
|
|
14364
14457
|
this.decomposeModelMatrix(mesh);
|
|
14458
|
+
}
|
|
14459
|
+
let bgDiskMeshCount = 0;
|
|
14460
|
+
if (firstBbox) {
|
|
14461
|
+
const disk = this.createBackgroundDisk(firstBbox);
|
|
14462
|
+
disk.mesh.modelMatrix.set(loadedMeshes[0].mesh.modelMatrix);
|
|
14463
|
+
this.decomposeModelMatrix(disk.mesh);
|
|
14464
|
+
this.meshRenderer.addOverlayMesh(disk.mesh, disk.material);
|
|
14465
|
+
bgDiskMeshCount = 1;
|
|
14466
|
+
}
|
|
14467
|
+
for (const { mesh, material } of loadedMeshes) {
|
|
14468
|
+
material.unlit = true;
|
|
14365
14469
|
this.meshRenderer.addOverlayMesh(mesh, material);
|
|
14366
14470
|
}
|
|
14367
14471
|
const info = {
|
|
14368
14472
|
position: [...position],
|
|
14369
14473
|
normal: [...normal],
|
|
14370
14474
|
meshStartIndex,
|
|
14371
|
-
meshCount: loadedMeshes.length,
|
|
14475
|
+
meshCount: bgDiskMeshCount + loadedMeshes.length,
|
|
14476
|
+
bgDiskMeshCount,
|
|
14372
14477
|
billboard: false,
|
|
14373
14478
|
placedScale,
|
|
14374
14479
|
placedNormalOffset: normalOffset,
|
|
@@ -16476,6 +16581,13 @@ class App {
|
|
|
16476
16581
|
getSplatScale() {
|
|
16477
16582
|
return this.sceneManager.getSplatScale();
|
|
16478
16583
|
}
|
|
16584
|
+
setSplatPivotToCenter() {
|
|
16585
|
+
const gsRenderer = this.sceneManager.getGSRenderer();
|
|
16586
|
+
if (!gsRenderer) return;
|
|
16587
|
+
const bbox = gsRenderer.getBoundingBox();
|
|
16588
|
+
if (!bbox) return;
|
|
16589
|
+
gsRenderer.setPivot(bbox.center[0], bbox.center[1], bbox.center[2]);
|
|
16590
|
+
}
|
|
16479
16591
|
// ============================================
|
|
16480
16592
|
// SH 模式
|
|
16481
16593
|
// ============================================
|