@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.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) {
|
|
@@ -13591,7 +13601,16 @@ class HotspotManager {
|
|
|
13591
13601
|
let closestIdx = -1;
|
|
13592
13602
|
for (let i = 0; i < this.hotspots.length; i++) {
|
|
13593
13603
|
const h = this.hotspots[i];
|
|
13594
|
-
|
|
13604
|
+
let px, py, pz;
|
|
13605
|
+
const firstMesh = this.meshRenderer.getOverlayMeshByIndex(h.meshStartIndex);
|
|
13606
|
+
if (firstMesh) {
|
|
13607
|
+
const m = firstMesh.modelMatrix;
|
|
13608
|
+
px = m[12];
|
|
13609
|
+
py = m[13];
|
|
13610
|
+
pz = m[14];
|
|
13611
|
+
} else {
|
|
13612
|
+
[px, py, pz] = h.position;
|
|
13613
|
+
}
|
|
13595
13614
|
const clipW = vp[3] * px + vp[7] * py + vp[11] * pz + vp[15];
|
|
13596
13615
|
if (clipW <= 0) continue;
|
|
13597
13616
|
const clipX = (vp[0] * px + vp[4] * py + vp[8] * pz + vp[12]) / clipW;
|
|
@@ -13999,6 +14018,77 @@ class HotspotManager {
|
|
|
13999
14018
|
this.indicatorMesh.hasUV = false;
|
|
14000
14019
|
this.indicatorMesh.indexFormat = "uint16";
|
|
14001
14020
|
}
|
|
14021
|
+
/**
|
|
14022
|
+
* 在 OBJ 本地坐标系中创建背景圆盘 Mesh,
|
|
14023
|
+
* 使其与 OBJ 图标共享同一 model matrix,billboard/缩放自动生效。
|
|
14024
|
+
*/
|
|
14025
|
+
createBackgroundDisk(objBbox) {
|
|
14026
|
+
const device = this.renderer.device;
|
|
14027
|
+
const segments = 48;
|
|
14028
|
+
const cx = (objBbox.min[0] + objBbox.max[0]) / 2;
|
|
14029
|
+
const cy = (objBbox.min[1] + objBbox.max[1]) / 2;
|
|
14030
|
+
const cz = Math.min(objBbox.min[2], objBbox.max[2]) - 5e-4;
|
|
14031
|
+
const dx = objBbox.max[0] - objBbox.min[0];
|
|
14032
|
+
const dy = objBbox.max[1] - objBbox.min[1];
|
|
14033
|
+
const maxDim2D = Math.max(dx, dy, 1e-6);
|
|
14034
|
+
const radius = maxDim2D * 0.85;
|
|
14035
|
+
const vertexCount = segments + 1;
|
|
14036
|
+
const stride = 6;
|
|
14037
|
+
const vertexData = new Float32Array(vertexCount * stride);
|
|
14038
|
+
vertexData[0] = cx;
|
|
14039
|
+
vertexData[1] = cy;
|
|
14040
|
+
vertexData[2] = cz;
|
|
14041
|
+
vertexData[3] = 0;
|
|
14042
|
+
vertexData[4] = 0;
|
|
14043
|
+
vertexData[5] = 1;
|
|
14044
|
+
for (let i = 0; i < segments; i++) {
|
|
14045
|
+
const angle = i / segments * Math.PI * 2;
|
|
14046
|
+
const off = (i + 1) * stride;
|
|
14047
|
+
vertexData[off + 0] = cx + Math.cos(angle) * radius;
|
|
14048
|
+
vertexData[off + 1] = cy + Math.sin(angle) * radius;
|
|
14049
|
+
vertexData[off + 2] = cz;
|
|
14050
|
+
vertexData[off + 3] = 0;
|
|
14051
|
+
vertexData[off + 4] = 0;
|
|
14052
|
+
vertexData[off + 5] = 1;
|
|
14053
|
+
}
|
|
14054
|
+
const indices = [];
|
|
14055
|
+
for (let i = 0; i < segments; i++) {
|
|
14056
|
+
indices.push(0, i + 1, (i + 1) % segments + 1);
|
|
14057
|
+
}
|
|
14058
|
+
const vertexBuffer = device.createBuffer({
|
|
14059
|
+
size: vertexData.byteLength,
|
|
14060
|
+
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
14061
|
+
});
|
|
14062
|
+
device.queue.writeBuffer(vertexBuffer, 0, vertexData);
|
|
14063
|
+
const indexData = new Uint16Array(indices);
|
|
14064
|
+
const alignedSize = Math.ceil(indexData.byteLength / 4) * 4;
|
|
14065
|
+
const alignedBuf = new Uint8Array(alignedSize);
|
|
14066
|
+
alignedBuf.set(
|
|
14067
|
+
new Uint8Array(indexData.buffer, indexData.byteOffset, indexData.byteLength)
|
|
14068
|
+
);
|
|
14069
|
+
const indexBuffer = device.createBuffer({
|
|
14070
|
+
size: alignedSize,
|
|
14071
|
+
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST
|
|
14072
|
+
});
|
|
14073
|
+
device.queue.writeBuffer(indexBuffer, 0, alignedBuf);
|
|
14074
|
+
const bbox = {
|
|
14075
|
+
min: [cx - radius, cy - radius, cz],
|
|
14076
|
+
max: [cx + radius, cy + radius, cz],
|
|
14077
|
+
center: [cx, cy, cz],
|
|
14078
|
+
radius
|
|
14079
|
+
};
|
|
14080
|
+
const mesh = new Mesh(vertexBuffer, vertexCount, indexBuffer, indices.length, bbox);
|
|
14081
|
+
mesh.hasUV = false;
|
|
14082
|
+
mesh.indexFormat = "uint16";
|
|
14083
|
+
const material = {
|
|
14084
|
+
baseColorFactor: [0.13, 0.59, 0.95, 1],
|
|
14085
|
+
baseColorTexture: null,
|
|
14086
|
+
metallicFactor: 0,
|
|
14087
|
+
roughnessFactor: 0.5,
|
|
14088
|
+
doubleSided: true
|
|
14089
|
+
};
|
|
14090
|
+
return { mesh, material };
|
|
14091
|
+
}
|
|
14002
14092
|
showIndicator() {
|
|
14003
14093
|
if (!this.indicatorMesh || this.indicatorAdded) return;
|
|
14004
14094
|
const material = {
|
|
@@ -14119,15 +14209,27 @@ class HotspotManager {
|
|
|
14119
14209
|
(firstBbox.min[2] + firstBbox.max[2]) / 2
|
|
14120
14210
|
];
|
|
14121
14211
|
}
|
|
14122
|
-
for (const { mesh
|
|
14212
|
+
for (const { mesh } of loadedMeshes) {
|
|
14123
14213
|
this.applyIndicatorTransform(mesh, snap);
|
|
14214
|
+
}
|
|
14215
|
+
let bgDiskMeshCount = 0;
|
|
14216
|
+
if (firstBbox) {
|
|
14217
|
+
const disk = this.createBackgroundDisk(firstBbox);
|
|
14218
|
+
disk.mesh.modelMatrix.set(loadedMeshes[0].mesh.modelMatrix);
|
|
14219
|
+
this.decomposeModelMatrix(disk.mesh);
|
|
14220
|
+
this.meshRenderer.addOverlayMesh(disk.mesh, disk.material);
|
|
14221
|
+
bgDiskMeshCount = 1;
|
|
14222
|
+
}
|
|
14223
|
+
for (const { mesh, material } of loadedMeshes) {
|
|
14224
|
+
material.unlit = true;
|
|
14124
14225
|
this.meshRenderer.addOverlayMesh(mesh, material);
|
|
14125
14226
|
}
|
|
14126
14227
|
const info = {
|
|
14127
14228
|
position: [...snap.point],
|
|
14128
14229
|
normal: [...snap.normal],
|
|
14129
14230
|
meshStartIndex,
|
|
14130
|
-
meshCount: loadedMeshes.length,
|
|
14231
|
+
meshCount: bgDiskMeshCount + loadedMeshes.length,
|
|
14232
|
+
bgDiskMeshCount,
|
|
14131
14233
|
billboard: false,
|
|
14132
14234
|
placedScale,
|
|
14133
14235
|
placedNormalOffset: snap.normalOffset,
|
|
@@ -14326,7 +14428,7 @@ class HotspotManager {
|
|
|
14326
14428
|
(firstBbox.min[2] + firstBbox.max[2]) / 2
|
|
14327
14429
|
];
|
|
14328
14430
|
}
|
|
14329
|
-
for (const { mesh
|
|
14431
|
+
for (const { mesh } of loadedMeshes) {
|
|
14330
14432
|
const bbox = mesh.getLocalBoundingBox();
|
|
14331
14433
|
let s = placedScale;
|
|
14332
14434
|
let lcx = 0, lcy = 0, lcz = 0;
|
|
@@ -14362,13 +14464,25 @@ class HotspotManager {
|
|
|
14362
14464
|
m[14] = position[2] + nz * normalOffset - owz;
|
|
14363
14465
|
m[15] = 1;
|
|
14364
14466
|
this.decomposeModelMatrix(mesh);
|
|
14467
|
+
}
|
|
14468
|
+
let bgDiskMeshCount = 0;
|
|
14469
|
+
if (firstBbox) {
|
|
14470
|
+
const disk = this.createBackgroundDisk(firstBbox);
|
|
14471
|
+
disk.mesh.modelMatrix.set(loadedMeshes[0].mesh.modelMatrix);
|
|
14472
|
+
this.decomposeModelMatrix(disk.mesh);
|
|
14473
|
+
this.meshRenderer.addOverlayMesh(disk.mesh, disk.material);
|
|
14474
|
+
bgDiskMeshCount = 1;
|
|
14475
|
+
}
|
|
14476
|
+
for (const { mesh, material } of loadedMeshes) {
|
|
14477
|
+
material.unlit = true;
|
|
14365
14478
|
this.meshRenderer.addOverlayMesh(mesh, material);
|
|
14366
14479
|
}
|
|
14367
14480
|
const info = {
|
|
14368
14481
|
position: [...position],
|
|
14369
14482
|
normal: [...normal],
|
|
14370
14483
|
meshStartIndex,
|
|
14371
|
-
meshCount: loadedMeshes.length,
|
|
14484
|
+
meshCount: bgDiskMeshCount + loadedMeshes.length,
|
|
14485
|
+
bgDiskMeshCount,
|
|
14372
14486
|
billboard: false,
|
|
14373
14487
|
placedScale,
|
|
14374
14488
|
placedNormalOffset: normalOffset,
|