@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 CHANGED
@@ -2476,10 +2476,16 @@ class MeshRenderer {
2476
2476
  this.lightDir[2],
2477
2477
  this.ambientIntensity
2478
2478
  ]);
2479
- this.renderItems(pass, this.items, device, vpMatrix, lightData, false);
2480
- this.renderItems(pass, this.overlayItems, device, vpMatrix, lightData, true);
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
- device.queue.writeBuffer(uniformBuffer, 144, lightData.buffer);
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
- const [px, py, pz] = h.position;
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, material } of loadedMeshes) {
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, material } of loadedMeshes) {
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,