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