@d5techs/3dgs-lib 1.4.74 → 1.4.76
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 +532 -222
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +532 -222
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +7 -0
- package/dist/editor/SelectionVolumeRenderer.d.ts +32 -0
- package/dist/editor/SplatEditor.d.ts +42 -6
- package/dist/editor/index.d.ts +2 -0
- package/dist/editor/tools/BoxSelection.d.ts +18 -18
- package/dist/editor/tools/SphereSelection.d.ts +11 -15
- package/dist/index.d.ts +2 -0
- package/package.json +1 -1
package/dist/3dgs-lib.cjs
CHANGED
|
@@ -811,6 +811,7 @@ const _OrbitControls = class _OrbitControls {
|
|
|
811
811
|
onKeyDown(e) {
|
|
812
812
|
var _a2;
|
|
813
813
|
if (!this.enabled) return;
|
|
814
|
+
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
814
815
|
const tag = (_a2 = e.target) == null ? void 0 : _a2.tagName;
|
|
815
816
|
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
|
|
816
817
|
const key = e.key.toLowerCase();
|
|
@@ -17567,213 +17568,212 @@ class EyedropperSelection {
|
|
|
17567
17568
|
}
|
|
17568
17569
|
}
|
|
17569
17570
|
class SphereSelection {
|
|
17570
|
-
constructor(parent,
|
|
17571
|
+
constructor(parent, callbacks) {
|
|
17571
17572
|
__publicField(this, "parent");
|
|
17572
|
-
__publicField(this, "
|
|
17573
|
-
__publicField(this, "
|
|
17574
|
-
__publicField(this, "
|
|
17575
|
-
__publicField(this, "
|
|
17576
|
-
__publicField(this, "radiusPx", 0);
|
|
17577
|
-
__publicField(this, "dragId");
|
|
17573
|
+
__publicField(this, "toolbar");
|
|
17574
|
+
__publicField(this, "callbacks");
|
|
17575
|
+
__publicField(this, "_radius", 1);
|
|
17576
|
+
__publicField(this, "radiusInput");
|
|
17578
17577
|
this.parent = parent;
|
|
17579
|
-
this.
|
|
17580
|
-
this.
|
|
17581
|
-
this.
|
|
17582
|
-
this.
|
|
17583
|
-
|
|
17584
|
-
|
|
17585
|
-
|
|
17586
|
-
|
|
17587
|
-
|
|
17588
|
-
|
|
17589
|
-
|
|
17590
|
-
this.
|
|
17591
|
-
this.
|
|
17592
|
-
|
|
17593
|
-
|
|
17594
|
-
|
|
17595
|
-
|
|
17596
|
-
|
|
17597
|
-
|
|
17598
|
-
|
|
17599
|
-
|
|
17600
|
-
|
|
17601
|
-
|
|
17602
|
-
|
|
17603
|
-
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
|
|
17610
|
-
|
|
17611
|
-
|
|
17612
|
-
|
|
17613
|
-
|
|
17614
|
-
|
|
17615
|
-
|
|
17616
|
-
|
|
17578
|
+
this.callbacks = callbacks;
|
|
17579
|
+
this.toolbar = document.createElement("div");
|
|
17580
|
+
this.toolbar.className = "volume-select-toolbar";
|
|
17581
|
+
this.toolbar.style.cssText = `
|
|
17582
|
+
position:absolute; bottom:12px; left:50%; transform:translateX(-50%);
|
|
17583
|
+
display:none; z-index:20; background:rgba(30,30,30,0.92);
|
|
17584
|
+
border-radius:8px; padding:6px 10px; gap:6px;
|
|
17585
|
+
align-items:center; font-size:13px; color:#ddd;
|
|
17586
|
+
backdrop-filter:blur(6px); user-select:none; white-space:nowrap;
|
|
17587
|
+
box-shadow:0 2px 12px rgba(0,0,0,0.4);
|
|
17588
|
+
`;
|
|
17589
|
+
this.toolbar.addEventListener("pointerdown", (e) => e.stopPropagation());
|
|
17590
|
+
this.toolbar.addEventListener("wheel", (e) => e.stopPropagation());
|
|
17591
|
+
const mkBtn = (label2, op) => {
|
|
17592
|
+
const btn = document.createElement("button");
|
|
17593
|
+
btn.textContent = label2;
|
|
17594
|
+
btn.style.cssText = `
|
|
17595
|
+
padding:4px 12px; border:1px solid #555; border-radius:4px;
|
|
17596
|
+
background:#333; color:#ddd; cursor:pointer; font-size:13px;
|
|
17597
|
+
transition: background 0.15s;
|
|
17598
|
+
`;
|
|
17599
|
+
btn.addEventListener("mouseenter", () => {
|
|
17600
|
+
btn.style.background = "#555";
|
|
17601
|
+
});
|
|
17602
|
+
btn.addEventListener("mouseleave", () => {
|
|
17603
|
+
btn.style.background = "#333";
|
|
17604
|
+
});
|
|
17605
|
+
btn.addEventListener("pointerdown", (e) => {
|
|
17606
|
+
e.stopPropagation();
|
|
17607
|
+
this.callbacks.onApply(op);
|
|
17608
|
+
});
|
|
17609
|
+
return btn;
|
|
17610
|
+
};
|
|
17611
|
+
const setBtn = mkBtn("Set", "set");
|
|
17612
|
+
const addBtn = mkBtn("Add", "add");
|
|
17613
|
+
const removeBtn = mkBtn("Remove", "remove");
|
|
17614
|
+
const inputWrap = document.createElement("span");
|
|
17615
|
+
inputWrap.style.cssText = "display:inline-flex; align-items:center; gap:2px;";
|
|
17616
|
+
const input = document.createElement("input");
|
|
17617
|
+
input.type = "number";
|
|
17618
|
+
input.min = "0.01";
|
|
17619
|
+
input.step = "0.1";
|
|
17620
|
+
input.value = this._radius.toFixed(2);
|
|
17621
|
+
input.style.cssText = `
|
|
17622
|
+
width:50px; padding:3px 4px; border:1px solid #555; border-radius:4px;
|
|
17623
|
+
background:#222; color:#ddd; font-size:12px; text-align:center;
|
|
17624
|
+
`;
|
|
17625
|
+
const label = document.createElement("span");
|
|
17626
|
+
label.textContent = "Radius";
|
|
17627
|
+
label.style.cssText = "color:#888; font-size:11px;";
|
|
17628
|
+
input.addEventListener("change", () => {
|
|
17629
|
+
const v = Math.max(0.01, parseFloat(input.value) || 0.01);
|
|
17630
|
+
input.value = v.toFixed(2);
|
|
17631
|
+
this._radius = v;
|
|
17632
|
+
this.callbacks.onRadiusChanged(v);
|
|
17633
|
+
});
|
|
17634
|
+
inputWrap.appendChild(input);
|
|
17635
|
+
inputWrap.appendChild(label);
|
|
17636
|
+
this.radiusInput = input;
|
|
17637
|
+
this.toolbar.appendChild(setBtn);
|
|
17638
|
+
this.toolbar.appendChild(addBtn);
|
|
17639
|
+
this.toolbar.appendChild(removeBtn);
|
|
17640
|
+
this.toolbar.appendChild(inputWrap);
|
|
17641
|
+
parent.appendChild(this.toolbar);
|
|
17617
17642
|
}
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
if (e.pointerType === "mouse" ? e.button !== 0 : !e.isPrimary) return;
|
|
17621
|
-
e.preventDefault();
|
|
17622
|
-
e.stopPropagation();
|
|
17623
|
-
this.dragId = e.pointerId;
|
|
17624
|
-
this.parent.setPointerCapture(this.dragId);
|
|
17625
|
-
this.center.x = e.offsetX;
|
|
17626
|
-
this.center.y = e.offsetY;
|
|
17627
|
-
this.radiusPx = 0;
|
|
17628
|
-
this.updateCircle();
|
|
17629
|
-
this.circle.style.display = "block";
|
|
17643
|
+
get radius() {
|
|
17644
|
+
return this._radius;
|
|
17630
17645
|
}
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
e.stopPropagation();
|
|
17635
|
-
const dx = e.offsetX - this.center.x;
|
|
17636
|
-
const dy = e.offsetY - this.center.y;
|
|
17637
|
-
this.radiusPx = Math.sqrt(dx * dx + dy * dy);
|
|
17638
|
-
this.updateCircle();
|
|
17646
|
+
setRadius(radius) {
|
|
17647
|
+
this._radius = radius;
|
|
17648
|
+
this.radiusInput.value = radius.toFixed(2);
|
|
17639
17649
|
}
|
|
17640
|
-
|
|
17641
|
-
|
|
17642
|
-
this.parent.releasePointerCapture(this.dragId);
|
|
17643
|
-
this.dragId = void 0;
|
|
17644
|
-
}
|
|
17645
|
-
this.circle.style.display = "none";
|
|
17650
|
+
activate() {
|
|
17651
|
+
this.toolbar.style.display = "flex";
|
|
17646
17652
|
}
|
|
17647
|
-
|
|
17648
|
-
|
|
17649
|
-
e.preventDefault();
|
|
17650
|
-
e.stopPropagation();
|
|
17651
|
-
const selectOp = e.shiftKey ? "add" : e.ctrlKey ? "remove" : "set";
|
|
17652
|
-
if (this.radiusPx < 3) this.radiusPx = 20;
|
|
17653
|
-
this.onSelect(selectOp, { x: this.center.x, y: this.center.y }, this.radiusPx);
|
|
17654
|
-
this.dragEnd();
|
|
17653
|
+
deactivate() {
|
|
17654
|
+
this.toolbar.style.display = "none";
|
|
17655
17655
|
}
|
|
17656
17656
|
}
|
|
17657
17657
|
class BoxSelection {
|
|
17658
|
-
constructor(parent,
|
|
17658
|
+
constructor(parent, callbacks) {
|
|
17659
17659
|
__publicField(this, "parent");
|
|
17660
|
-
__publicField(this, "
|
|
17661
|
-
__publicField(this, "
|
|
17662
|
-
__publicField(this, "
|
|
17663
|
-
__publicField(this, "
|
|
17664
|
-
__publicField(this, "
|
|
17665
|
-
__publicField(this, "
|
|
17666
|
-
__publicField(this, "
|
|
17667
|
-
__publicField(this, "
|
|
17668
|
-
__publicField(this, "dragId");
|
|
17660
|
+
__publicField(this, "toolbar");
|
|
17661
|
+
__publicField(this, "callbacks");
|
|
17662
|
+
__publicField(this, "_lenX", 2);
|
|
17663
|
+
__publicField(this, "_lenY", 2);
|
|
17664
|
+
__publicField(this, "_lenZ", 2);
|
|
17665
|
+
__publicField(this, "inputX");
|
|
17666
|
+
__publicField(this, "inputY");
|
|
17667
|
+
__publicField(this, "inputZ");
|
|
17669
17668
|
this.parent = parent;
|
|
17670
|
-
this.
|
|
17671
|
-
this.
|
|
17672
|
-
this.
|
|
17673
|
-
this.
|
|
17674
|
-
|
|
17675
|
-
|
|
17676
|
-
|
|
17677
|
-
|
|
17678
|
-
|
|
17679
|
-
|
|
17680
|
-
|
|
17681
|
-
this.
|
|
17682
|
-
this.
|
|
17683
|
-
|
|
17684
|
-
|
|
17685
|
-
|
|
17686
|
-
|
|
17687
|
-
|
|
17688
|
-
|
|
17689
|
-
|
|
17690
|
-
|
|
17691
|
-
|
|
17692
|
-
|
|
17669
|
+
this.callbacks = callbacks;
|
|
17670
|
+
this.toolbar = document.createElement("div");
|
|
17671
|
+
this.toolbar.className = "volume-select-toolbar";
|
|
17672
|
+
this.toolbar.style.cssText = `
|
|
17673
|
+
position:absolute; bottom:12px; left:50%; transform:translateX(-50%);
|
|
17674
|
+
display:none; z-index:20; background:rgba(30,30,30,0.92);
|
|
17675
|
+
border-radius:8px; padding:6px 10px; gap:6px;
|
|
17676
|
+
align-items:center; font-size:13px; color:#ddd;
|
|
17677
|
+
backdrop-filter:blur(6px); user-select:none; white-space:nowrap;
|
|
17678
|
+
box-shadow:0 2px 12px rgba(0,0,0,0.4);
|
|
17679
|
+
`;
|
|
17680
|
+
this.toolbar.addEventListener("pointerdown", (e) => e.stopPropagation());
|
|
17681
|
+
this.toolbar.addEventListener("wheel", (e) => e.stopPropagation());
|
|
17682
|
+
const mkBtn = (label, op) => {
|
|
17683
|
+
const btn = document.createElement("button");
|
|
17684
|
+
btn.textContent = label;
|
|
17685
|
+
btn.style.cssText = `
|
|
17686
|
+
padding:4px 12px; border:1px solid #555; border-radius:4px;
|
|
17687
|
+
background:#333; color:#ddd; cursor:pointer; font-size:13px;
|
|
17688
|
+
transition: background 0.15s;
|
|
17689
|
+
`;
|
|
17690
|
+
btn.addEventListener("mouseenter", () => {
|
|
17691
|
+
btn.style.background = "#555";
|
|
17692
|
+
});
|
|
17693
|
+
btn.addEventListener("mouseleave", () => {
|
|
17694
|
+
btn.style.background = "#333";
|
|
17695
|
+
});
|
|
17696
|
+
btn.addEventListener("pointerdown", (e) => {
|
|
17697
|
+
e.stopPropagation();
|
|
17698
|
+
this.callbacks.onApply(op);
|
|
17699
|
+
});
|
|
17700
|
+
return btn;
|
|
17693
17701
|
};
|
|
17694
|
-
|
|
17695
|
-
|
|
17696
|
-
|
|
17697
|
-
|
|
17698
|
-
|
|
17702
|
+
const mkInput = (placeholder, initial, onChange) => {
|
|
17703
|
+
const wrap = document.createElement("span");
|
|
17704
|
+
wrap.style.cssText = "display:inline-flex; align-items:center; gap:2px;";
|
|
17705
|
+
const input = document.createElement("input");
|
|
17706
|
+
input.type = "number";
|
|
17707
|
+
input.min = "0.01";
|
|
17708
|
+
input.step = "0.1";
|
|
17709
|
+
input.value = initial.toFixed(2);
|
|
17710
|
+
input.style.cssText = `
|
|
17711
|
+
width:50px; padding:3px 4px; border:1px solid #555; border-radius:4px;
|
|
17712
|
+
background:#222; color:#ddd; font-size:12px; text-align:center;
|
|
17713
|
+
`;
|
|
17714
|
+
const label = document.createElement("span");
|
|
17715
|
+
label.textContent = placeholder;
|
|
17716
|
+
label.style.cssText = "color:#888; font-size:11px;";
|
|
17717
|
+
input.addEventListener("change", () => {
|
|
17718
|
+
const v = Math.max(0.01, parseFloat(input.value) || 0.01);
|
|
17719
|
+
input.value = v.toFixed(2);
|
|
17720
|
+
onChange(v);
|
|
17721
|
+
});
|
|
17722
|
+
wrap.appendChild(input);
|
|
17723
|
+
wrap.appendChild(label);
|
|
17724
|
+
return { wrap, input };
|
|
17725
|
+
};
|
|
17726
|
+
const setBtn = mkBtn("Set", "set");
|
|
17727
|
+
const addBtn = mkBtn("Add", "add");
|
|
17728
|
+
const removeBtn = mkBtn("Remove", "remove");
|
|
17729
|
+
const xInput = mkInput("LenX", this._lenX, (v) => {
|
|
17730
|
+
this._lenX = v;
|
|
17731
|
+
this.emitDims();
|
|
17732
|
+
});
|
|
17733
|
+
const yInput = mkInput("LenY", this._lenY, (v) => {
|
|
17734
|
+
this._lenY = v;
|
|
17735
|
+
this.emitDims();
|
|
17736
|
+
});
|
|
17737
|
+
const zInput = mkInput("LenZ", this._lenZ, (v) => {
|
|
17738
|
+
this._lenZ = v;
|
|
17739
|
+
this.emitDims();
|
|
17740
|
+
});
|
|
17741
|
+
this.inputX = xInput.input;
|
|
17742
|
+
this.inputY = yInput.input;
|
|
17743
|
+
this.inputZ = zInput.input;
|
|
17744
|
+
this.toolbar.appendChild(setBtn);
|
|
17745
|
+
this.toolbar.appendChild(addBtn);
|
|
17746
|
+
this.toolbar.appendChild(removeBtn);
|
|
17747
|
+
this.toolbar.appendChild(xInput.wrap);
|
|
17748
|
+
this.toolbar.appendChild(yInput.wrap);
|
|
17749
|
+
this.toolbar.appendChild(zInput.wrap);
|
|
17750
|
+
parent.appendChild(this.toolbar);
|
|
17751
|
+
}
|
|
17752
|
+
get lenX() {
|
|
17753
|
+
return this._lenX;
|
|
17754
|
+
}
|
|
17755
|
+
get lenY() {
|
|
17756
|
+
return this._lenY;
|
|
17757
|
+
}
|
|
17758
|
+
get lenZ() {
|
|
17759
|
+
return this._lenZ;
|
|
17760
|
+
}
|
|
17761
|
+
setDimensions(lenX, lenY, lenZ) {
|
|
17762
|
+
this._lenX = lenX;
|
|
17763
|
+
this._lenY = lenY;
|
|
17764
|
+
this._lenZ = lenZ;
|
|
17765
|
+
this.inputX.value = lenX.toFixed(2);
|
|
17766
|
+
this.inputY.value = lenY.toFixed(2);
|
|
17767
|
+
this.inputZ.value = lenZ.toFixed(2);
|
|
17699
17768
|
}
|
|
17700
17769
|
activate() {
|
|
17701
|
-
this.
|
|
17702
|
-
this.parent.style.cursor = "crosshair";
|
|
17703
|
-
this.parent.addEventListener("pointerdown", this.pointerdown);
|
|
17704
|
-
this.parent.addEventListener("pointermove", this.pointermove);
|
|
17705
|
-
this.parent.addEventListener("pointerup", this.pointerup);
|
|
17770
|
+
this.toolbar.style.display = "flex";
|
|
17706
17771
|
}
|
|
17707
17772
|
deactivate() {
|
|
17708
|
-
|
|
17709
|
-
this.svg.style.display = "none";
|
|
17710
|
-
this.parent.style.cursor = "";
|
|
17711
|
-
this.parent.removeEventListener("pointerdown", this.pointerdown);
|
|
17712
|
-
this.parent.removeEventListener("pointermove", this.pointermove);
|
|
17713
|
-
this.parent.removeEventListener("pointerup", this.pointerup);
|
|
17714
|
-
}
|
|
17715
|
-
updateVisuals() {
|
|
17716
|
-
const x = this.center.x - this.halfW;
|
|
17717
|
-
const y = this.center.y - this.halfH;
|
|
17718
|
-
const w = this.halfW * 2;
|
|
17719
|
-
const h = this.halfH * 2;
|
|
17720
|
-
this.rect.setAttribute("x", x.toString());
|
|
17721
|
-
this.rect.setAttribute("y", y.toString());
|
|
17722
|
-
this.rect.setAttribute("width", Math.max(1, w).toString());
|
|
17723
|
-
this.rect.setAttribute("height", Math.max(1, h).toString());
|
|
17724
|
-
this.crossV.setAttribute("x1", this.center.x.toString());
|
|
17725
|
-
this.crossV.setAttribute("y1", y.toString());
|
|
17726
|
-
this.crossV.setAttribute("x2", this.center.x.toString());
|
|
17727
|
-
this.crossV.setAttribute("y2", (y + h).toString());
|
|
17728
|
-
this.crossH.setAttribute("x1", x.toString());
|
|
17729
|
-
this.crossH.setAttribute("y1", this.center.y.toString());
|
|
17730
|
-
this.crossH.setAttribute("x2", (x + w).toString());
|
|
17731
|
-
this.crossH.setAttribute("y2", this.center.y.toString());
|
|
17732
|
-
}
|
|
17733
|
-
pointerdown(e) {
|
|
17734
|
-
if (this.dragId !== void 0) return;
|
|
17735
|
-
if (e.pointerType === "mouse" ? e.button !== 0 : !e.isPrimary) return;
|
|
17736
|
-
e.preventDefault();
|
|
17737
|
-
e.stopPropagation();
|
|
17738
|
-
this.dragId = e.pointerId;
|
|
17739
|
-
this.parent.setPointerCapture(this.dragId);
|
|
17740
|
-
this.center.x = e.offsetX;
|
|
17741
|
-
this.center.y = e.offsetY;
|
|
17742
|
-
this.halfW = 0;
|
|
17743
|
-
this.halfH = 0;
|
|
17744
|
-
this.updateVisuals();
|
|
17745
|
-
this.rect.style.display = "block";
|
|
17746
|
-
this.crossV.style.display = "block";
|
|
17747
|
-
this.crossH.style.display = "block";
|
|
17773
|
+
this.toolbar.style.display = "none";
|
|
17748
17774
|
}
|
|
17749
|
-
|
|
17750
|
-
|
|
17751
|
-
e.preventDefault();
|
|
17752
|
-
e.stopPropagation();
|
|
17753
|
-
this.halfW = Math.abs(e.offsetX - this.center.x);
|
|
17754
|
-
this.halfH = Math.abs(e.offsetY - this.center.y);
|
|
17755
|
-
this.updateVisuals();
|
|
17756
|
-
}
|
|
17757
|
-
dragEnd() {
|
|
17758
|
-
if (this.dragId !== void 0) {
|
|
17759
|
-
this.parent.releasePointerCapture(this.dragId);
|
|
17760
|
-
this.dragId = void 0;
|
|
17761
|
-
}
|
|
17762
|
-
this.rect.style.display = "none";
|
|
17763
|
-
this.crossV.style.display = "none";
|
|
17764
|
-
this.crossH.style.display = "none";
|
|
17765
|
-
}
|
|
17766
|
-
pointerup(e) {
|
|
17767
|
-
if (e.pointerId !== this.dragId) return;
|
|
17768
|
-
e.preventDefault();
|
|
17769
|
-
e.stopPropagation();
|
|
17770
|
-
const selectOp = e.shiftKey ? "add" : e.ctrlKey ? "remove" : "set";
|
|
17771
|
-
if (this.halfW < 3 && this.halfH < 3) {
|
|
17772
|
-
this.halfW = 20;
|
|
17773
|
-
this.halfH = 20;
|
|
17774
|
-
}
|
|
17775
|
-
this.onSelect(selectOp, { x: this.center.x, y: this.center.y }, this.halfW, this.halfH);
|
|
17776
|
-
this.dragEnd();
|
|
17775
|
+
emitDims() {
|
|
17776
|
+
this.callbacks.onDimensionsChanged(this._lenX, this._lenY, this._lenZ);
|
|
17777
17777
|
}
|
|
17778
17778
|
}
|
|
17779
17779
|
function exportEditedPLY(positions, scales, rotations, colors, opacities, shCoeffs, state) {
|
|
@@ -17877,9 +17877,205 @@ function exportEditedPLY(positions, scales, rotations, colors, opacities, shCoef
|
|
|
17877
17877
|
}
|
|
17878
17878
|
return buffer;
|
|
17879
17879
|
}
|
|
17880
|
+
const SPHERE_SEGMENTS = 64;
|
|
17881
|
+
const SPHERE_RINGS = 3;
|
|
17882
|
+
class SelectionVolumeRenderer {
|
|
17883
|
+
constructor(renderer, camera) {
|
|
17884
|
+
__publicField(this, "renderer");
|
|
17885
|
+
__publicField(this, "camera");
|
|
17886
|
+
__publicField(this, "pipeline", null);
|
|
17887
|
+
__publicField(this, "uniformBuffer", null);
|
|
17888
|
+
__publicField(this, "bindGroup", null);
|
|
17889
|
+
__publicField(this, "vertexBuffer", null);
|
|
17890
|
+
__publicField(this, "_volume", { type: null, center: [0, 0, 0], dimensions: [2, 2, 2] });
|
|
17891
|
+
__publicField(this, "vertexCount", 0);
|
|
17892
|
+
__publicField(this, "maxVertices");
|
|
17893
|
+
__publicField(this, "lineColor", [0.2, 0.8, 1]);
|
|
17894
|
+
this.renderer = renderer;
|
|
17895
|
+
this.camera = camera;
|
|
17896
|
+
this.maxVertices = Math.max(
|
|
17897
|
+
24,
|
|
17898
|
+
SPHERE_SEGMENTS * 2 * SPHERE_RINGS
|
|
17899
|
+
);
|
|
17900
|
+
this.createPipeline();
|
|
17901
|
+
this.createVertexBuffer();
|
|
17902
|
+
}
|
|
17903
|
+
get volume() {
|
|
17904
|
+
return this._volume;
|
|
17905
|
+
}
|
|
17906
|
+
setVolume(type, center, dimensions) {
|
|
17907
|
+
this._volume.type = type;
|
|
17908
|
+
if (center) this._volume.center = center;
|
|
17909
|
+
if (dimensions) this._volume.dimensions = dimensions;
|
|
17910
|
+
}
|
|
17911
|
+
setCenter(x, y, z) {
|
|
17912
|
+
this._volume.center = [x, y, z];
|
|
17913
|
+
}
|
|
17914
|
+
setDimensions(a, b, c) {
|
|
17915
|
+
this._volume.dimensions = [a, b, c];
|
|
17916
|
+
}
|
|
17917
|
+
createPipeline() {
|
|
17918
|
+
const device = this.renderer.device;
|
|
17919
|
+
const shaderCode = (
|
|
17920
|
+
/* wgsl */
|
|
17921
|
+
`
|
|
17922
|
+
struct Uniforms { viewProjection: mat4x4<f32> }
|
|
17923
|
+
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
17924
|
+
|
|
17925
|
+
struct VI { @location(0) position: vec3<f32>, @location(1) color: vec3<f32> }
|
|
17926
|
+
struct VO { @builtin(position) position: vec4<f32>, @location(0) color: vec3<f32> }
|
|
17927
|
+
|
|
17928
|
+
@vertex fn vs(i: VI) -> VO {
|
|
17929
|
+
var o: VO;
|
|
17930
|
+
o.position = uniforms.viewProjection * vec4(i.position, 1.0);
|
|
17931
|
+
o.color = i.color;
|
|
17932
|
+
return o;
|
|
17933
|
+
}
|
|
17934
|
+
@fragment fn fs(i: VO) -> @location(0) vec4<f32> {
|
|
17935
|
+
return vec4(i.color, 0.8);
|
|
17936
|
+
}
|
|
17937
|
+
`
|
|
17938
|
+
);
|
|
17939
|
+
const sm = device.createShaderModule({ code: shaderCode });
|
|
17940
|
+
this.uniformBuffer = device.createBuffer({ size: 64, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
17941
|
+
const bgl = device.createBindGroupLayout({
|
|
17942
|
+
entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: "uniform" } }]
|
|
17943
|
+
});
|
|
17944
|
+
this.bindGroup = device.createBindGroup({ layout: bgl, entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }] });
|
|
17945
|
+
this.pipeline = device.createRenderPipeline({
|
|
17946
|
+
layout: device.createPipelineLayout({ bindGroupLayouts: [bgl] }),
|
|
17947
|
+
vertex: {
|
|
17948
|
+
module: sm,
|
|
17949
|
+
entryPoint: "vs",
|
|
17950
|
+
buffers: [{
|
|
17951
|
+
arrayStride: 24,
|
|
17952
|
+
attributes: [
|
|
17953
|
+
{ shaderLocation: 0, offset: 0, format: "float32x3" },
|
|
17954
|
+
{ shaderLocation: 1, offset: 12, format: "float32x3" }
|
|
17955
|
+
]
|
|
17956
|
+
}]
|
|
17957
|
+
},
|
|
17958
|
+
fragment: {
|
|
17959
|
+
module: sm,
|
|
17960
|
+
entryPoint: "fs",
|
|
17961
|
+
targets: [{
|
|
17962
|
+
format: this.renderer.format,
|
|
17963
|
+
blend: {
|
|
17964
|
+
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
17965
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
17966
|
+
}
|
|
17967
|
+
}]
|
|
17968
|
+
},
|
|
17969
|
+
primitive: { topology: "line-list", cullMode: "none" },
|
|
17970
|
+
depthStencil: { format: this.renderer.depthFormat, depthWriteEnabled: false, depthCompare: "always" }
|
|
17971
|
+
});
|
|
17972
|
+
}
|
|
17973
|
+
createVertexBuffer() {
|
|
17974
|
+
const size = this.maxVertices * 24;
|
|
17975
|
+
this.vertexBuffer = this.renderer.device.createBuffer({
|
|
17976
|
+
size,
|
|
17977
|
+
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
17978
|
+
});
|
|
17979
|
+
}
|
|
17980
|
+
generateBoxVertices() {
|
|
17981
|
+
const [cx, cy, cz] = this._volume.center;
|
|
17982
|
+
const [lx, ly, lz] = this._volume.dimensions;
|
|
17983
|
+
const hx = lx / 2, hy = ly / 2, hz = lz / 2;
|
|
17984
|
+
const [r, g, b] = this.lineColor;
|
|
17985
|
+
const v = [];
|
|
17986
|
+
const addLine = (x12, y12, z12, x2, y2, z2) => {
|
|
17987
|
+
v.push(x12, y12, z12, r, g, b, x2, y2, z2, r, g, b);
|
|
17988
|
+
};
|
|
17989
|
+
const x0 = cx - hx, x1 = cx + hx;
|
|
17990
|
+
const y0 = cy - hy, y1 = cy + hy;
|
|
17991
|
+
const z0 = cz - hz, z1 = cz + hz;
|
|
17992
|
+
addLine(x0, y0, z0, x1, y0, z0);
|
|
17993
|
+
addLine(x1, y0, z0, x1, y0, z1);
|
|
17994
|
+
addLine(x1, y0, z1, x0, y0, z1);
|
|
17995
|
+
addLine(x0, y0, z1, x0, y0, z0);
|
|
17996
|
+
addLine(x0, y1, z0, x1, y1, z0);
|
|
17997
|
+
addLine(x1, y1, z0, x1, y1, z1);
|
|
17998
|
+
addLine(x1, y1, z1, x0, y1, z1);
|
|
17999
|
+
addLine(x0, y1, z1, x0, y1, z0);
|
|
18000
|
+
addLine(x0, y0, z0, x0, y1, z0);
|
|
18001
|
+
addLine(x1, y0, z0, x1, y1, z0);
|
|
18002
|
+
addLine(x1, y0, z1, x1, y1, z1);
|
|
18003
|
+
addLine(x0, y0, z1, x0, y1, z1);
|
|
18004
|
+
return new Float32Array(v);
|
|
18005
|
+
}
|
|
18006
|
+
generateSphereVertices() {
|
|
18007
|
+
const [cx, cy, cz] = this._volume.center;
|
|
18008
|
+
const radius = this._volume.dimensions[0];
|
|
18009
|
+
const [r, g, b] = this.lineColor;
|
|
18010
|
+
const v = [];
|
|
18011
|
+
const seg = SPHERE_SEGMENTS;
|
|
18012
|
+
const addCircle = (axis) => {
|
|
18013
|
+
for (let i = 0; i < seg; i++) {
|
|
18014
|
+
const a0 = i / seg * Math.PI * 2;
|
|
18015
|
+
const a1 = (i + 1) / seg * Math.PI * 2;
|
|
18016
|
+
let x0, y0, z0, x1, y1, z1;
|
|
18017
|
+
if (axis === "y") {
|
|
18018
|
+
x0 = cx + Math.cos(a0) * radius;
|
|
18019
|
+
y0 = cy;
|
|
18020
|
+
z0 = cz + Math.sin(a0) * radius;
|
|
18021
|
+
x1 = cx + Math.cos(a1) * radius;
|
|
18022
|
+
y1 = cy;
|
|
18023
|
+
z1 = cz + Math.sin(a1) * radius;
|
|
18024
|
+
} else if (axis === "x") {
|
|
18025
|
+
x0 = cx;
|
|
18026
|
+
y0 = cy + Math.cos(a0) * radius;
|
|
18027
|
+
z0 = cz + Math.sin(a0) * radius;
|
|
18028
|
+
x1 = cx;
|
|
18029
|
+
y1 = cy + Math.cos(a1) * radius;
|
|
18030
|
+
z1 = cz + Math.sin(a1) * radius;
|
|
18031
|
+
} else {
|
|
18032
|
+
x0 = cx + Math.cos(a0) * radius;
|
|
18033
|
+
y0 = cy + Math.sin(a0) * radius;
|
|
18034
|
+
z0 = cz;
|
|
18035
|
+
x1 = cx + Math.cos(a1) * radius;
|
|
18036
|
+
y1 = cy + Math.sin(a1) * radius;
|
|
18037
|
+
z1 = cz;
|
|
18038
|
+
}
|
|
18039
|
+
v.push(x0, y0, z0, r, g, b, x1, y1, z1, r, g, b);
|
|
18040
|
+
}
|
|
18041
|
+
};
|
|
18042
|
+
addCircle("x");
|
|
18043
|
+
addCircle("y");
|
|
18044
|
+
addCircle("z");
|
|
18045
|
+
return new Float32Array(v);
|
|
18046
|
+
}
|
|
18047
|
+
render(pass) {
|
|
18048
|
+
if (!this._volume.type || !this.pipeline || !this.bindGroup || !this.vertexBuffer || !this.uniformBuffer) return;
|
|
18049
|
+
const device = this.renderer.device;
|
|
18050
|
+
const verts = this._volume.type === "box" ? this.generateBoxVertices() : this.generateSphereVertices();
|
|
18051
|
+
this.vertexCount = verts.length / 6;
|
|
18052
|
+
if (this.vertexCount === 0) return;
|
|
18053
|
+
const needed = this.vertexCount * 24;
|
|
18054
|
+
if (needed > this.vertexBuffer.size) {
|
|
18055
|
+
this.vertexBuffer.destroy();
|
|
18056
|
+
this.vertexBuffer = device.createBuffer({ size: needed, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST });
|
|
18057
|
+
}
|
|
18058
|
+
device.queue.writeBuffer(this.vertexBuffer, 0, verts.buffer);
|
|
18059
|
+
device.queue.writeBuffer(this.uniformBuffer, 0, new Float32Array(this.camera.viewProjectionMatrix));
|
|
18060
|
+
pass.setPipeline(this.pipeline);
|
|
18061
|
+
pass.setBindGroup(0, this.bindGroup);
|
|
18062
|
+
pass.setVertexBuffer(0, this.vertexBuffer);
|
|
18063
|
+
pass.draw(this.vertexCount);
|
|
18064
|
+
}
|
|
18065
|
+
destroy() {
|
|
18066
|
+
var _a2, _b2;
|
|
18067
|
+
(_a2 = this.vertexBuffer) == null ? void 0 : _a2.destroy();
|
|
18068
|
+
(_b2 = this.uniformBuffer) == null ? void 0 : _b2.destroy();
|
|
18069
|
+
this.vertexBuffer = null;
|
|
18070
|
+
this.uniformBuffer = null;
|
|
18071
|
+
this.pipeline = null;
|
|
18072
|
+
this.bindGroup = null;
|
|
18073
|
+
}
|
|
18074
|
+
}
|
|
17880
18075
|
class SplatEditor {
|
|
17881
|
-
constructor(camera, gsRenderer, container, callbacks = {}) {
|
|
18076
|
+
constructor(camera, gsRenderer, container, callbacks = {}, renderer) {
|
|
17882
18077
|
__publicField(this, "camera");
|
|
18078
|
+
__publicField(this, "gpuRenderer");
|
|
17883
18079
|
__publicField(this, "gsRenderer");
|
|
17884
18080
|
__publicField(this, "container");
|
|
17885
18081
|
__publicField(this, "splatState");
|
|
@@ -17894,6 +18090,10 @@ class SplatEditor {
|
|
|
17894
18090
|
__publicField(this, "projDirty", true);
|
|
17895
18091
|
__publicField(this, "_active", false);
|
|
17896
18092
|
__publicField(this, "overlayCleanup", []);
|
|
18093
|
+
/** 体积选择线框渲染器 */
|
|
18094
|
+
__publicField(this, "volumeRenderer", null);
|
|
18095
|
+
__publicField(this, "boxTool", null);
|
|
18096
|
+
__publicField(this, "sphereTool", null);
|
|
17897
18097
|
// ============================================
|
|
17898
18098
|
// 键盘快捷键
|
|
17899
18099
|
// ============================================
|
|
@@ -17902,6 +18102,7 @@ class SplatEditor {
|
|
|
17902
18102
|
this.gsRenderer = gsRenderer;
|
|
17903
18103
|
this.container = container;
|
|
17904
18104
|
this.callbacks = callbacks;
|
|
18105
|
+
this.gpuRenderer = renderer;
|
|
17905
18106
|
}
|
|
17906
18107
|
get active() {
|
|
17907
18108
|
return this._active;
|
|
@@ -17948,9 +18149,20 @@ class SplatEditor {
|
|
|
17948
18149
|
this.container.style.position = "relative";
|
|
17949
18150
|
}
|
|
17950
18151
|
this.toolManager = new ToolManager((name) => {
|
|
17951
|
-
var _a2, _b2;
|
|
17952
|
-
|
|
17953
|
-
|
|
18152
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
18153
|
+
const isVolumeTool = name === "box" || name === "sphere";
|
|
18154
|
+
this.toolOverlay.style.display = name && !isVolumeTool ? "block" : "none";
|
|
18155
|
+
if (isVolumeTool && this.volumeRenderer) {
|
|
18156
|
+
const volType = name;
|
|
18157
|
+
const center = this.getModelCenter();
|
|
18158
|
+
const dims = volType === "box" ? [this.boxTool.lenX, this.boxTool.lenY, this.boxTool.lenZ] : [this.sphereTool.radius, 0, 0];
|
|
18159
|
+
this.volumeRenderer.setVolume(volType, center, dims);
|
|
18160
|
+
(_b2 = (_a2 = this.callbacks).onVolumeToolActivated) == null ? void 0 : _b2.call(_a2, this.volumeRenderer.volume);
|
|
18161
|
+
} else {
|
|
18162
|
+
if (this.volumeRenderer) this.volumeRenderer.setVolume(null);
|
|
18163
|
+
(_d = (_c = this.callbacks).onVolumeToolDeactivated) == null ? void 0 : _d.call(_c);
|
|
18164
|
+
}
|
|
18165
|
+
(_f = (_e = this.callbacks).onToolChanged) == null ? void 0 : _f.call(_e, name);
|
|
17954
18166
|
});
|
|
17955
18167
|
this.toolManager.register("rect", new RectSelection(
|
|
17956
18168
|
this.toolOverlay,
|
|
@@ -17986,24 +18198,42 @@ class SplatEditor {
|
|
|
17986
18198
|
this.toolOverlay,
|
|
17987
18199
|
(op, pt, threshold) => this.selectByColor(op, pt, threshold)
|
|
17988
18200
|
));
|
|
17989
|
-
this.
|
|
17990
|
-
this.
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
|
|
17995
|
-
|
|
17996
|
-
|
|
18201
|
+
if (this.gpuRenderer) {
|
|
18202
|
+
this.volumeRenderer = new SelectionVolumeRenderer(this.gpuRenderer, this.camera);
|
|
18203
|
+
}
|
|
18204
|
+
this.sphereTool = new SphereSelection(this.container, {
|
|
18205
|
+
onApply: (op) => this.applyVolumeSelection(op),
|
|
18206
|
+
onRadiusChanged: (radius) => {
|
|
18207
|
+
var _a2;
|
|
18208
|
+
(_a2 = this.volumeRenderer) == null ? void 0 : _a2.setDimensions(radius, 0, 0);
|
|
18209
|
+
}
|
|
18210
|
+
});
|
|
18211
|
+
this.toolManager.register("sphere", this.sphereTool);
|
|
18212
|
+
this.boxTool = new BoxSelection(this.container, {
|
|
18213
|
+
onApply: (op) => this.applyVolumeSelection(op),
|
|
18214
|
+
onDimensionsChanged: (lx, ly, lz) => {
|
|
18215
|
+
var _a2;
|
|
18216
|
+
(_a2 = this.volumeRenderer) == null ? void 0 : _a2.setDimensions(lx, ly, lz);
|
|
18217
|
+
}
|
|
18218
|
+
});
|
|
18219
|
+
this.toolManager.register("box", this.boxTool);
|
|
17997
18220
|
this.gsRenderer.setEditorState(this.splatState.data);
|
|
17998
18221
|
this._keyHandler = this._onKeyDown.bind(this);
|
|
17999
18222
|
window.addEventListener("keydown", this._keyHandler);
|
|
18000
18223
|
this.projDirty = true;
|
|
18001
18224
|
}
|
|
18225
|
+
/**
|
|
18226
|
+
* 渲染体积选择线框(在主渲染 pass 内调用)
|
|
18227
|
+
*/
|
|
18228
|
+
renderVolume(pass) {
|
|
18229
|
+
var _a2;
|
|
18230
|
+
(_a2 = this.volumeRenderer) == null ? void 0 : _a2.render(pass);
|
|
18231
|
+
}
|
|
18002
18232
|
/**
|
|
18003
18233
|
* 退出编辑模式,将编辑结果永久写入渲染数据
|
|
18004
18234
|
*/
|
|
18005
18235
|
exit() {
|
|
18006
|
-
var _a2, _b2;
|
|
18236
|
+
var _a2, _b2, _c;
|
|
18007
18237
|
if (!this._active) return;
|
|
18008
18238
|
this._active = false;
|
|
18009
18239
|
window.removeEventListener("keydown", this._keyHandler);
|
|
@@ -18012,6 +18242,8 @@ class SplatEditor {
|
|
|
18012
18242
|
this.overlayCleanup = [];
|
|
18013
18243
|
(_a2 = this.toolOverlay) == null ? void 0 : _a2.remove();
|
|
18014
18244
|
(_b2 = this.maskCanvas) == null ? void 0 : _b2.remove();
|
|
18245
|
+
(_c = this.volumeRenderer) == null ? void 0 : _c.destroy();
|
|
18246
|
+
this.volumeRenderer = null;
|
|
18015
18247
|
this.applyEditsToRenderer();
|
|
18016
18248
|
this.editHistory.clear();
|
|
18017
18249
|
this.gsRenderer.clearEditorState();
|
|
@@ -18247,17 +18479,14 @@ class SplatEditor {
|
|
|
18247
18479
|
this.editHistory.add(editOp);
|
|
18248
18480
|
}
|
|
18249
18481
|
/**
|
|
18250
|
-
*
|
|
18482
|
+
* 世界空间球体选择
|
|
18251
18483
|
*/
|
|
18252
|
-
|
|
18253
|
-
const pick = this.pickWorldPosition(centerPx.x, centerPx.y);
|
|
18254
|
-
if (!pick) return;
|
|
18255
|
-
const worldRadius = radiusPx * pick.pixelToWorld;
|
|
18484
|
+
selectByWorldSphere(op, center, radius) {
|
|
18256
18485
|
const cpuPos = this.gsRenderer.getCPUPositions();
|
|
18257
18486
|
if (!cpuPos) return;
|
|
18258
18487
|
const modelMat = this.gsRenderer.getModelMatrix();
|
|
18259
|
-
const
|
|
18260
|
-
const
|
|
18488
|
+
const r2 = radius * radius;
|
|
18489
|
+
const [cx, cy, cz] = center;
|
|
18261
18490
|
const editOp = new SelectOp(this.splatState, op, (i) => {
|
|
18262
18491
|
if (this.splatState.data[i] & (State.hidden | State.deleted)) return false;
|
|
18263
18492
|
const i3 = i * 3;
|
|
@@ -18266,25 +18495,19 @@ class SplatEditor {
|
|
|
18266
18495
|
const wy = modelMat[1] * lx + modelMat[5] * ly + modelMat[9] * lz + modelMat[13];
|
|
18267
18496
|
const wz = modelMat[2] * lx + modelMat[6] * ly + modelMat[10] * lz + modelMat[14];
|
|
18268
18497
|
const dx = wx - cx, dy = wy - cy, dz = wz - cz;
|
|
18269
|
-
return dx * dx + dy * dy + dz * dz
|
|
18498
|
+
return dx * dx + dy * dy + dz * dz <= r2;
|
|
18270
18499
|
});
|
|
18271
18500
|
this.editHistory.add(editOp);
|
|
18272
18501
|
}
|
|
18273
18502
|
/**
|
|
18274
|
-
*
|
|
18275
|
-
* X/Y 半宽由屏幕拖拽距离转换,Z 半深度取 max(halfW, halfH)
|
|
18503
|
+
* 世界空间 AABB 选择
|
|
18276
18504
|
*/
|
|
18277
|
-
|
|
18278
|
-
const pick = this.pickWorldPosition(centerPx.x, centerPx.y);
|
|
18279
|
-
if (!pick) return;
|
|
18280
|
-
const s = pick.pixelToWorld;
|
|
18281
|
-
const hx = halfWPx * s;
|
|
18282
|
-
const hy = halfHPx * s;
|
|
18283
|
-
const hz = Math.max(hx, hy);
|
|
18505
|
+
selectByWorldBox(op, center, lenX, lenY, lenZ) {
|
|
18284
18506
|
const cpuPos = this.gsRenderer.getCPUPositions();
|
|
18285
18507
|
if (!cpuPos) return;
|
|
18286
18508
|
const modelMat = this.gsRenderer.getModelMatrix();
|
|
18287
|
-
const cx
|
|
18509
|
+
const [cx, cy, cz] = center;
|
|
18510
|
+
const hx = lenX / 2, hy = lenY / 2, hz = lenZ / 2;
|
|
18288
18511
|
const editOp = new SelectOp(this.splatState, op, (i) => {
|
|
18289
18512
|
if (this.splatState.data[i] & (State.hidden | State.deleted)) return false;
|
|
18290
18513
|
const i3 = i * 3;
|
|
@@ -18292,10 +18515,83 @@ class SplatEditor {
|
|
|
18292
18515
|
const wx = modelMat[0] * lx + modelMat[4] * ly + modelMat[8] * lz + modelMat[12];
|
|
18293
18516
|
const wy = modelMat[1] * lx + modelMat[5] * ly + modelMat[9] * lz + modelMat[13];
|
|
18294
18517
|
const wz = modelMat[2] * lx + modelMat[6] * ly + modelMat[10] * lz + modelMat[14];
|
|
18295
|
-
|
|
18518
|
+
const rx = wx - cx, ry = wy - cy, rz = wz - cz;
|
|
18519
|
+
return rx >= -hx && rx <= hx && ry >= -hy && ry <= hy && rz >= -hz && rz <= hz;
|
|
18296
18520
|
});
|
|
18297
18521
|
this.editHistory.add(editOp);
|
|
18298
18522
|
}
|
|
18523
|
+
/**
|
|
18524
|
+
* 应用当前体积选择
|
|
18525
|
+
*/
|
|
18526
|
+
applyVolumeSelection(op) {
|
|
18527
|
+
if (!this.volumeRenderer) return;
|
|
18528
|
+
const vol = this.volumeRenderer.volume;
|
|
18529
|
+
if (!vol.type) return;
|
|
18530
|
+
if (vol.type === "sphere") {
|
|
18531
|
+
this.selectByWorldSphere(op, vol.center, vol.dimensions[0]);
|
|
18532
|
+
} else {
|
|
18533
|
+
this.selectByWorldBox(op, vol.center, vol.dimensions[0], vol.dimensions[1], vol.dimensions[2]);
|
|
18534
|
+
}
|
|
18535
|
+
}
|
|
18536
|
+
/**
|
|
18537
|
+
* 设置体积选择的中心位置(供外部 gizmo 调用)
|
|
18538
|
+
*/
|
|
18539
|
+
setVolumeCenter(x, y, z) {
|
|
18540
|
+
var _a2;
|
|
18541
|
+
(_a2 = this.volumeRenderer) == null ? void 0 : _a2.setCenter(x, y, z);
|
|
18542
|
+
}
|
|
18543
|
+
/**
|
|
18544
|
+
* 获取当前体积状态
|
|
18545
|
+
*/
|
|
18546
|
+
getVolumeState() {
|
|
18547
|
+
var _a2;
|
|
18548
|
+
return ((_a2 = this.volumeRenderer) == null ? void 0 : _a2.volume) ?? null;
|
|
18549
|
+
}
|
|
18550
|
+
/**
|
|
18551
|
+
* 创建体积位置的 TransformableObject 代理,供 gizmo 控制
|
|
18552
|
+
*/
|
|
18553
|
+
createVolumeTransformProxy() {
|
|
18554
|
+
if (!this.volumeRenderer) return null;
|
|
18555
|
+
const vol = this.volumeRenderer;
|
|
18556
|
+
return {
|
|
18557
|
+
get position() {
|
|
18558
|
+
return vol.volume.center;
|
|
18559
|
+
},
|
|
18560
|
+
get rotation() {
|
|
18561
|
+
return [0, 0, 0];
|
|
18562
|
+
},
|
|
18563
|
+
get scale() {
|
|
18564
|
+
return [1, 1, 1];
|
|
18565
|
+
},
|
|
18566
|
+
setPosition: (x, y, z) => {
|
|
18567
|
+
vol.setCenter(x, y, z);
|
|
18568
|
+
},
|
|
18569
|
+
setRotation: () => {
|
|
18570
|
+
},
|
|
18571
|
+
setScale: () => {
|
|
18572
|
+
}
|
|
18573
|
+
};
|
|
18574
|
+
}
|
|
18575
|
+
/**
|
|
18576
|
+
* 获取模型包围盒中心(世界空间)
|
|
18577
|
+
*/
|
|
18578
|
+
getModelCenter() {
|
|
18579
|
+
const cpuPos = this.gsRenderer.getCPUPositions();
|
|
18580
|
+
if (!cpuPos || cpuPos.length === 0) return [0, 0, 0];
|
|
18581
|
+
const modelMat = this.gsRenderer.getModelMatrix();
|
|
18582
|
+
const count = this.splatState.count;
|
|
18583
|
+
let sx = 0, sy = 0, sz = 0, n = 0;
|
|
18584
|
+
const step = Math.max(1, Math.floor(count / 1e3));
|
|
18585
|
+
for (let i = 0; i < count; i += step) {
|
|
18586
|
+
const i3 = i * 3;
|
|
18587
|
+
const lx = cpuPos[i3], ly = cpuPos[i3 + 1], lz = cpuPos[i3 + 2];
|
|
18588
|
+
sx += modelMat[0] * lx + modelMat[4] * ly + modelMat[8] * lz + modelMat[12];
|
|
18589
|
+
sy += modelMat[1] * lx + modelMat[5] * ly + modelMat[9] * lz + modelMat[13];
|
|
18590
|
+
sz += modelMat[2] * lx + modelMat[6] * ly + modelMat[10] * lz + modelMat[14];
|
|
18591
|
+
n++;
|
|
18592
|
+
}
|
|
18593
|
+
return n > 0 ? [sx / n, sy / n, sz / n] : [0, 0, 0];
|
|
18594
|
+
}
|
|
18299
18595
|
/**
|
|
18300
18596
|
* 根据屏幕像素坐标,找到最近的可见 splat 并返回其世界坐标及深度换算系数
|
|
18301
18597
|
*/
|
|
@@ -18500,6 +18796,8 @@ class App {
|
|
|
18500
18796
|
__publicField(this, "baseRenderScale", 1);
|
|
18501
18797
|
// 绑定的事件处理函数
|
|
18502
18798
|
__publicField(this, "boundOnResize");
|
|
18799
|
+
/** 额外渲染回调(在 gizmo 之前、场景辅助之后执行) */
|
|
18800
|
+
__publicField(this, "extraRenderCallbacks", []);
|
|
18503
18801
|
this.canvas = canvas;
|
|
18504
18802
|
this.boundOnResize = this.onResize.bind(this);
|
|
18505
18803
|
}
|
|
@@ -18945,6 +19243,7 @@ class App {
|
|
|
18945
19243
|
}
|
|
18946
19244
|
this.meshRenderer.render(pass);
|
|
18947
19245
|
this.sceneAids.render(pass);
|
|
19246
|
+
for (const cb of this.extraRenderCallbacks) cb(pass);
|
|
18948
19247
|
this.gizmoManager.render(pass);
|
|
18949
19248
|
this.renderer.endFrame();
|
|
18950
19249
|
if (this.hotspotManager.isActive()) {
|
|
@@ -19187,6 +19486,16 @@ class App {
|
|
|
19187
19486
|
getRenderer() {
|
|
19188
19487
|
return this.renderer;
|
|
19189
19488
|
}
|
|
19489
|
+
/**
|
|
19490
|
+
* 注册额外的渲染回调(在场景辅助之后、gizmo 之前执行)
|
|
19491
|
+
*/
|
|
19492
|
+
addRenderCallback(cb) {
|
|
19493
|
+
this.extraRenderCallbacks.push(cb);
|
|
19494
|
+
}
|
|
19495
|
+
removeRenderCallback(cb) {
|
|
19496
|
+
const idx = this.extraRenderCallbacks.indexOf(cb);
|
|
19497
|
+
if (idx >= 0) this.extraRenderCallbacks.splice(idx, 1);
|
|
19498
|
+
}
|
|
19190
19499
|
/**
|
|
19191
19500
|
* CPU splat 拾取:在屏幕坐标 (clientX, clientY) 处找最近的 splat,返回世界坐标或 null
|
|
19192
19501
|
*/
|
|
@@ -19585,6 +19894,7 @@ exports.Renderer = Renderer;
|
|
|
19585
19894
|
exports.SHMode = SHMode;
|
|
19586
19895
|
exports.SceneAidsRenderer = SceneAidsRenderer;
|
|
19587
19896
|
exports.SceneManager = SceneManager;
|
|
19897
|
+
exports.SelectionVolumeRenderer = SelectionVolumeRenderer;
|
|
19588
19898
|
exports.SkyboxRenderer = SkyboxRenderer;
|
|
19589
19899
|
exports.SplatBoundingBoxProvider = SplatBoundingBoxProvider;
|
|
19590
19900
|
exports.SplatEditor = SplatEditor;
|