@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 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) {
@@ -14001,6 +14011,77 @@ class HotspotManager {
14001
14011
  this.indicatorMesh.hasUV = false;
14002
14012
  this.indicatorMesh.indexFormat = "uint16";
14003
14013
  }
14014
+ /**
14015
+ * 在 OBJ 本地坐标系中创建背景圆盘 Mesh,
14016
+ * 使其与 OBJ 图标共享同一 model matrix,billboard/缩放自动生效。
14017
+ */
14018
+ createBackgroundDisk(objBbox) {
14019
+ const device = this.renderer.device;
14020
+ const segments = 48;
14021
+ const cx = (objBbox.min[0] + objBbox.max[0]) / 2;
14022
+ const cy = (objBbox.min[1] + objBbox.max[1]) / 2;
14023
+ const cz = Math.min(objBbox.min[2], objBbox.max[2]) - 5e-4;
14024
+ const dx = objBbox.max[0] - objBbox.min[0];
14025
+ const dy = objBbox.max[1] - objBbox.min[1];
14026
+ const maxDim2D = Math.max(dx, dy, 1e-6);
14027
+ const radius = maxDim2D * 0.85;
14028
+ const vertexCount = segments + 1;
14029
+ const stride = 6;
14030
+ const vertexData = new Float32Array(vertexCount * stride);
14031
+ vertexData[0] = cx;
14032
+ vertexData[1] = cy;
14033
+ vertexData[2] = cz;
14034
+ vertexData[3] = 0;
14035
+ vertexData[4] = 0;
14036
+ vertexData[5] = 1;
14037
+ for (let i = 0; i < segments; i++) {
14038
+ const angle = i / segments * Math.PI * 2;
14039
+ const off = (i + 1) * stride;
14040
+ vertexData[off + 0] = cx + Math.cos(angle) * radius;
14041
+ vertexData[off + 1] = cy + Math.sin(angle) * radius;
14042
+ vertexData[off + 2] = cz;
14043
+ vertexData[off + 3] = 0;
14044
+ vertexData[off + 4] = 0;
14045
+ vertexData[off + 5] = 1;
14046
+ }
14047
+ const indices = [];
14048
+ for (let i = 0; i < segments; i++) {
14049
+ indices.push(0, i + 1, (i + 1) % segments + 1);
14050
+ }
14051
+ const vertexBuffer = device.createBuffer({
14052
+ size: vertexData.byteLength,
14053
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
14054
+ });
14055
+ device.queue.writeBuffer(vertexBuffer, 0, vertexData);
14056
+ const indexData = new Uint16Array(indices);
14057
+ const alignedSize = Math.ceil(indexData.byteLength / 4) * 4;
14058
+ const alignedBuf = new Uint8Array(alignedSize);
14059
+ alignedBuf.set(
14060
+ new Uint8Array(indexData.buffer, indexData.byteOffset, indexData.byteLength)
14061
+ );
14062
+ const indexBuffer = device.createBuffer({
14063
+ size: alignedSize,
14064
+ usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST
14065
+ });
14066
+ device.queue.writeBuffer(indexBuffer, 0, alignedBuf);
14067
+ const bbox = {
14068
+ min: [cx - radius, cy - radius, cz],
14069
+ max: [cx + radius, cy + radius, cz],
14070
+ center: [cx, cy, cz],
14071
+ radius
14072
+ };
14073
+ const mesh = new Mesh(vertexBuffer, vertexCount, indexBuffer, indices.length, bbox);
14074
+ mesh.hasUV = false;
14075
+ mesh.indexFormat = "uint16";
14076
+ const material = {
14077
+ baseColorFactor: [0.13, 0.59, 0.95, 1],
14078
+ baseColorTexture: null,
14079
+ metallicFactor: 0,
14080
+ roughnessFactor: 0.5,
14081
+ doubleSided: true
14082
+ };
14083
+ return { mesh, material };
14084
+ }
14004
14085
  showIndicator() {
14005
14086
  if (!this.indicatorMesh || this.indicatorAdded) return;
14006
14087
  const material = {
@@ -14121,15 +14202,27 @@ class HotspotManager {
14121
14202
  (firstBbox.min[2] + firstBbox.max[2]) / 2
14122
14203
  ];
14123
14204
  }
14124
- for (const { mesh, material } of loadedMeshes) {
14205
+ for (const { mesh } of loadedMeshes) {
14125
14206
  this.applyIndicatorTransform(mesh, snap);
14207
+ }
14208
+ let bgDiskMeshCount = 0;
14209
+ if (firstBbox) {
14210
+ const disk = this.createBackgroundDisk(firstBbox);
14211
+ disk.mesh.modelMatrix.set(loadedMeshes[0].mesh.modelMatrix);
14212
+ this.decomposeModelMatrix(disk.mesh);
14213
+ this.meshRenderer.addOverlayMesh(disk.mesh, disk.material);
14214
+ bgDiskMeshCount = 1;
14215
+ }
14216
+ for (const { mesh, material } of loadedMeshes) {
14217
+ material.unlit = true;
14126
14218
  this.meshRenderer.addOverlayMesh(mesh, material);
14127
14219
  }
14128
14220
  const info = {
14129
14221
  position: [...snap.point],
14130
14222
  normal: [...snap.normal],
14131
14223
  meshStartIndex,
14132
- meshCount: loadedMeshes.length,
14224
+ meshCount: bgDiskMeshCount + loadedMeshes.length,
14225
+ bgDiskMeshCount,
14133
14226
  billboard: false,
14134
14227
  placedScale,
14135
14228
  placedNormalOffset: snap.normalOffset,
@@ -14328,7 +14421,7 @@ class HotspotManager {
14328
14421
  (firstBbox.min[2] + firstBbox.max[2]) / 2
14329
14422
  ];
14330
14423
  }
14331
- for (const { mesh, material } of loadedMeshes) {
14424
+ for (const { mesh } of loadedMeshes) {
14332
14425
  const bbox = mesh.getLocalBoundingBox();
14333
14426
  let s = placedScale;
14334
14427
  let lcx = 0, lcy = 0, lcz = 0;
@@ -14364,13 +14457,25 @@ class HotspotManager {
14364
14457
  m[14] = position[2] + nz * normalOffset - owz;
14365
14458
  m[15] = 1;
14366
14459
  this.decomposeModelMatrix(mesh);
14460
+ }
14461
+ let bgDiskMeshCount = 0;
14462
+ if (firstBbox) {
14463
+ const disk = this.createBackgroundDisk(firstBbox);
14464
+ disk.mesh.modelMatrix.set(loadedMeshes[0].mesh.modelMatrix);
14465
+ this.decomposeModelMatrix(disk.mesh);
14466
+ this.meshRenderer.addOverlayMesh(disk.mesh, disk.material);
14467
+ bgDiskMeshCount = 1;
14468
+ }
14469
+ for (const { mesh, material } of loadedMeshes) {
14470
+ material.unlit = true;
14367
14471
  this.meshRenderer.addOverlayMesh(mesh, material);
14368
14472
  }
14369
14473
  const info = {
14370
14474
  position: [...position],
14371
14475
  normal: [...normal],
14372
14476
  meshStartIndex,
14373
- meshCount: loadedMeshes.length,
14477
+ meshCount: bgDiskMeshCount + loadedMeshes.length,
14478
+ bgDiskMeshCount,
14374
14479
  billboard: false,
14375
14480
  placedScale,
14376
14481
  placedNormalOffset: normalOffset,
@@ -16478,6 +16583,13 @@ class App {
16478
16583
  getSplatScale() {
16479
16584
  return this.sceneManager.getSplatScale();
16480
16585
  }
16586
+ setSplatPivotToCenter() {
16587
+ const gsRenderer = this.sceneManager.getGSRenderer();
16588
+ if (!gsRenderer) return;
16589
+ const bbox = gsRenderer.getBoundingBox();
16590
+ if (!bbox) return;
16591
+ gsRenderer.setPivot(bbox.center[0], bbox.center[1], bbox.center[2]);
16592
+ }
16481
16593
  // ============================================
16482
16594
  // SH 模式
16483
16595
  // ============================================