@d5techs/3dgs-lib 1.4.82 → 1.4.84
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 +243 -638
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +243 -638
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/editor/SelectionVolumeRenderer.d.ts +10 -10
- package/dist/editor/SplatEditor.d.ts +4 -0
- package/dist/editor/tools/BoxSelection.d.ts +2 -12
- package/dist/editor/tools/SphereSelection.d.ts +2 -9
- package/package.json +1 -1
package/dist/3dgs-lib.cjs
CHANGED
|
@@ -17568,188 +17568,31 @@ class EyedropperSelection {
|
|
|
17568
17568
|
}
|
|
17569
17569
|
}
|
|
17570
17570
|
class SphereSelection {
|
|
17571
|
-
constructor(
|
|
17572
|
-
__publicField(this, "parent");
|
|
17573
|
-
__publicField(this, "toolbar");
|
|
17574
|
-
__publicField(this, "callbacks");
|
|
17571
|
+
constructor(onRadiusChanged) {
|
|
17575
17572
|
__publicField(this, "_radius", 1);
|
|
17576
|
-
__publicField(this, "
|
|
17577
|
-
this.
|
|
17578
|
-
this.callbacks = callbacks;
|
|
17579
|
-
this.toolbar = document.createElement("div");
|
|
17580
|
-
this.toolbar.className = "select-toolbar";
|
|
17581
|
-
this.toolbar.style.cssText = `
|
|
17582
|
-
position:absolute; bottom:100px; left:50%; transform:translateX(-50%);
|
|
17583
|
-
height:54px; display:none; z-index:20;
|
|
17584
|
-
padding:0 8px; border-radius:8px;
|
|
17585
|
-
background:rgba(30,30,30,0.92);
|
|
17586
|
-
align-items:center; font-size:13px; color:#ddd;
|
|
17587
|
-
backdrop-filter:blur(6px); user-select:none; white-space:nowrap;
|
|
17588
|
-
box-shadow:0 2px 12px rgba(0,0,0,0.4);
|
|
17589
|
-
`;
|
|
17590
|
-
this.toolbar.addEventListener("pointerdown", (e) => e.stopPropagation());
|
|
17591
|
-
this.toolbar.addEventListener("wheel", (e) => e.stopPropagation());
|
|
17592
|
-
const mkBtn = (label2, op) => {
|
|
17593
|
-
const btn = document.createElement("button");
|
|
17594
|
-
btn.textContent = label2;
|
|
17595
|
-
btn.style.cssText = `
|
|
17596
|
-
height:38px; padding:0 16px; border:none; border-radius:2px;
|
|
17597
|
-
background:#444; color:#ddd; cursor:pointer; font-size:13px;
|
|
17598
|
-
transition: background 0.15s;
|
|
17599
|
-
`;
|
|
17600
|
-
btn.addEventListener("mouseenter", () => {
|
|
17601
|
-
btn.style.background = "#555";
|
|
17602
|
-
});
|
|
17603
|
-
btn.addEventListener("mouseleave", () => {
|
|
17604
|
-
btn.style.background = "#444";
|
|
17605
|
-
});
|
|
17606
|
-
btn.addEventListener("pointerdown", (e) => {
|
|
17607
|
-
e.stopPropagation();
|
|
17608
|
-
this.callbacks.onApply(op);
|
|
17609
|
-
});
|
|
17610
|
-
return btn;
|
|
17611
|
-
};
|
|
17612
|
-
const setBtn = mkBtn("Set", "set");
|
|
17613
|
-
const addBtn = mkBtn("Add", "add");
|
|
17614
|
-
const removeBtn = mkBtn("Remove", "remove");
|
|
17615
|
-
const inputWrap = document.createElement("span");
|
|
17616
|
-
inputWrap.style.cssText = "display:inline-flex; align-items:center; gap:4px; margin-left:4px;";
|
|
17617
|
-
const label = document.createElement("span");
|
|
17618
|
-
label.textContent = "Radius";
|
|
17619
|
-
label.style.cssText = "color:#888; font-size:11px;";
|
|
17620
|
-
const input = document.createElement("input");
|
|
17621
|
-
input.type = "number";
|
|
17622
|
-
input.min = "0.01";
|
|
17623
|
-
input.step = "0.01";
|
|
17624
|
-
input.value = this._radius.toFixed(2);
|
|
17625
|
-
input.style.cssText = `
|
|
17626
|
-
width:80px; padding:4px 6px; border:1px solid #555; border-radius:4px;
|
|
17627
|
-
background:#222; color:#ddd; font-size:12px; text-align:center;
|
|
17628
|
-
`;
|
|
17629
|
-
input.addEventListener("change", () => {
|
|
17630
|
-
const v = Math.max(0.01, parseFloat(input.value) || 0.01);
|
|
17631
|
-
input.value = v.toFixed(2);
|
|
17632
|
-
this._radius = v;
|
|
17633
|
-
this.callbacks.onRadiusChanged(v);
|
|
17634
|
-
});
|
|
17635
|
-
inputWrap.appendChild(label);
|
|
17636
|
-
inputWrap.appendChild(input);
|
|
17637
|
-
this.radiusInput = input;
|
|
17638
|
-
this.toolbar.appendChild(setBtn);
|
|
17639
|
-
this.toolbar.appendChild(addBtn);
|
|
17640
|
-
this.toolbar.appendChild(removeBtn);
|
|
17641
|
-
this.toolbar.appendChild(inputWrap);
|
|
17642
|
-
parent.appendChild(this.toolbar);
|
|
17573
|
+
__publicField(this, "_onRadiusChanged");
|
|
17574
|
+
this._onRadiusChanged = onRadiusChanged;
|
|
17643
17575
|
}
|
|
17644
17576
|
get radius() {
|
|
17645
17577
|
return this._radius;
|
|
17646
17578
|
}
|
|
17647
17579
|
setRadius(radius) {
|
|
17580
|
+
var _a2;
|
|
17648
17581
|
this._radius = radius;
|
|
17649
|
-
this.
|
|
17582
|
+
(_a2 = this._onRadiusChanged) == null ? void 0 : _a2.call(this, radius);
|
|
17650
17583
|
}
|
|
17651
17584
|
activate() {
|
|
17652
|
-
this.toolbar.style.display = "flex";
|
|
17653
17585
|
}
|
|
17654
17586
|
deactivate() {
|
|
17655
|
-
this.toolbar.style.display = "none";
|
|
17656
17587
|
}
|
|
17657
17588
|
}
|
|
17658
17589
|
class BoxSelection {
|
|
17659
|
-
constructor(
|
|
17660
|
-
__publicField(this, "parent");
|
|
17661
|
-
__publicField(this, "toolbar");
|
|
17662
|
-
__publicField(this, "callbacks");
|
|
17590
|
+
constructor(onDimensionsChanged) {
|
|
17663
17591
|
__publicField(this, "_lenX", 2);
|
|
17664
17592
|
__publicField(this, "_lenY", 2);
|
|
17665
17593
|
__publicField(this, "_lenZ", 2);
|
|
17666
|
-
__publicField(this, "
|
|
17667
|
-
|
|
17668
|
-
__publicField(this, "inputZ");
|
|
17669
|
-
this.parent = parent;
|
|
17670
|
-
this.callbacks = callbacks;
|
|
17671
|
-
this.toolbar = document.createElement("div");
|
|
17672
|
-
this.toolbar.className = "select-toolbar";
|
|
17673
|
-
this.toolbar.style.cssText = `
|
|
17674
|
-
position:absolute; bottom:100px; left:50%; transform:translateX(-50%);
|
|
17675
|
-
height:54px; display:none; z-index:20;
|
|
17676
|
-
padding:0 8px; border-radius:8px;
|
|
17677
|
-
background:rgba(30,30,30,0.92);
|
|
17678
|
-
align-items:center; font-size:13px; color:#ddd;
|
|
17679
|
-
backdrop-filter:blur(6px); user-select:none; white-space:nowrap;
|
|
17680
|
-
box-shadow:0 2px 12px rgba(0,0,0,0.4);
|
|
17681
|
-
`;
|
|
17682
|
-
this.toolbar.addEventListener("pointerdown", (e) => e.stopPropagation());
|
|
17683
|
-
this.toolbar.addEventListener("wheel", (e) => e.stopPropagation());
|
|
17684
|
-
const mkBtn = (label, op) => {
|
|
17685
|
-
const btn = document.createElement("button");
|
|
17686
|
-
btn.textContent = label;
|
|
17687
|
-
btn.style.cssText = `
|
|
17688
|
-
height:38px; padding:0 16px; border:none; border-radius:2px;
|
|
17689
|
-
background:#444; color:#ddd; cursor:pointer; font-size:13px;
|
|
17690
|
-
transition: background 0.15s;
|
|
17691
|
-
`;
|
|
17692
|
-
btn.addEventListener("mouseenter", () => {
|
|
17693
|
-
btn.style.background = "#555";
|
|
17694
|
-
});
|
|
17695
|
-
btn.addEventListener("mouseleave", () => {
|
|
17696
|
-
btn.style.background = "#444";
|
|
17697
|
-
});
|
|
17698
|
-
btn.addEventListener("pointerdown", (e) => {
|
|
17699
|
-
e.stopPropagation();
|
|
17700
|
-
this.callbacks.onApply(op);
|
|
17701
|
-
});
|
|
17702
|
-
return btn;
|
|
17703
|
-
};
|
|
17704
|
-
const mkInput = (placeholder, initial, onChange) => {
|
|
17705
|
-
const wrap = document.createElement("span");
|
|
17706
|
-
wrap.style.cssText = "display:inline-flex; align-items:center; gap:4px; margin-left:4px;";
|
|
17707
|
-
const label = document.createElement("span");
|
|
17708
|
-
label.textContent = placeholder;
|
|
17709
|
-
label.style.cssText = "color:#888; font-size:11px;";
|
|
17710
|
-
const input = document.createElement("input");
|
|
17711
|
-
input.type = "number";
|
|
17712
|
-
input.min = "0.01";
|
|
17713
|
-
input.step = "0.01";
|
|
17714
|
-
input.value = initial.toFixed(2);
|
|
17715
|
-
input.style.cssText = `
|
|
17716
|
-
width:80px; padding:4px 6px; border:1px solid #555; border-radius:4px;
|
|
17717
|
-
background:#222; color:#ddd; font-size:12px; text-align:center;
|
|
17718
|
-
`;
|
|
17719
|
-
input.addEventListener("change", () => {
|
|
17720
|
-
const v = Math.max(0.01, parseFloat(input.value) || 0.01);
|
|
17721
|
-
input.value = v.toFixed(2);
|
|
17722
|
-
onChange(v);
|
|
17723
|
-
});
|
|
17724
|
-
wrap.appendChild(label);
|
|
17725
|
-
wrap.appendChild(input);
|
|
17726
|
-
return { wrap, input };
|
|
17727
|
-
};
|
|
17728
|
-
const setBtn = mkBtn("Set", "set");
|
|
17729
|
-
const addBtn = mkBtn("Add", "add");
|
|
17730
|
-
const removeBtn = mkBtn("Remove", "remove");
|
|
17731
|
-
const xInput = mkInput("LenX", this._lenX, (v) => {
|
|
17732
|
-
this._lenX = v;
|
|
17733
|
-
this.emitDims();
|
|
17734
|
-
});
|
|
17735
|
-
const yInput = mkInput("LenY", this._lenY, (v) => {
|
|
17736
|
-
this._lenY = v;
|
|
17737
|
-
this.emitDims();
|
|
17738
|
-
});
|
|
17739
|
-
const zInput = mkInput("LenZ", this._lenZ, (v) => {
|
|
17740
|
-
this._lenZ = v;
|
|
17741
|
-
this.emitDims();
|
|
17742
|
-
});
|
|
17743
|
-
this.inputX = xInput.input;
|
|
17744
|
-
this.inputY = yInput.input;
|
|
17745
|
-
this.inputZ = zInput.input;
|
|
17746
|
-
this.toolbar.appendChild(setBtn);
|
|
17747
|
-
this.toolbar.appendChild(addBtn);
|
|
17748
|
-
this.toolbar.appendChild(removeBtn);
|
|
17749
|
-
this.toolbar.appendChild(xInput.wrap);
|
|
17750
|
-
this.toolbar.appendChild(yInput.wrap);
|
|
17751
|
-
this.toolbar.appendChild(zInput.wrap);
|
|
17752
|
-
parent.appendChild(this.toolbar);
|
|
17594
|
+
__publicField(this, "_onDimensionsChanged");
|
|
17595
|
+
this._onDimensionsChanged = onDimensionsChanged;
|
|
17753
17596
|
}
|
|
17754
17597
|
get lenX() {
|
|
17755
17598
|
return this._lenX;
|
|
@@ -17761,21 +17604,15 @@ class BoxSelection {
|
|
|
17761
17604
|
return this._lenZ;
|
|
17762
17605
|
}
|
|
17763
17606
|
setDimensions(lenX, lenY, lenZ) {
|
|
17607
|
+
var _a2;
|
|
17764
17608
|
this._lenX = lenX;
|
|
17765
17609
|
this._lenY = lenY;
|
|
17766
17610
|
this._lenZ = lenZ;
|
|
17767
|
-
this.
|
|
17768
|
-
this.inputY.value = lenY.toFixed(2);
|
|
17769
|
-
this.inputZ.value = lenZ.toFixed(2);
|
|
17611
|
+
(_a2 = this._onDimensionsChanged) == null ? void 0 : _a2.call(this, lenX, lenY, lenZ);
|
|
17770
17612
|
}
|
|
17771
17613
|
activate() {
|
|
17772
|
-
this.toolbar.style.display = "flex";
|
|
17773
17614
|
}
|
|
17774
17615
|
deactivate() {
|
|
17775
|
-
this.toolbar.style.display = "none";
|
|
17776
|
-
}
|
|
17777
|
-
emitDims() {
|
|
17778
|
-
this.callbacks.onDimensionsChanged(this._lenX, this._lenY, this._lenZ);
|
|
17779
17616
|
}
|
|
17780
17617
|
}
|
|
17781
17618
|
function exportEditedPLY(positions, scales, rotations, colors, opacities, shCoeffs, state) {
|
|
@@ -17879,311 +17716,29 @@ function exportEditedPLY(positions, scales, rotations, colors, opacities, shCoef
|
|
|
17879
17716
|
}
|
|
17880
17717
|
return buffer;
|
|
17881
17718
|
}
|
|
17882
|
-
const
|
|
17883
|
-
|
|
17884
|
-
|
|
17885
|
-
|
|
17886
|
-
0.5,
|
|
17887
|
-
-0.5,
|
|
17888
|
-
0.5,
|
|
17889
|
-
0.5,
|
|
17890
|
-
0.5,
|
|
17891
|
-
0.5,
|
|
17892
|
-
-0.5,
|
|
17893
|
-
-0.5,
|
|
17894
|
-
0.5,
|
|
17895
|
-
0.5,
|
|
17896
|
-
0.5,
|
|
17897
|
-
0.5,
|
|
17898
|
-
-0.5,
|
|
17899
|
-
0.5,
|
|
17900
|
-
0.5,
|
|
17901
|
-
0.5,
|
|
17902
|
-
-0.5,
|
|
17903
|
-
-0.5,
|
|
17904
|
-
-0.5,
|
|
17905
|
-
-0.5,
|
|
17906
|
-
-0.5,
|
|
17907
|
-
-0.5,
|
|
17908
|
-
0.5,
|
|
17909
|
-
-0.5,
|
|
17910
|
-
0.5,
|
|
17911
|
-
-0.5,
|
|
17912
|
-
-0.5,
|
|
17913
|
-
-0.5,
|
|
17914
|
-
0.5,
|
|
17915
|
-
-0.5,
|
|
17916
|
-
0.5,
|
|
17917
|
-
0.5,
|
|
17918
|
-
-0.5,
|
|
17919
|
-
-0.5,
|
|
17920
|
-
0.5,
|
|
17921
|
-
0.5,
|
|
17922
|
-
0.5,
|
|
17923
|
-
0.5,
|
|
17924
|
-
0.5,
|
|
17925
|
-
0.5,
|
|
17926
|
-
0.5,
|
|
17927
|
-
-0.5,
|
|
17928
|
-
-0.5,
|
|
17929
|
-
0.5,
|
|
17930
|
-
0.5,
|
|
17931
|
-
0.5,
|
|
17932
|
-
0.5,
|
|
17933
|
-
-0.5,
|
|
17934
|
-
-0.5,
|
|
17935
|
-
0.5,
|
|
17936
|
-
-0.5,
|
|
17937
|
-
-0.5,
|
|
17938
|
-
-0.5,
|
|
17939
|
-
-0.5,
|
|
17940
|
-
0.5,
|
|
17941
|
-
-0.5,
|
|
17942
|
-
-0.5,
|
|
17943
|
-
0.5,
|
|
17944
|
-
-0.5,
|
|
17945
|
-
0.5,
|
|
17946
|
-
-0.5,
|
|
17947
|
-
-0.5,
|
|
17948
|
-
-0.5,
|
|
17949
|
-
0.5,
|
|
17950
|
-
-0.5,
|
|
17951
|
-
0.5,
|
|
17952
|
-
-0.5,
|
|
17953
|
-
-0.5,
|
|
17954
|
-
0.5,
|
|
17955
|
-
0.5,
|
|
17956
|
-
-0.5,
|
|
17957
|
-
0.5,
|
|
17958
|
-
0.5,
|
|
17959
|
-
-0.5,
|
|
17960
|
-
-0.5,
|
|
17961
|
-
0.5,
|
|
17962
|
-
0.5,
|
|
17963
|
-
-0.5,
|
|
17964
|
-
0.5,
|
|
17965
|
-
-0.5,
|
|
17966
|
-
0.5,
|
|
17967
|
-
0.5,
|
|
17968
|
-
0.5,
|
|
17969
|
-
-0.5,
|
|
17970
|
-
0.5,
|
|
17971
|
-
0.5,
|
|
17972
|
-
0.5,
|
|
17973
|
-
-0.5,
|
|
17974
|
-
-0.5,
|
|
17975
|
-
-0.5,
|
|
17976
|
-
-0.5,
|
|
17977
|
-
-0.5,
|
|
17978
|
-
0.5,
|
|
17979
|
-
-0.5,
|
|
17980
|
-
0.5,
|
|
17981
|
-
0.5,
|
|
17982
|
-
-0.5,
|
|
17983
|
-
-0.5,
|
|
17984
|
-
-0.5,
|
|
17985
|
-
-0.5,
|
|
17986
|
-
0.5,
|
|
17987
|
-
0.5,
|
|
17988
|
-
-0.5,
|
|
17989
|
-
0.5,
|
|
17990
|
-
-0.5
|
|
17991
|
-
]);
|
|
17992
|
-
const COMMON_WGSL = (
|
|
17993
|
-
/* wgsl */
|
|
17994
|
-
`
|
|
17995
|
-
struct Uniforms {
|
|
17996
|
-
viewProjMatrix: mat4x4<f32>,
|
|
17997
|
-
modelMatrix: mat4x4<f32>,
|
|
17998
|
-
nearOrigin: vec4<f32>,
|
|
17999
|
-
nearX: vec4<f32>,
|
|
18000
|
-
nearY: vec4<f32>,
|
|
18001
|
-
farOrigin: vec4<f32>,
|
|
18002
|
-
farX: vec4<f32>,
|
|
18003
|
-
farY: vec4<f32>,
|
|
18004
|
-
targetSize: vec4<f32>,
|
|
18005
|
-
shapeP0: vec4<f32>,
|
|
18006
|
-
shapeP1: vec4<f32>,
|
|
18007
|
-
}
|
|
18008
|
-
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
18009
|
-
|
|
18010
|
-
struct VO { @builtin(position) position: vec4<f32> }
|
|
18011
|
-
struct FO {
|
|
18012
|
-
@location(0) color: vec4<f32>,
|
|
18013
|
-
@builtin(frag_depth) depth: f32,
|
|
18014
|
-
}
|
|
18015
|
-
|
|
18016
|
-
@vertex fn vs(@location(0) pos: vec3<f32>) -> VO {
|
|
18017
|
-
var o: VO;
|
|
18018
|
-
o.position = u.viewProjMatrix * u.modelMatrix * vec4(pos, 1.0);
|
|
18019
|
-
return o;
|
|
18020
|
-
}
|
|
18021
|
-
|
|
18022
|
-
fn interleavedGradientNoise(p: vec2<f32>) -> f32 {
|
|
18023
|
-
return fract(52.9829189 * fract(dot(p, vec2(0.06711056, 0.00583715))));
|
|
18024
|
-
}
|
|
18025
|
-
|
|
18026
|
-
fn writeDepth(alpha: f32, fc: vec2<f32>) -> bool {
|
|
18027
|
-
return alpha > interleavedGradientNoise(fc);
|
|
18028
|
-
}
|
|
18029
|
-
|
|
18030
|
-
fn calcDepth(wp: vec3<f32>) -> f32 {
|
|
18031
|
-
let v = u.viewProjMatrix * vec4(wp, 1.0);
|
|
18032
|
-
return clamp(v.z / v.w, 0.0, 1.0);
|
|
18033
|
-
}
|
|
18034
|
-
|
|
18035
|
-
fn reconstructRay(fragPos: vec4<f32>) -> array<vec3<f32>, 2> {
|
|
18036
|
-
let clip = vec2(fragPos.x / u.targetSize.x, 1.0 - fragPos.y / u.targetSize.y);
|
|
18037
|
-
let wNear = u.nearOrigin.xyz + u.nearX.xyz * clip.x + u.nearY.xyz * clip.y;
|
|
18038
|
-
let wFar = u.farOrigin.xyz + u.farX.xyz * clip.x + u.farY.xyz * clip.y;
|
|
18039
|
-
return array(wNear, normalize(wFar - wNear));
|
|
18040
|
-
}
|
|
18041
|
-
`
|
|
18042
|
-
);
|
|
18043
|
-
const BOX_FRAG_WGSL = (
|
|
18044
|
-
/* wgsl */
|
|
18045
|
-
`
|
|
18046
|
-
fn intersectBox(pos: vec3<f32>, dir: vec3<f32>, cen: vec3<f32>, halfLen: vec3<f32>) -> vec4<f32> {
|
|
18047
|
-
let vx = select(0.0, 1.0, dir.x != 0.0);
|
|
18048
|
-
let vy = select(0.0, 1.0, dir.y != 0.0);
|
|
18049
|
-
let vz = select(0.0, 1.0, dir.z != 0.0);
|
|
18050
|
-
let valid = vec3<f32>(vx, vy, vz);
|
|
18051
|
-
let m = vec3<f32>(
|
|
18052
|
-
select(0.0, sign(dir.x) / abs(dir.x), dir.x != 0.0),
|
|
18053
|
-
select(0.0, sign(dir.y) / abs(dir.y), dir.y != 0.0),
|
|
18054
|
-
select(0.0, sign(dir.z) / abs(dir.z), dir.z != 0.0),
|
|
18055
|
-
);
|
|
18056
|
-
let n = m * (pos - cen);
|
|
18057
|
-
let k = abs(m) * halfLen;
|
|
18058
|
-
var v0 = -n - k;
|
|
18059
|
-
var v1 = -n + k;
|
|
18060
|
-
v0 = mix(vec3(-1e10), v0, valid);
|
|
18061
|
-
v1 = mix(vec3( 1e10), v1, valid);
|
|
18062
|
-
|
|
18063
|
-
var axis0: i32; var axis1: i32;
|
|
18064
|
-
if v0.x > v0.y { axis0 = select(2, 0, v0.x > v0.z); }
|
|
18065
|
-
else { axis0 = select(2, 1, v0.y > v0.z); }
|
|
18066
|
-
if v1.x < v1.y { axis1 = select(2, 0, v1.x < v1.z); }
|
|
18067
|
-
else { axis1 = select(2, 1, v1.y < v1.z); }
|
|
18068
|
-
|
|
18069
|
-
let t0 = select(select(v0.z, v0.y, axis0==1), v0.x, axis0==0);
|
|
18070
|
-
let t1 = select(select(v1.z, v1.y, axis1==1), v1.x, axis1==0);
|
|
18071
|
-
if t0 > t1 || t1 < 0.0 { return vec4(-1.0); }
|
|
18072
|
-
return vec4(t0, t1, f32(axis0), f32(axis1));
|
|
18073
|
-
}
|
|
18074
|
-
|
|
18075
|
-
fn strips(pos: vec3<f32>, axis: i32) -> bool {
|
|
18076
|
-
let f = fract(pos * 2.0 + vec3(0.015));
|
|
18077
|
-
let b = f < vec3(0.03);
|
|
18078
|
-
if axis == 0 { return b.y || b.z; }
|
|
18079
|
-
if axis == 1 { return b.x || b.z; }
|
|
18080
|
-
return b.x || b.y;
|
|
18081
|
-
}
|
|
18082
|
-
|
|
18083
|
-
@fragment fn fs(i: VO) -> FO {
|
|
18084
|
-
var o: FO;
|
|
18085
|
-
o.color = vec4(0.0);
|
|
18086
|
-
o.depth = 1.0;
|
|
18087
|
-
|
|
18088
|
-
let ray = reconstructRay(i.position);
|
|
18089
|
-
let hit = intersectBox(ray[0], ray[1], u.shapeP0.xyz, u.shapeP1.xyz);
|
|
18090
|
-
if hit.x < 0.0 { discard; return o; }
|
|
18091
|
-
|
|
18092
|
-
let t0 = hit.x; let t1 = hit.y;
|
|
18093
|
-
let a0 = i32(hit.z); let a1 = i32(hit.w);
|
|
18094
|
-
let frontPos = ray[0] + ray[1] * t0;
|
|
18095
|
-
let backPos = ray[0] + ray[1] * t1;
|
|
18096
|
-
let front = t0 > 0.0 && strips(frontPos - u.shapeP0.xyz, a0);
|
|
18097
|
-
let back = strips(backPos - u.shapeP0.xyz, a1);
|
|
18098
|
-
|
|
18099
|
-
if front {
|
|
18100
|
-
o.color = vec4(1.0, 1.0, 1.0, 0.6);
|
|
18101
|
-
o.depth = select(1.0, calcDepth(frontPos), writeDepth(0.6, i.position.xy));
|
|
18102
|
-
return o;
|
|
18103
|
-
}
|
|
18104
|
-
if back {
|
|
18105
|
-
o.color = vec4(0.0, 0.0, 0.0, 0.6);
|
|
18106
|
-
o.depth = select(1.0, calcDepth(backPos), writeDepth(0.6, i.position.xy));
|
|
18107
|
-
return o;
|
|
18108
|
-
}
|
|
18109
|
-
discard;
|
|
18110
|
-
return o;
|
|
18111
|
-
}
|
|
18112
|
-
`
|
|
18113
|
-
);
|
|
18114
|
-
const SPHERE_FRAG_WGSL = (
|
|
18115
|
-
/* wgsl */
|
|
18116
|
-
`
|
|
18117
|
-
fn intersectSphere(pos: vec3<f32>, dir: vec3<f32>, sph: vec4<f32>) -> vec2<f32> {
|
|
18118
|
-
let L = sph.xyz - pos;
|
|
18119
|
-
let tca = dot(L, dir);
|
|
18120
|
-
let d2 = sph.w * sph.w - (dot(L, L) - tca * tca);
|
|
18121
|
-
if d2 <= 0.0 { return vec2(-1.0); }
|
|
18122
|
-
let thc = sqrt(d2);
|
|
18123
|
-
let t0 = tca - thc;
|
|
18124
|
-
let t1 = tca + thc;
|
|
18125
|
-
if t1 <= 0.0 { return vec2(-1.0); }
|
|
18126
|
-
return vec2(t0, t1);
|
|
18127
|
-
}
|
|
18128
|
-
|
|
18129
|
-
fn calcAzimuthElev(dir: vec3<f32>) -> vec2<f32> {
|
|
18130
|
-
let azimuth = atan2(dir.z, dir.x);
|
|
18131
|
-
let elev = asin(clamp(dir.y, -1.0, 1.0));
|
|
18132
|
-
return vec2(azimuth, elev) * 180.0 / 3.14159265;
|
|
18133
|
-
}
|
|
18134
|
-
|
|
18135
|
-
fn sphereStrips(lp: vec3<f32>, radius: f32) -> bool {
|
|
18136
|
-
let ae = calcAzimuthElev(normalize(lp));
|
|
18137
|
-
let spacing = 180.0 / (2.0 * 3.14159265 * radius);
|
|
18138
|
-
let sz = 0.03;
|
|
18139
|
-
return fract(ae.x / spacing) < sz || fract(ae.y / spacing) < sz;
|
|
18140
|
-
}
|
|
18141
|
-
|
|
18142
|
-
@fragment fn fs(i: VO) -> FO {
|
|
18143
|
-
var o: FO;
|
|
18144
|
-
o.color = vec4(0.0);
|
|
18145
|
-
o.depth = 1.0;
|
|
18146
|
-
|
|
18147
|
-
let sph = u.shapeP0;
|
|
18148
|
-
let ray = reconstructRay(i.position);
|
|
18149
|
-
let hit = intersectSphere(ray[0], ray[1], sph);
|
|
18150
|
-
if hit.x < 0.0 && hit.y < 0.0 { discard; return o; }
|
|
18151
|
-
|
|
18152
|
-
let t0 = hit.x; let t1 = hit.y;
|
|
18153
|
-
let frontPos = ray[0] + ray[1] * t0;
|
|
18154
|
-
let backPos = ray[0] + ray[1] * t1;
|
|
18155
|
-
let front = t0 > 0.0 && sphereStrips(frontPos - sph.xyz, sph.w);
|
|
18156
|
-
let back = sphereStrips(backPos - sph.xyz, sph.w);
|
|
18157
|
-
|
|
18158
|
-
if front {
|
|
18159
|
-
o.color = vec4(1.0, 1.0, 1.0, 0.6);
|
|
18160
|
-
o.depth = select(1.0, calcDepth(frontPos), writeDepth(0.6, i.position.xy));
|
|
18161
|
-
return o;
|
|
18162
|
-
}
|
|
18163
|
-
if back {
|
|
18164
|
-
o.color = vec4(0.0, 0.0, 0.0, 0.6);
|
|
18165
|
-
o.depth = select(1.0, calcDepth(backPos), writeDepth(0.6, i.position.xy));
|
|
18166
|
-
return o;
|
|
18167
|
-
}
|
|
18168
|
-
discard;
|
|
18169
|
-
return o;
|
|
18170
|
-
}
|
|
18171
|
-
`
|
|
18172
|
-
);
|
|
18173
|
-
const UNIFORM_SIZE = 272;
|
|
17719
|
+
const SEG = 64;
|
|
17720
|
+
const LAT_COUNT = 8;
|
|
17721
|
+
const LON_COUNT = 12;
|
|
17722
|
+
const BOX_GRID_SUBDIV = 4;
|
|
18174
17723
|
class SelectionVolumeRenderer {
|
|
18175
17724
|
constructor(renderer, camera) {
|
|
18176
17725
|
__publicField(this, "renderer");
|
|
18177
17726
|
__publicField(this, "camera");
|
|
18178
|
-
__publicField(this, "
|
|
18179
|
-
__publicField(this, "
|
|
17727
|
+
__publicField(this, "frontPipeline", null);
|
|
17728
|
+
__publicField(this, "behindPipeline", null);
|
|
18180
17729
|
__publicField(this, "uniformBuffer", null);
|
|
18181
17730
|
__publicField(this, "bindGroup", null);
|
|
18182
17731
|
__publicField(this, "vertexBuffer", null);
|
|
18183
17732
|
__publicField(this, "_volume", { type: null, center: [0, 0, 0], dimensions: [2, 2, 2] });
|
|
17733
|
+
__publicField(this, "vertexCount", 0);
|
|
17734
|
+
__publicField(this, "frontColor", [0.4, 0.9, 1]);
|
|
18184
17735
|
this.renderer = renderer;
|
|
18185
17736
|
this.camera = camera;
|
|
18186
|
-
this.
|
|
17737
|
+
this.createPipelines();
|
|
17738
|
+
this.vertexBuffer = this.renderer.device.createBuffer({
|
|
17739
|
+
size: 65536,
|
|
17740
|
+
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
17741
|
+
});
|
|
18187
17742
|
}
|
|
18188
17743
|
get volume() {
|
|
18189
17744
|
return this._volume;
|
|
@@ -18199,187 +17754,225 @@ class SelectionVolumeRenderer {
|
|
|
18199
17754
|
setDimensions(a, b, c) {
|
|
18200
17755
|
this._volume.dimensions = [a, b, c];
|
|
18201
17756
|
}
|
|
18202
|
-
|
|
17757
|
+
createPipelines() {
|
|
18203
17758
|
const device = this.renderer.device;
|
|
18204
|
-
|
|
18205
|
-
|
|
18206
|
-
|
|
18207
|
-
|
|
18208
|
-
|
|
18209
|
-
|
|
18210
|
-
|
|
18211
|
-
|
|
18212
|
-
|
|
17759
|
+
const shaderCode = (
|
|
17760
|
+
/* wgsl */
|
|
17761
|
+
`
|
|
17762
|
+
struct Uniforms {
|
|
17763
|
+
viewMatrix: mat4x4<f32>,
|
|
17764
|
+
projMatrix: mat4x4<f32>,
|
|
17765
|
+
modelMatrix: mat4x4<f32>,
|
|
17766
|
+
}
|
|
17767
|
+
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
17768
|
+
|
|
17769
|
+
struct VI { @location(0) position: vec3<f32>, @location(1) color: vec3<f32> }
|
|
17770
|
+
struct VO { @builtin(position) position: vec4<f32>, @location(0) color: vec3<f32> }
|
|
17771
|
+
|
|
17772
|
+
@vertex fn vs(i: VI) -> VO {
|
|
17773
|
+
var o: VO;
|
|
17774
|
+
let worldPos = uniforms.modelMatrix * vec4(i.position, 1.0);
|
|
17775
|
+
let viewPos = uniforms.viewMatrix * worldPos;
|
|
17776
|
+
o.position = uniforms.projMatrix * viewPos;
|
|
17777
|
+
o.color = i.color;
|
|
17778
|
+
return o;
|
|
17779
|
+
}
|
|
17780
|
+
@fragment fn fs(i: VO) -> @location(0) vec4<f32> {
|
|
17781
|
+
return vec4(i.color, 0.7);
|
|
17782
|
+
}
|
|
17783
|
+
@fragment fn fsBehind(i: VO) -> @location(0) vec4<f32> {
|
|
17784
|
+
return vec4(i.color * 0.35, 0.2);
|
|
17785
|
+
}
|
|
17786
|
+
`
|
|
17787
|
+
);
|
|
17788
|
+
const sm = device.createShaderModule({ code: shaderCode });
|
|
17789
|
+
this.uniformBuffer = device.createBuffer({ size: 192, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
18213
17790
|
const bgl = device.createBindGroupLayout({
|
|
18214
|
-
entries: [{
|
|
18215
|
-
binding: 0,
|
|
18216
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
18217
|
-
buffer: { type: "uniform" }
|
|
18218
|
-
}]
|
|
18219
|
-
});
|
|
18220
|
-
this.bindGroup = device.createBindGroup({
|
|
18221
|
-
layout: bgl,
|
|
18222
|
-
entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }]
|
|
17791
|
+
entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } }]
|
|
18223
17792
|
});
|
|
17793
|
+
this.bindGroup = device.createBindGroup({ layout: bgl, entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }] });
|
|
18224
17794
|
const layout = device.createPipelineLayout({ bindGroupLayouts: [bgl] });
|
|
18225
|
-
const
|
|
18226
|
-
module:
|
|
17795
|
+
const vertexState = {
|
|
17796
|
+
module: sm,
|
|
18227
17797
|
entryPoint: "vs",
|
|
18228
17798
|
buffers: [{
|
|
18229
|
-
arrayStride:
|
|
18230
|
-
attributes: [
|
|
17799
|
+
arrayStride: 24,
|
|
17800
|
+
attributes: [
|
|
17801
|
+
{ shaderLocation: 0, offset: 0, format: "float32x3" },
|
|
17802
|
+
{ shaderLocation: 1, offset: 12, format: "float32x3" }
|
|
17803
|
+
]
|
|
18231
17804
|
}]
|
|
18232
|
-
}
|
|
18233
|
-
const
|
|
17805
|
+
};
|
|
17806
|
+
const blendState = {
|
|
18234
17807
|
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
18235
17808
|
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
18236
17809
|
};
|
|
18237
|
-
|
|
18238
|
-
format: this.renderer.depthFormat,
|
|
18239
|
-
depthWriteEnabled: true,
|
|
18240
|
-
depthCompare: "less-equal"
|
|
18241
|
-
};
|
|
18242
|
-
const boxMod = device.createShaderModule({ code: COMMON_WGSL + BOX_FRAG_WGSL });
|
|
18243
|
-
this.boxPipeline = device.createRenderPipeline({
|
|
17810
|
+
this.frontPipeline = device.createRenderPipeline({
|
|
18244
17811
|
layout,
|
|
18245
|
-
vertex:
|
|
17812
|
+
vertex: vertexState,
|
|
18246
17813
|
fragment: {
|
|
18247
|
-
module:
|
|
17814
|
+
module: sm,
|
|
18248
17815
|
entryPoint: "fs",
|
|
18249
|
-
targets: [{ format: this.renderer.format, blend }]
|
|
17816
|
+
targets: [{ format: this.renderer.format, blend: blendState }]
|
|
18250
17817
|
},
|
|
18251
|
-
primitive: { topology: "
|
|
18252
|
-
depthStencil
|
|
17818
|
+
primitive: { topology: "line-list", cullMode: "none" },
|
|
17819
|
+
depthStencil: { format: this.renderer.depthFormat, depthWriteEnabled: false, depthCompare: "less-equal" }
|
|
18253
17820
|
});
|
|
18254
|
-
|
|
18255
|
-
this.spherePipeline = device.createRenderPipeline({
|
|
17821
|
+
this.behindPipeline = device.createRenderPipeline({
|
|
18256
17822
|
layout,
|
|
18257
|
-
vertex:
|
|
17823
|
+
vertex: vertexState,
|
|
18258
17824
|
fragment: {
|
|
18259
|
-
module:
|
|
18260
|
-
entryPoint: "
|
|
18261
|
-
targets: [{ format: this.renderer.format, blend }]
|
|
17825
|
+
module: sm,
|
|
17826
|
+
entryPoint: "fsBehind",
|
|
17827
|
+
targets: [{ format: this.renderer.format, blend: blendState }]
|
|
18262
17828
|
},
|
|
18263
|
-
primitive: { topology: "
|
|
18264
|
-
depthStencil
|
|
17829
|
+
primitive: { topology: "line-list", cullMode: "none" },
|
|
17830
|
+
depthStencil: { format: this.renderer.depthFormat, depthWriteEnabled: false, depthCompare: "greater" }
|
|
18265
17831
|
});
|
|
18266
17832
|
}
|
|
18267
|
-
//
|
|
18268
|
-
|
|
18269
|
-
const
|
|
18270
|
-
const
|
|
18271
|
-
const
|
|
18272
|
-
const
|
|
18273
|
-
const
|
|
18274
|
-
|
|
18275
|
-
|
|
18276
|
-
const
|
|
18277
|
-
const
|
|
18278
|
-
const
|
|
18279
|
-
|
|
18280
|
-
|
|
18281
|
-
|
|
18282
|
-
|
|
18283
|
-
|
|
18284
|
-
|
|
18285
|
-
|
|
18286
|
-
|
|
18287
|
-
|
|
18288
|
-
|
|
18289
|
-
|
|
18290
|
-
|
|
18291
|
-
|
|
18292
|
-
|
|
18293
|
-
|
|
18294
|
-
|
|
18295
|
-
|
|
18296
|
-
|
|
18297
|
-
|
|
18298
|
-
|
|
18299
|
-
|
|
18300
|
-
|
|
18301
|
-
|
|
18302
|
-
|
|
18303
|
-
|
|
18304
|
-
|
|
17833
|
+
// ========== Box: 12 edges + grid lines on all 6 faces ==========
|
|
17834
|
+
generateBoxVertices(color) {
|
|
17835
|
+
const [lx, ly, lz] = this._volume.dimensions;
|
|
17836
|
+
const hx = lx / 2, hy = ly / 2, hz = lz / 2;
|
|
17837
|
+
const [r, g, b] = color;
|
|
17838
|
+
const v = [];
|
|
17839
|
+
const line = (x12, y12, z12, x2, y2, z2) => {
|
|
17840
|
+
v.push(x12, y12, z12, r, g, b, x2, y2, z2, r, g, b);
|
|
17841
|
+
};
|
|
17842
|
+
const x0 = -hx, x1 = hx;
|
|
17843
|
+
const y0 = -hy, y1 = hy;
|
|
17844
|
+
const z0 = -hz, z1 = hz;
|
|
17845
|
+
line(x0, y0, z0, x1, y0, z0);
|
|
17846
|
+
line(x1, y0, z0, x1, y0, z1);
|
|
17847
|
+
line(x1, y0, z1, x0, y0, z1);
|
|
17848
|
+
line(x0, y0, z1, x0, y0, z0);
|
|
17849
|
+
line(x0, y1, z0, x1, y1, z0);
|
|
17850
|
+
line(x1, y1, z0, x1, y1, z1);
|
|
17851
|
+
line(x1, y1, z1, x0, y1, z1);
|
|
17852
|
+
line(x0, y1, z1, x0, y1, z0);
|
|
17853
|
+
line(x0, y0, z0, x0, y1, z0);
|
|
17854
|
+
line(x1, y0, z0, x1, y1, z0);
|
|
17855
|
+
line(x1, y0, z1, x1, y1, z1);
|
|
17856
|
+
line(x0, y0, z1, x0, y1, z1);
|
|
17857
|
+
const n = BOX_GRID_SUBDIV;
|
|
17858
|
+
for (let i = 1; i < n; i++) {
|
|
17859
|
+
const t = i / n;
|
|
17860
|
+
const px = x0 + (x1 - x0) * t;
|
|
17861
|
+
const pz = z0 + (z1 - z0) * t;
|
|
17862
|
+
line(px, y0, z0, px, y0, z1);
|
|
17863
|
+
line(px, y1, z0, px, y1, z1);
|
|
17864
|
+
line(x0, y0, pz, x1, y0, pz);
|
|
17865
|
+
line(x0, y1, pz, x1, y1, pz);
|
|
17866
|
+
}
|
|
17867
|
+
for (let i = 1; i < n; i++) {
|
|
17868
|
+
const t = i / n;
|
|
17869
|
+
const px = x0 + (x1 - x0) * t;
|
|
17870
|
+
const py = y0 + (y1 - y0) * t;
|
|
17871
|
+
line(px, y0, z0, px, y1, z0);
|
|
17872
|
+
line(px, y0, z1, px, y1, z1);
|
|
17873
|
+
line(x0, py, z0, x1, py, z0);
|
|
17874
|
+
line(x0, py, z1, x1, py, z1);
|
|
17875
|
+
}
|
|
17876
|
+
for (let i = 1; i < n; i++) {
|
|
17877
|
+
const t = i / n;
|
|
17878
|
+
const py = y0 + (y1 - y0) * t;
|
|
17879
|
+
const pz = z0 + (z1 - z0) * t;
|
|
17880
|
+
line(x0, py, z0, x0, py, z1);
|
|
17881
|
+
line(x1, py, z0, x1, py, z1);
|
|
17882
|
+
line(x0, y0, pz, x0, y1, pz);
|
|
17883
|
+
line(x1, y0, pz, x1, y1, pz);
|
|
17884
|
+
}
|
|
17885
|
+
return new Float32Array(v);
|
|
17886
|
+
}
|
|
17887
|
+
// ========== Sphere: latitude + longitude rings ==========
|
|
17888
|
+
generateSphereVertices(color) {
|
|
17889
|
+
const radius = this._volume.dimensions[0];
|
|
17890
|
+
const [r, g, b] = color;
|
|
17891
|
+
const v = [];
|
|
17892
|
+
const addRing = (centerY, ringRadius) => {
|
|
17893
|
+
for (let i = 0; i < SEG; i++) {
|
|
17894
|
+
const a0 = i / SEG * Math.PI * 2;
|
|
17895
|
+
const a1 = (i + 1) / SEG * Math.PI * 2;
|
|
17896
|
+
v.push(
|
|
17897
|
+
Math.cos(a0) * ringRadius,
|
|
17898
|
+
centerY,
|
|
17899
|
+
Math.sin(a0) * ringRadius,
|
|
17900
|
+
r,
|
|
17901
|
+
g,
|
|
17902
|
+
b,
|
|
17903
|
+
Math.cos(a1) * ringRadius,
|
|
17904
|
+
centerY,
|
|
17905
|
+
Math.sin(a1) * ringRadius,
|
|
17906
|
+
r,
|
|
17907
|
+
g,
|
|
17908
|
+
b
|
|
17909
|
+
);
|
|
17910
|
+
}
|
|
17911
|
+
};
|
|
17912
|
+
for (let i = 0; i <= LAT_COUNT; i++) {
|
|
17913
|
+
const phi = -Math.PI / 2 + i / LAT_COUNT * Math.PI;
|
|
17914
|
+
const y = Math.sin(phi) * radius;
|
|
17915
|
+
const ringR = Math.cos(phi) * radius;
|
|
17916
|
+
if (ringR < 1e-3) continue;
|
|
17917
|
+
addRing(y, ringR);
|
|
17918
|
+
}
|
|
17919
|
+
for (let j = 0; j < LON_COUNT; j++) {
|
|
17920
|
+
const theta = j / LON_COUNT * Math.PI;
|
|
17921
|
+
for (let i = 0; i < SEG; i++) {
|
|
17922
|
+
const phi0 = i / SEG * Math.PI * 2;
|
|
17923
|
+
const phi1 = (i + 1) / SEG * Math.PI * 2;
|
|
17924
|
+
v.push(
|
|
17925
|
+
Math.sin(phi0) * Math.sin(theta) * radius,
|
|
17926
|
+
Math.cos(phi0) * radius,
|
|
17927
|
+
Math.sin(phi0) * Math.cos(theta) * radius,
|
|
17928
|
+
r,
|
|
17929
|
+
g,
|
|
17930
|
+
b,
|
|
17931
|
+
Math.sin(phi1) * Math.sin(theta) * radius,
|
|
17932
|
+
Math.cos(phi1) * radius,
|
|
17933
|
+
Math.sin(phi1) * Math.cos(theta) * radius,
|
|
17934
|
+
r,
|
|
17935
|
+
g,
|
|
17936
|
+
b
|
|
17937
|
+
);
|
|
17938
|
+
}
|
|
17939
|
+
}
|
|
17940
|
+
return new Float32Array(v);
|
|
18305
17941
|
}
|
|
18306
17942
|
render(pass) {
|
|
18307
|
-
|
|
18308
|
-
if (!vol.type || !this.uniformBuffer || !this.vertexBuffer || !this.bindGroup) return;
|
|
18309
|
-
const pipeline = vol.type === "box" ? this.boxPipeline : this.spherePipeline;
|
|
18310
|
-
if (!pipeline) return;
|
|
17943
|
+
if (!this._volume.type || !this.frontPipeline || !this.behindPipeline || !this.bindGroup || !this.vertexBuffer || !this.uniformBuffer) return;
|
|
18311
17944
|
const device = this.renderer.device;
|
|
18312
|
-
const
|
|
18313
|
-
|
|
18314
|
-
|
|
18315
|
-
|
|
18316
|
-
|
|
18317
|
-
|
|
18318
|
-
|
|
18319
|
-
|
|
18320
|
-
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
|
|
18331
|
-
|
|
18332
|
-
|
|
18333
|
-
}
|
|
18334
|
-
|
|
18335
|
-
|
|
18336
|
-
uniforms[17] = 0;
|
|
18337
|
-
uniforms[18] = 0;
|
|
18338
|
-
uniforms[19] = 0;
|
|
18339
|
-
uniforms[20] = 0;
|
|
18340
|
-
uniforms[21] = r2;
|
|
18341
|
-
uniforms[22] = 0;
|
|
18342
|
-
uniforms[23] = 0;
|
|
18343
|
-
uniforms[24] = 0;
|
|
18344
|
-
uniforms[25] = 0;
|
|
18345
|
-
uniforms[26] = r2;
|
|
18346
|
-
uniforms[27] = 0;
|
|
18347
|
-
uniforms[28] = cx;
|
|
18348
|
-
uniforms[29] = cy;
|
|
18349
|
-
uniforms[30] = cz;
|
|
18350
|
-
uniforms[31] = 1;
|
|
18351
|
-
}
|
|
18352
|
-
const frustumBuf = new Float32Array(24);
|
|
18353
|
-
this.computeFrustumUniforms(frustumBuf);
|
|
18354
|
-
uniforms.set(frustumBuf, 32);
|
|
18355
|
-
uniforms[56] = this.renderer.width;
|
|
18356
|
-
uniforms[57] = this.renderer.height;
|
|
18357
|
-
uniforms[58] = 0;
|
|
18358
|
-
uniforms[59] = 0;
|
|
18359
|
-
if (vol.type === "box") {
|
|
18360
|
-
uniforms[60] = cx;
|
|
18361
|
-
uniforms[61] = cy;
|
|
18362
|
-
uniforms[62] = cz;
|
|
18363
|
-
uniforms[63] = 0;
|
|
18364
|
-
uniforms[64] = vol.dimensions[0] * 0.5;
|
|
18365
|
-
uniforms[65] = vol.dimensions[1] * 0.5;
|
|
18366
|
-
uniforms[66] = vol.dimensions[2] * 0.5;
|
|
18367
|
-
uniforms[67] = 0;
|
|
18368
|
-
} else {
|
|
18369
|
-
uniforms[60] = cx;
|
|
18370
|
-
uniforms[61] = cy;
|
|
18371
|
-
uniforms[62] = cz;
|
|
18372
|
-
uniforms[63] = vol.dimensions[0];
|
|
18373
|
-
uniforms[64] = 0;
|
|
18374
|
-
uniforms[65] = 0;
|
|
18375
|
-
uniforms[66] = 0;
|
|
18376
|
-
uniforms[67] = 0;
|
|
18377
|
-
}
|
|
18378
|
-
device.queue.writeBuffer(this.uniformBuffer, 0, uniforms.buffer);
|
|
18379
|
-
pass.setPipeline(pipeline);
|
|
17945
|
+
const [cx, cy, cz] = this._volume.center;
|
|
17946
|
+
const modelMatrix = new Float32Array(16);
|
|
17947
|
+
modelMatrix[0] = 1;
|
|
17948
|
+
modelMatrix[5] = 1;
|
|
17949
|
+
modelMatrix[10] = 1;
|
|
17950
|
+
modelMatrix[15] = 1;
|
|
17951
|
+
modelMatrix[12] = cx;
|
|
17952
|
+
modelMatrix[13] = cy;
|
|
17953
|
+
modelMatrix[14] = cz;
|
|
17954
|
+
const uniforms = new Float32Array(48);
|
|
17955
|
+
uniforms.set(this.camera.viewMatrix, 0);
|
|
17956
|
+
uniforms.set(this.camera.projectionMatrix, 16);
|
|
17957
|
+
uniforms.set(modelMatrix, 32);
|
|
17958
|
+
device.queue.writeBuffer(this.uniformBuffer, 0, uniforms);
|
|
17959
|
+
const frontVerts = this._volume.type === "box" ? this.generateBoxVertices(this.frontColor) : this.generateSphereVertices(this.frontColor);
|
|
17960
|
+
this.vertexCount = frontVerts.length / 6;
|
|
17961
|
+
if (this.vertexCount === 0) return;
|
|
17962
|
+
const needed = this.vertexCount * 24;
|
|
17963
|
+
if (needed > this.vertexBuffer.size) {
|
|
17964
|
+
this.vertexBuffer.destroy();
|
|
17965
|
+
this.vertexBuffer = device.createBuffer({ size: needed, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST });
|
|
17966
|
+
}
|
|
17967
|
+
device.queue.writeBuffer(this.vertexBuffer, 0, frontVerts.buffer);
|
|
17968
|
+
pass.setPipeline(this.frontPipeline);
|
|
18380
17969
|
pass.setBindGroup(0, this.bindGroup);
|
|
18381
17970
|
pass.setVertexBuffer(0, this.vertexBuffer);
|
|
18382
|
-
pass.draw(
|
|
17971
|
+
pass.draw(this.vertexCount);
|
|
17972
|
+
pass.setPipeline(this.behindPipeline);
|
|
17973
|
+
pass.setBindGroup(0, this.bindGroup);
|
|
17974
|
+
pass.setVertexBuffer(0, this.vertexBuffer);
|
|
17975
|
+
pass.draw(this.vertexCount);
|
|
18383
17976
|
}
|
|
18384
17977
|
destroy() {
|
|
18385
17978
|
var _a2, _b2;
|
|
@@ -18387,8 +17980,8 @@ class SelectionVolumeRenderer {
|
|
|
18387
17980
|
(_b2 = this.uniformBuffer) == null ? void 0 : _b2.destroy();
|
|
18388
17981
|
this.vertexBuffer = null;
|
|
18389
17982
|
this.uniformBuffer = null;
|
|
18390
|
-
this.
|
|
18391
|
-
this.
|
|
17983
|
+
this.frontPipeline = null;
|
|
17984
|
+
this.behindPipeline = null;
|
|
18392
17985
|
this.bindGroup = null;
|
|
18393
17986
|
}
|
|
18394
17987
|
}
|
|
@@ -18526,20 +18119,14 @@ class SplatEditor {
|
|
|
18526
18119
|
if (this.gpuRenderer) {
|
|
18527
18120
|
this.volumeRenderer = new SelectionVolumeRenderer(this.gpuRenderer, this.camera);
|
|
18528
18121
|
}
|
|
18529
|
-
this.sphereTool = new SphereSelection(
|
|
18530
|
-
|
|
18531
|
-
|
|
18532
|
-
var _a2;
|
|
18533
|
-
(_a2 = this.volumeRenderer) == null ? void 0 : _a2.setDimensions(radius, 0, 0);
|
|
18534
|
-
}
|
|
18122
|
+
this.sphereTool = new SphereSelection((radius) => {
|
|
18123
|
+
var _a2;
|
|
18124
|
+
(_a2 = this.volumeRenderer) == null ? void 0 : _a2.setDimensions(radius, 0, 0);
|
|
18535
18125
|
});
|
|
18536
18126
|
this.toolManager.register("sphere", this.sphereTool);
|
|
18537
|
-
this.boxTool = new BoxSelection(
|
|
18538
|
-
|
|
18539
|
-
|
|
18540
|
-
var _a2;
|
|
18541
|
-
(_a2 = this.volumeRenderer) == null ? void 0 : _a2.setDimensions(lx, ly, lz);
|
|
18542
|
-
}
|
|
18127
|
+
this.boxTool = new BoxSelection((lx, ly, lz) => {
|
|
18128
|
+
var _a2;
|
|
18129
|
+
(_a2 = this.volumeRenderer) == null ? void 0 : _a2.setDimensions(lx, ly, lz);
|
|
18543
18130
|
});
|
|
18544
18131
|
this.toolManager.register("box", this.boxTool);
|
|
18545
18132
|
this.gsRenderer.setEditorState(this.splatState.data);
|
|
@@ -18897,6 +18484,24 @@ class SplatEditor {
|
|
|
18897
18484
|
}
|
|
18898
18485
|
};
|
|
18899
18486
|
}
|
|
18487
|
+
// ============================================
|
|
18488
|
+
// 体积工具参数 API(供前端 UI 调用)
|
|
18489
|
+
// ============================================
|
|
18490
|
+
setBoxDimensions(lx, ly, lz) {
|
|
18491
|
+
var _a2;
|
|
18492
|
+
(_a2 = this.boxTool) == null ? void 0 : _a2.setDimensions(lx, ly, lz);
|
|
18493
|
+
}
|
|
18494
|
+
getBoxDimensions() {
|
|
18495
|
+
return this.boxTool ? [this.boxTool.lenX, this.boxTool.lenY, this.boxTool.lenZ] : [2, 2, 2];
|
|
18496
|
+
}
|
|
18497
|
+
setSphereRadius(radius) {
|
|
18498
|
+
var _a2;
|
|
18499
|
+
(_a2 = this.sphereTool) == null ? void 0 : _a2.setRadius(radius);
|
|
18500
|
+
}
|
|
18501
|
+
getSphereRadius() {
|
|
18502
|
+
var _a2;
|
|
18503
|
+
return ((_a2 = this.sphereTool) == null ? void 0 : _a2.radius) ?? 1;
|
|
18504
|
+
}
|
|
18900
18505
|
/**
|
|
18901
18506
|
* 获取模型世界空间包围盒(中心 + 尺寸)
|
|
18902
18507
|
*/
|