@d5techs/3dgs-lib 1.4.12 → 1.4.14
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 +123 -9
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +123 -9
- package/dist/3dgs-lib.js.map +1 -1
- 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.cjs
CHANGED
|
@@ -2476,10 +2476,16 @@ class MeshRenderer {
|
|
|
2476
2476
|
this.lightDir[2],
|
|
2477
2477
|
this.ambientIntensity
|
|
2478
2478
|
]);
|
|
2479
|
-
|
|
2480
|
-
|
|
2479
|
+
const unlitLightData = new Float32Array([
|
|
2480
|
+
this.lightDir[0],
|
|
2481
|
+
this.lightDir[1],
|
|
2482
|
+
this.lightDir[2],
|
|
2483
|
+
1
|
|
2484
|
+
]);
|
|
2485
|
+
this.renderItems(pass, this.items, device, vpMatrix, lightData, unlitLightData, false);
|
|
2486
|
+
this.renderItems(pass, this.overlayItems, device, vpMatrix, lightData, unlitLightData, true);
|
|
2481
2487
|
}
|
|
2482
|
-
renderItems(pass, items, device, vpMatrix, lightData, overlay) {
|
|
2488
|
+
renderItems(pass, items, device, vpMatrix, lightData, unlitLightData, overlay) {
|
|
2483
2489
|
if (items.length === 0) return;
|
|
2484
2490
|
for (const item of items) {
|
|
2485
2491
|
const { mesh, material, uniformBuffer, bindGroup } = item;
|
|
@@ -2487,7 +2493,11 @@ class MeshRenderer {
|
|
|
2487
2493
|
device.queue.writeBuffer(uniformBuffer, 64, mesh.modelMatrix.buffer);
|
|
2488
2494
|
const colorData = new Float32Array(material.baseColorFactor);
|
|
2489
2495
|
device.queue.writeBuffer(uniformBuffer, 128, colorData.buffer);
|
|
2490
|
-
|
|
2496
|
+
if (material.unlit) {
|
|
2497
|
+
device.queue.writeBuffer(uniformBuffer, 144, unlitLightData.buffer);
|
|
2498
|
+
} else {
|
|
2499
|
+
device.queue.writeBuffer(uniformBuffer, 144, lightData.buffer);
|
|
2500
|
+
}
|
|
2491
2501
|
let pipeline;
|
|
2492
2502
|
if (overlay) {
|
|
2493
2503
|
if (mesh.hasUV) {
|
|
@@ -13593,7 +13603,16 @@ class HotspotManager {
|
|
|
13593
13603
|
let closestIdx = -1;
|
|
13594
13604
|
for (let i = 0; i < this.hotspots.length; i++) {
|
|
13595
13605
|
const h = this.hotspots[i];
|
|
13596
|
-
|
|
13606
|
+
let px, py, pz;
|
|
13607
|
+
const firstMesh = this.meshRenderer.getOverlayMeshByIndex(h.meshStartIndex);
|
|
13608
|
+
if (firstMesh) {
|
|
13609
|
+
const m = firstMesh.modelMatrix;
|
|
13610
|
+
px = m[12];
|
|
13611
|
+
py = m[13];
|
|
13612
|
+
pz = m[14];
|
|
13613
|
+
} else {
|
|
13614
|
+
[px, py, pz] = h.position;
|
|
13615
|
+
}
|
|
13597
13616
|
const clipW = vp[3] * px + vp[7] * py + vp[11] * pz + vp[15];
|
|
13598
13617
|
if (clipW <= 0) continue;
|
|
13599
13618
|
const clipX = (vp[0] * px + vp[4] * py + vp[8] * pz + vp[12]) / clipW;
|
|
@@ -14001,6 +14020,77 @@ class HotspotManager {
|
|
|
14001
14020
|
this.indicatorMesh.hasUV = false;
|
|
14002
14021
|
this.indicatorMesh.indexFormat = "uint16";
|
|
14003
14022
|
}
|
|
14023
|
+
/**
|
|
14024
|
+
* 在 OBJ 本地坐标系中创建背景圆盘 Mesh,
|
|
14025
|
+
* 使其与 OBJ 图标共享同一 model matrix,billboard/缩放自动生效。
|
|
14026
|
+
*/
|
|
14027
|
+
createBackgroundDisk(objBbox) {
|
|
14028
|
+
const device = this.renderer.device;
|
|
14029
|
+
const segments = 48;
|
|
14030
|
+
const cx = (objBbox.min[0] + objBbox.max[0]) / 2;
|
|
14031
|
+
const cy = (objBbox.min[1] + objBbox.max[1]) / 2;
|
|
14032
|
+
const cz = Math.min(objBbox.min[2], objBbox.max[2]) - 5e-4;
|
|
14033
|
+
const dx = objBbox.max[0] - objBbox.min[0];
|
|
14034
|
+
const dy = objBbox.max[1] - objBbox.min[1];
|
|
14035
|
+
const maxDim2D = Math.max(dx, dy, 1e-6);
|
|
14036
|
+
const radius = maxDim2D * 0.85;
|
|
14037
|
+
const vertexCount = segments + 1;
|
|
14038
|
+
const stride = 6;
|
|
14039
|
+
const vertexData = new Float32Array(vertexCount * stride);
|
|
14040
|
+
vertexData[0] = cx;
|
|
14041
|
+
vertexData[1] = cy;
|
|
14042
|
+
vertexData[2] = cz;
|
|
14043
|
+
vertexData[3] = 0;
|
|
14044
|
+
vertexData[4] = 0;
|
|
14045
|
+
vertexData[5] = 1;
|
|
14046
|
+
for (let i = 0; i < segments; i++) {
|
|
14047
|
+
const angle = i / segments * Math.PI * 2;
|
|
14048
|
+
const off = (i + 1) * stride;
|
|
14049
|
+
vertexData[off + 0] = cx + Math.cos(angle) * radius;
|
|
14050
|
+
vertexData[off + 1] = cy + Math.sin(angle) * radius;
|
|
14051
|
+
vertexData[off + 2] = cz;
|
|
14052
|
+
vertexData[off + 3] = 0;
|
|
14053
|
+
vertexData[off + 4] = 0;
|
|
14054
|
+
vertexData[off + 5] = 1;
|
|
14055
|
+
}
|
|
14056
|
+
const indices = [];
|
|
14057
|
+
for (let i = 0; i < segments; i++) {
|
|
14058
|
+
indices.push(0, i + 1, (i + 1) % segments + 1);
|
|
14059
|
+
}
|
|
14060
|
+
const vertexBuffer = device.createBuffer({
|
|
14061
|
+
size: vertexData.byteLength,
|
|
14062
|
+
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
14063
|
+
});
|
|
14064
|
+
device.queue.writeBuffer(vertexBuffer, 0, vertexData);
|
|
14065
|
+
const indexData = new Uint16Array(indices);
|
|
14066
|
+
const alignedSize = Math.ceil(indexData.byteLength / 4) * 4;
|
|
14067
|
+
const alignedBuf = new Uint8Array(alignedSize);
|
|
14068
|
+
alignedBuf.set(
|
|
14069
|
+
new Uint8Array(indexData.buffer, indexData.byteOffset, indexData.byteLength)
|
|
14070
|
+
);
|
|
14071
|
+
const indexBuffer = device.createBuffer({
|
|
14072
|
+
size: alignedSize,
|
|
14073
|
+
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST
|
|
14074
|
+
});
|
|
14075
|
+
device.queue.writeBuffer(indexBuffer, 0, alignedBuf);
|
|
14076
|
+
const bbox = {
|
|
14077
|
+
min: [cx - radius, cy - radius, cz],
|
|
14078
|
+
max: [cx + radius, cy + radius, cz],
|
|
14079
|
+
center: [cx, cy, cz],
|
|
14080
|
+
radius
|
|
14081
|
+
};
|
|
14082
|
+
const mesh = new Mesh(vertexBuffer, vertexCount, indexBuffer, indices.length, bbox);
|
|
14083
|
+
mesh.hasUV = false;
|
|
14084
|
+
mesh.indexFormat = "uint16";
|
|
14085
|
+
const material = {
|
|
14086
|
+
baseColorFactor: [0.13, 0.59, 0.95, 1],
|
|
14087
|
+
baseColorTexture: null,
|
|
14088
|
+
metallicFactor: 0,
|
|
14089
|
+
roughnessFactor: 0.5,
|
|
14090
|
+
doubleSided: true
|
|
14091
|
+
};
|
|
14092
|
+
return { mesh, material };
|
|
14093
|
+
}
|
|
14004
14094
|
showIndicator() {
|
|
14005
14095
|
if (!this.indicatorMesh || this.indicatorAdded) return;
|
|
14006
14096
|
const material = {
|
|
@@ -14121,15 +14211,27 @@ class HotspotManager {
|
|
|
14121
14211
|
(firstBbox.min[2] + firstBbox.max[2]) / 2
|
|
14122
14212
|
];
|
|
14123
14213
|
}
|
|
14124
|
-
for (const { mesh
|
|
14214
|
+
for (const { mesh } of loadedMeshes) {
|
|
14125
14215
|
this.applyIndicatorTransform(mesh, snap);
|
|
14216
|
+
}
|
|
14217
|
+
let bgDiskMeshCount = 0;
|
|
14218
|
+
if (firstBbox) {
|
|
14219
|
+
const disk = this.createBackgroundDisk(firstBbox);
|
|
14220
|
+
disk.mesh.modelMatrix.set(loadedMeshes[0].mesh.modelMatrix);
|
|
14221
|
+
this.decomposeModelMatrix(disk.mesh);
|
|
14222
|
+
this.meshRenderer.addOverlayMesh(disk.mesh, disk.material);
|
|
14223
|
+
bgDiskMeshCount = 1;
|
|
14224
|
+
}
|
|
14225
|
+
for (const { mesh, material } of loadedMeshes) {
|
|
14226
|
+
material.unlit = true;
|
|
14126
14227
|
this.meshRenderer.addOverlayMesh(mesh, material);
|
|
14127
14228
|
}
|
|
14128
14229
|
const info = {
|
|
14129
14230
|
position: [...snap.point],
|
|
14130
14231
|
normal: [...snap.normal],
|
|
14131
14232
|
meshStartIndex,
|
|
14132
|
-
meshCount: loadedMeshes.length,
|
|
14233
|
+
meshCount: bgDiskMeshCount + loadedMeshes.length,
|
|
14234
|
+
bgDiskMeshCount,
|
|
14133
14235
|
billboard: false,
|
|
14134
14236
|
placedScale,
|
|
14135
14237
|
placedNormalOffset: snap.normalOffset,
|
|
@@ -14328,7 +14430,7 @@ class HotspotManager {
|
|
|
14328
14430
|
(firstBbox.min[2] + firstBbox.max[2]) / 2
|
|
14329
14431
|
];
|
|
14330
14432
|
}
|
|
14331
|
-
for (const { mesh
|
|
14433
|
+
for (const { mesh } of loadedMeshes) {
|
|
14332
14434
|
const bbox = mesh.getLocalBoundingBox();
|
|
14333
14435
|
let s = placedScale;
|
|
14334
14436
|
let lcx = 0, lcy = 0, lcz = 0;
|
|
@@ -14364,13 +14466,25 @@ class HotspotManager {
|
|
|
14364
14466
|
m[14] = position[2] + nz * normalOffset - owz;
|
|
14365
14467
|
m[15] = 1;
|
|
14366
14468
|
this.decomposeModelMatrix(mesh);
|
|
14469
|
+
}
|
|
14470
|
+
let bgDiskMeshCount = 0;
|
|
14471
|
+
if (firstBbox) {
|
|
14472
|
+
const disk = this.createBackgroundDisk(firstBbox);
|
|
14473
|
+
disk.mesh.modelMatrix.set(loadedMeshes[0].mesh.modelMatrix);
|
|
14474
|
+
this.decomposeModelMatrix(disk.mesh);
|
|
14475
|
+
this.meshRenderer.addOverlayMesh(disk.mesh, disk.material);
|
|
14476
|
+
bgDiskMeshCount = 1;
|
|
14477
|
+
}
|
|
14478
|
+
for (const { mesh, material } of loadedMeshes) {
|
|
14479
|
+
material.unlit = true;
|
|
14367
14480
|
this.meshRenderer.addOverlayMesh(mesh, material);
|
|
14368
14481
|
}
|
|
14369
14482
|
const info = {
|
|
14370
14483
|
position: [...position],
|
|
14371
14484
|
normal: [...normal],
|
|
14372
14485
|
meshStartIndex,
|
|
14373
|
-
meshCount: loadedMeshes.length,
|
|
14486
|
+
meshCount: bgDiskMeshCount + loadedMeshes.length,
|
|
14487
|
+
bgDiskMeshCount,
|
|
14374
14488
|
billboard: false,
|
|
14375
14489
|
placedScale,
|
|
14376
14490
|
placedNormalOffset: normalOffset,
|