vim-web 0.6.0-dev.1 → 0.6.0-dev.3
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/types/core-viewers/webgl/loader/vimCollection.d.ts +3 -2
- package/dist/types/core-viewers/webgl/viewer/rendering/gpuPicker.d.ts +28 -10
- package/dist/vim-web.iife.js +290 -239
- package/dist/vim-web.iife.js.map +1 -1
- package/dist/vim-web.js +290 -239
- package/dist/vim-web.js.map +1 -1
- package/package.json +1 -1
package/dist/vim-web.iife.js
CHANGED
|
@@ -910,7 +910,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
910
910
|
return dist$3;
|
|
911
911
|
}
|
|
912
912
|
var distExports$2 = requireDist$2();
|
|
913
|
-
const MAX_VIMS =
|
|
913
|
+
const MAX_VIMS = 255;
|
|
914
914
|
let VimCollection$1 = class VimCollection {
|
|
915
915
|
constructor() {
|
|
916
916
|
// Sparse storage indexed by stable ID
|
|
@@ -48665,6 +48665,266 @@ void main() {
|
|
|
48665
48665
|
return this.mesh;
|
|
48666
48666
|
}
|
|
48667
48667
|
}
|
|
48668
|
+
const MARKER_VIM_INDEX = 255;
|
|
48669
|
+
function packPickingId(vimIndex, elementIndex) {
|
|
48670
|
+
return (vimIndex & 255) << 24 | elementIndex & 16777215;
|
|
48671
|
+
}
|
|
48672
|
+
function unpackPickingId(packedId) {
|
|
48673
|
+
return {
|
|
48674
|
+
vimIndex: packedId >>> 24,
|
|
48675
|
+
elementIndex: packedId & 16777215
|
|
48676
|
+
};
|
|
48677
|
+
}
|
|
48678
|
+
class GpuPickResult {
|
|
48679
|
+
constructor(elementIndex, vimIndex, worldPosition, worldNormal, vim, marker) {
|
|
48680
|
+
/** The element index in the vim (or marker index if vimIndex === MARKER_VIM_INDEX) */
|
|
48681
|
+
__publicField(this, "elementIndex");
|
|
48682
|
+
/** The vim index identifying which vim the element belongs to (255 = marker) */
|
|
48683
|
+
__publicField(this, "vimIndex");
|
|
48684
|
+
/** The world position of the hit */
|
|
48685
|
+
__publicField(this, "worldPosition");
|
|
48686
|
+
/** The world normal at the hit point */
|
|
48687
|
+
__publicField(this, "worldNormal");
|
|
48688
|
+
/** Reference to the vim containing the element */
|
|
48689
|
+
__publicField(this, "_vim");
|
|
48690
|
+
/** Reference to the marker if this is a marker hit */
|
|
48691
|
+
__publicField(this, "_marker");
|
|
48692
|
+
this.elementIndex = elementIndex;
|
|
48693
|
+
this.vimIndex = vimIndex;
|
|
48694
|
+
this.worldPosition = worldPosition;
|
|
48695
|
+
this.worldNormal = worldNormal;
|
|
48696
|
+
this._vim = vim;
|
|
48697
|
+
this._marker = marker;
|
|
48698
|
+
}
|
|
48699
|
+
/**
|
|
48700
|
+
* The object property for IRaycastResult interface.
|
|
48701
|
+
* Returns the Element3D or Marker for the picked object.
|
|
48702
|
+
*/
|
|
48703
|
+
get object() {
|
|
48704
|
+
return this._marker ?? this.getElement();
|
|
48705
|
+
}
|
|
48706
|
+
/**
|
|
48707
|
+
* Gets the Element3D object for the picked element.
|
|
48708
|
+
* @returns The Element3D object, or undefined if not found or if this is a marker hit
|
|
48709
|
+
*/
|
|
48710
|
+
getElement() {
|
|
48711
|
+
var _a3;
|
|
48712
|
+
return (_a3 = this._vim) == null ? void 0 : _a3.getElementFromIndex(this.elementIndex);
|
|
48713
|
+
}
|
|
48714
|
+
/**
|
|
48715
|
+
* Gets the Marker object if this is a marker hit.
|
|
48716
|
+
* @returns The Marker object, or undefined if this is an element hit
|
|
48717
|
+
*/
|
|
48718
|
+
getMarker() {
|
|
48719
|
+
return this._marker;
|
|
48720
|
+
}
|
|
48721
|
+
}
|
|
48722
|
+
class GpuPicker {
|
|
48723
|
+
constructor(renderer, camera2, scene, vims, section, width, height) {
|
|
48724
|
+
__publicField(this, "_renderer");
|
|
48725
|
+
__publicField(this, "_camera");
|
|
48726
|
+
__publicField(this, "_scene");
|
|
48727
|
+
__publicField(this, "_vims");
|
|
48728
|
+
__publicField(this, "_markers");
|
|
48729
|
+
__publicField(this, "_section");
|
|
48730
|
+
__publicField(this, "_renderTarget");
|
|
48731
|
+
__publicField(this, "_pickingMaterial");
|
|
48732
|
+
__publicField(this, "_readBuffer");
|
|
48733
|
+
// Debug visualization
|
|
48734
|
+
__publicField(this, "debug", true);
|
|
48735
|
+
__publicField(this, "_debugSphere");
|
|
48736
|
+
__publicField(this, "_debugLine");
|
|
48737
|
+
this._renderer = renderer;
|
|
48738
|
+
this._camera = camera2;
|
|
48739
|
+
this._scene = scene;
|
|
48740
|
+
this._vims = vims;
|
|
48741
|
+
this._section = section;
|
|
48742
|
+
this._renderTarget = new WebGLRenderTarget(width, height, {
|
|
48743
|
+
minFilter: NearestFilter,
|
|
48744
|
+
magFilter: NearestFilter,
|
|
48745
|
+
format: RGBAFormat,
|
|
48746
|
+
type: FloatType,
|
|
48747
|
+
depthBuffer: true
|
|
48748
|
+
});
|
|
48749
|
+
this._pickingMaterial = new PickingMaterial();
|
|
48750
|
+
this._readBuffer = new Float32Array(4);
|
|
48751
|
+
}
|
|
48752
|
+
/**
|
|
48753
|
+
* Sets the GizmoMarkers reference for marker picking.
|
|
48754
|
+
* Must be called after gizmos are initialized.
|
|
48755
|
+
*/
|
|
48756
|
+
setMarkers(markers) {
|
|
48757
|
+
this._markers = markers;
|
|
48758
|
+
}
|
|
48759
|
+
/**
|
|
48760
|
+
* Updates the render target size to match viewport.
|
|
48761
|
+
*/
|
|
48762
|
+
setSize(width, height) {
|
|
48763
|
+
this._renderTarget.setSize(width, height);
|
|
48764
|
+
}
|
|
48765
|
+
/**
|
|
48766
|
+
* Performs GPU picking at the given screen coordinates.
|
|
48767
|
+
* Returns a result object with element index, world position, and getElement() method.
|
|
48768
|
+
*
|
|
48769
|
+
* @param screenPos Screen position in 0-1 range (0,0 is top-left)
|
|
48770
|
+
* @returns Pick result with element index, world position, and getElement(), or undefined if no hit
|
|
48771
|
+
*/
|
|
48772
|
+
pick(screenPos) {
|
|
48773
|
+
var _a3;
|
|
48774
|
+
const camera2 = this._camera.three;
|
|
48775
|
+
camera2.updateMatrixWorld(true);
|
|
48776
|
+
const currentRenderTarget = this._renderer.getRenderTarget();
|
|
48777
|
+
const currentOverrideMaterial = this._scene.threeScene.overrideMaterial;
|
|
48778
|
+
const currentBackground = this._scene.threeScene.background;
|
|
48779
|
+
this._pickingMaterial.updateCamera(camera2);
|
|
48780
|
+
if (this._section.active) {
|
|
48781
|
+
this._pickingMaterial.clippingPlanes = this._section.clippingPlanes;
|
|
48782
|
+
} else {
|
|
48783
|
+
this._pickingMaterial.clippingPlanes = [];
|
|
48784
|
+
}
|
|
48785
|
+
this._scene.threeScene.background = null;
|
|
48786
|
+
this._scene.threeScene.overrideMaterial = this._pickingMaterial.material;
|
|
48787
|
+
camera2.layers.disable(1);
|
|
48788
|
+
this._renderer.setRenderTarget(this._renderTarget);
|
|
48789
|
+
this._renderer.setClearColor(0, 0);
|
|
48790
|
+
this._renderer.clear();
|
|
48791
|
+
this._renderer.render(this._scene.threeScene, camera2);
|
|
48792
|
+
this._renderer.setRenderTarget(currentRenderTarget);
|
|
48793
|
+
camera2.layers.enable(1);
|
|
48794
|
+
this._scene.threeScene.overrideMaterial = currentOverrideMaterial;
|
|
48795
|
+
this._scene.threeScene.background = currentBackground;
|
|
48796
|
+
const pixelX = Math.floor(screenPos.x * this._renderTarget.width);
|
|
48797
|
+
const pixelY = Math.floor((1 - screenPos.y) * this._renderTarget.height);
|
|
48798
|
+
this._renderer.readRenderTargetPixels(
|
|
48799
|
+
this._renderTarget,
|
|
48800
|
+
pixelX,
|
|
48801
|
+
pixelY,
|
|
48802
|
+
1,
|
|
48803
|
+
1,
|
|
48804
|
+
this._readBuffer
|
|
48805
|
+
);
|
|
48806
|
+
const depth = this._readBuffer[1];
|
|
48807
|
+
const normalX = this._readBuffer[2];
|
|
48808
|
+
const normalY = this._readBuffer[3];
|
|
48809
|
+
if (depth <= 0) {
|
|
48810
|
+
return void 0;
|
|
48811
|
+
}
|
|
48812
|
+
const dataView = new DataView(this._readBuffer.buffer);
|
|
48813
|
+
const packedId = dataView.getUint32(0, true);
|
|
48814
|
+
const { vimIndex, elementIndex } = unpackPickingId(packedId);
|
|
48815
|
+
const normalZ = Math.sqrt(Math.max(0, 1 - normalX * normalX - normalY * normalY));
|
|
48816
|
+
const worldNormal = new Vector3(normalX, normalY, normalZ).normalize();
|
|
48817
|
+
const worldPosition = this.reconstructWorldPosition(screenPos, depth, camera2);
|
|
48818
|
+
if (vimIndex === MARKER_VIM_INDEX) {
|
|
48819
|
+
const marker = (_a3 = this._markers) == null ? void 0 : _a3.getMarkerFromIndex(elementIndex);
|
|
48820
|
+
const result2 = new GpuPickResult(elementIndex, vimIndex, worldPosition, worldNormal, void 0, marker);
|
|
48821
|
+
if (this.debug) {
|
|
48822
|
+
this.showDebugVisuals(result2);
|
|
48823
|
+
}
|
|
48824
|
+
return result2;
|
|
48825
|
+
}
|
|
48826
|
+
const vim = this._vims.getFromId(vimIndex);
|
|
48827
|
+
const result = new GpuPickResult(elementIndex, vimIndex, worldPosition, worldNormal, vim);
|
|
48828
|
+
if (this.debug) {
|
|
48829
|
+
this.showDebugVisuals(result);
|
|
48830
|
+
}
|
|
48831
|
+
return result;
|
|
48832
|
+
}
|
|
48833
|
+
/**
|
|
48834
|
+
* Shows debug visuals (sphere at hit point, line showing normal direction).
|
|
48835
|
+
*/
|
|
48836
|
+
showDebugVisuals(result) {
|
|
48837
|
+
this.clearDebugVisuals();
|
|
48838
|
+
const sphereGeometry = new SphereGeometry(0.5, 16, 16);
|
|
48839
|
+
const sphereMaterial = new MeshBasicMaterial({ color: 16711680 });
|
|
48840
|
+
this._debugSphere = new Mesh(sphereGeometry, sphereMaterial);
|
|
48841
|
+
this._debugSphere.position.copy(result.worldPosition);
|
|
48842
|
+
this._debugSphere.layers.set(1);
|
|
48843
|
+
this._scene.threeScene.add(this._debugSphere);
|
|
48844
|
+
const lineLength = 2;
|
|
48845
|
+
const lineStart = result.worldPosition.clone();
|
|
48846
|
+
const lineEnd = result.worldPosition.clone().add(result.worldNormal.clone().multiplyScalar(lineLength));
|
|
48847
|
+
const lineGeometry = new BufferGeometry().setFromPoints([lineStart, lineEnd]);
|
|
48848
|
+
const lineMaterial = new LineBasicMaterial({ color: 65280, linewidth: 2 });
|
|
48849
|
+
this._debugLine = new Line(lineGeometry, lineMaterial);
|
|
48850
|
+
this._debugLine.layers.set(1);
|
|
48851
|
+
this._scene.threeScene.add(this._debugLine);
|
|
48852
|
+
this._renderer.domElement.dispatchEvent(new Event("needsUpdate"));
|
|
48853
|
+
}
|
|
48854
|
+
/**
|
|
48855
|
+
* Reconstructs world position from screen coordinates and depth value.
|
|
48856
|
+
*/
|
|
48857
|
+
reconstructWorldPosition(screenPos, depth, camera2) {
|
|
48858
|
+
const ndcX = screenPos.x * 2 - 1;
|
|
48859
|
+
const ndcY = (1 - screenPos.y) * 2 - 1;
|
|
48860
|
+
const rayEnd = new Vector3(ndcX, ndcY, 1).unproject(camera2);
|
|
48861
|
+
const rayDir = rayEnd.sub(camera2.position).normalize();
|
|
48862
|
+
const cameraDir = new Vector3();
|
|
48863
|
+
camera2.getWorldDirection(cameraDir);
|
|
48864
|
+
const t = depth / rayDir.dot(cameraDir);
|
|
48865
|
+
const worldPos = camera2.position.clone().add(rayDir.clone().multiplyScalar(t));
|
|
48866
|
+
return worldPos;
|
|
48867
|
+
}
|
|
48868
|
+
/**
|
|
48869
|
+
* Removes debug visuals (sphere and normal line) from the scene.
|
|
48870
|
+
*/
|
|
48871
|
+
clearDebugVisuals() {
|
|
48872
|
+
if (this._debugSphere) {
|
|
48873
|
+
this._scene.threeScene.remove(this._debugSphere);
|
|
48874
|
+
this._debugSphere.geometry.dispose();
|
|
48875
|
+
this._debugSphere.material.dispose();
|
|
48876
|
+
this._debugSphere = void 0;
|
|
48877
|
+
}
|
|
48878
|
+
if (this._debugLine) {
|
|
48879
|
+
this._scene.threeScene.remove(this._debugLine);
|
|
48880
|
+
this._debugLine.geometry.dispose();
|
|
48881
|
+
this._debugLine.material.dispose();
|
|
48882
|
+
this._debugLine = void 0;
|
|
48883
|
+
}
|
|
48884
|
+
}
|
|
48885
|
+
/**
|
|
48886
|
+
* Raycasts from camera to the screen position to find the first object hit.
|
|
48887
|
+
* Implements IRaycaster interface.
|
|
48888
|
+
* @param position - Screen position in 0-1 range (0,0 is top-left)
|
|
48889
|
+
* @returns A promise that resolves to the raycast result, or undefined if no hit
|
|
48890
|
+
*/
|
|
48891
|
+
raycastFromScreen(position) {
|
|
48892
|
+
return Promise.resolve(this.pick(position));
|
|
48893
|
+
}
|
|
48894
|
+
/**
|
|
48895
|
+
* Raycasts from camera towards a world position to find the first object hit.
|
|
48896
|
+
* Implements IRaycaster interface.
|
|
48897
|
+
* @param position - The world position to raycast towards
|
|
48898
|
+
* @returns A promise that resolves to the raycast result, or undefined if no hit
|
|
48899
|
+
*/
|
|
48900
|
+
raycastFromWorld(position) {
|
|
48901
|
+
const screenPos = this.worldToScreen(position);
|
|
48902
|
+
if (!screenPos) return Promise.resolve(void 0);
|
|
48903
|
+
return Promise.resolve(this.pick(screenPos));
|
|
48904
|
+
}
|
|
48905
|
+
/**
|
|
48906
|
+
* Converts a world position to screen coordinates (0-1 range).
|
|
48907
|
+
* @param worldPos - The world position to convert
|
|
48908
|
+
* @returns Screen position in 0-1 range, or undefined if behind camera
|
|
48909
|
+
*/
|
|
48910
|
+
worldToScreen(worldPos) {
|
|
48911
|
+
const camera2 = this._camera.three;
|
|
48912
|
+
camera2.updateMatrixWorld(true);
|
|
48913
|
+
const ndc = worldPos.clone().project(camera2);
|
|
48914
|
+
if (ndc.z > 1) return void 0;
|
|
48915
|
+
const screenX = (ndc.x + 1) / 2;
|
|
48916
|
+
const screenY = (1 - ndc.y) / 2;
|
|
48917
|
+
return new Vector2(screenX, screenY);
|
|
48918
|
+
}
|
|
48919
|
+
/**
|
|
48920
|
+
* Disposes of all resources.
|
|
48921
|
+
*/
|
|
48922
|
+
dispose() {
|
|
48923
|
+
this.clearDebugVisuals();
|
|
48924
|
+
this._renderTarget.dispose();
|
|
48925
|
+
this._pickingMaterial.dispose();
|
|
48926
|
+
}
|
|
48927
|
+
}
|
|
48668
48928
|
class GizmoMarkers {
|
|
48669
48929
|
/**
|
|
48670
48930
|
* Constructs the marker manager and sets up an initial instanced mesh.
|
|
@@ -48708,6 +48968,12 @@ void main() {
|
|
|
48708
48968
|
mesh.count = 0;
|
|
48709
48969
|
mesh.frustumCulled = false;
|
|
48710
48970
|
mesh.layers.enableAll();
|
|
48971
|
+
const packedIdArray = new Uint32Array(capacity);
|
|
48972
|
+
const packedIdAttr = new InstancedBufferAttribute(packedIdArray, 1);
|
|
48973
|
+
mesh.geometry.setAttribute("packedId", packedIdAttr);
|
|
48974
|
+
const ignoreArray = new Float32Array(capacity);
|
|
48975
|
+
const ignoreAttr = new InstancedBufferAttribute(ignoreArray, 1);
|
|
48976
|
+
mesh.geometry.setAttribute("ignore", ignoreAttr);
|
|
48711
48977
|
this._viewer.renderer.add(mesh);
|
|
48712
48978
|
return mesh;
|
|
48713
48979
|
}
|
|
@@ -48717,12 +48983,20 @@ void main() {
|
|
|
48717
48983
|
resizeMesh() {
|
|
48718
48984
|
const larger = this.createMesh(this._mesh, this._mesh.count * 2);
|
|
48719
48985
|
larger.count = this._mesh.count;
|
|
48986
|
+
const oldPackedId = this._mesh.geometry.getAttribute("packedId");
|
|
48987
|
+
const oldIgnore = this._mesh.geometry.getAttribute("ignore");
|
|
48988
|
+
const newPackedId = larger.geometry.getAttribute("packedId");
|
|
48989
|
+
const newIgnore = larger.geometry.getAttribute("ignore");
|
|
48720
48990
|
for (let i2 = 0; i2 < this._mesh.count; i2++) {
|
|
48721
48991
|
this._mesh.getMatrixAt(i2, this._reusableMatrix);
|
|
48722
48992
|
larger.setMatrixAt(i2, this._reusableMatrix);
|
|
48993
|
+
newPackedId.setX(i2, oldPackedId.getX(i2));
|
|
48994
|
+
newIgnore.setX(i2, oldIgnore.getX(i2));
|
|
48723
48995
|
const sub = new SimpleInstanceSubmesh(larger, i2);
|
|
48724
48996
|
this._markers[i2].updateMesh(sub);
|
|
48725
48997
|
}
|
|
48998
|
+
newPackedId.needsUpdate = true;
|
|
48999
|
+
newIgnore.needsUpdate = true;
|
|
48726
49000
|
this._viewer.renderer.remove(this._mesh);
|
|
48727
49001
|
this._mesh = larger;
|
|
48728
49002
|
}
|
|
@@ -48736,8 +49010,12 @@ void main() {
|
|
|
48736
49010
|
if (this._mesh.count === this._mesh.instanceMatrix.count) {
|
|
48737
49011
|
this.resizeMesh();
|
|
48738
49012
|
}
|
|
49013
|
+
const markerIndex = this._mesh.count;
|
|
48739
49014
|
this._mesh.count += 1;
|
|
48740
|
-
const
|
|
49015
|
+
const packedIdAttr = this._mesh.geometry.getAttribute("packedId");
|
|
49016
|
+
packedIdAttr.setX(markerIndex, packPickingId(MARKER_VIM_INDEX, markerIndex));
|
|
49017
|
+
packedIdAttr.needsUpdate = true;
|
|
49018
|
+
const sub = new SimpleInstanceSubmesh(this._mesh, markerIndex);
|
|
48741
49019
|
const marker = new Marker(this._viewer, sub);
|
|
48742
49020
|
marker.position = position;
|
|
48743
49021
|
this._markers.push(marker);
|
|
@@ -48758,7 +49036,10 @@ void main() {
|
|
|
48758
49036
|
this._mesh.getMatrixAt(fromIndex, this._reusableMatrix);
|
|
48759
49037
|
this._mesh.setMatrixAt(destIndex, this._reusableMatrix);
|
|
48760
49038
|
this._mesh.instanceMatrix.needsUpdate = true;
|
|
48761
|
-
const
|
|
49039
|
+
const packedIdAttr = this._mesh.geometry.getAttribute("packedId");
|
|
49040
|
+
packedIdAttr.setX(destIndex, packPickingId(MARKER_VIM_INDEX, destIndex));
|
|
49041
|
+
packedIdAttr.needsUpdate = true;
|
|
49042
|
+
const sub = new SimpleInstanceSubmesh(this._mesh, destIndex);
|
|
48762
49043
|
lastMarker.updateMesh(sub);
|
|
48763
49044
|
}
|
|
48764
49045
|
this._markers.length -= 1;
|
|
@@ -53659,238 +53940,6 @@ void main() {
|
|
|
53659
53940
|
this.axes.dispose();
|
|
53660
53941
|
}
|
|
53661
53942
|
}
|
|
53662
|
-
function packPickingId(vimIndex, elementIndex) {
|
|
53663
|
-
return (vimIndex & 255) << 24 | elementIndex & 16777215;
|
|
53664
|
-
}
|
|
53665
|
-
function unpackPickingId(packedId) {
|
|
53666
|
-
return {
|
|
53667
|
-
vimIndex: packedId >>> 24,
|
|
53668
|
-
elementIndex: packedId & 16777215
|
|
53669
|
-
};
|
|
53670
|
-
}
|
|
53671
|
-
class GpuPickResult {
|
|
53672
|
-
constructor(elementIndex, vimIndex, worldPosition, worldNormal, vim) {
|
|
53673
|
-
/** The element index in the vim */
|
|
53674
|
-
__publicField(this, "elementIndex");
|
|
53675
|
-
/** The vim index identifying which vim the element belongs to */
|
|
53676
|
-
__publicField(this, "vimIndex");
|
|
53677
|
-
/** The world position of the hit */
|
|
53678
|
-
__publicField(this, "worldPosition");
|
|
53679
|
-
/** The world normal at the hit point */
|
|
53680
|
-
__publicField(this, "worldNormal");
|
|
53681
|
-
/** Reference to the vim containing the element */
|
|
53682
|
-
__publicField(this, "_vim");
|
|
53683
|
-
this.elementIndex = elementIndex;
|
|
53684
|
-
this.vimIndex = vimIndex;
|
|
53685
|
-
this.worldPosition = worldPosition;
|
|
53686
|
-
this.worldNormal = worldNormal;
|
|
53687
|
-
this._vim = vim;
|
|
53688
|
-
}
|
|
53689
|
-
/**
|
|
53690
|
-
* The object property for IRaycastResult interface.
|
|
53691
|
-
* Returns the Element3D for the picked element.
|
|
53692
|
-
*/
|
|
53693
|
-
get object() {
|
|
53694
|
-
return this.getElement();
|
|
53695
|
-
}
|
|
53696
|
-
/**
|
|
53697
|
-
* Gets the Element3D object for the picked element.
|
|
53698
|
-
* @returns The Element3D object, or undefined if not found
|
|
53699
|
-
*/
|
|
53700
|
-
getElement() {
|
|
53701
|
-
var _a3;
|
|
53702
|
-
return (_a3 = this._vim) == null ? void 0 : _a3.getElementFromIndex(this.elementIndex);
|
|
53703
|
-
}
|
|
53704
|
-
}
|
|
53705
|
-
class GpuPicker {
|
|
53706
|
-
constructor(renderer, camera2, scene, vims, section, width, height) {
|
|
53707
|
-
__publicField(this, "_renderer");
|
|
53708
|
-
__publicField(this, "_camera");
|
|
53709
|
-
__publicField(this, "_scene");
|
|
53710
|
-
__publicField(this, "_vims");
|
|
53711
|
-
__publicField(this, "_section");
|
|
53712
|
-
__publicField(this, "_renderTarget");
|
|
53713
|
-
__publicField(this, "_pickingMaterial");
|
|
53714
|
-
__publicField(this, "_readBuffer");
|
|
53715
|
-
// Debug visualization
|
|
53716
|
-
__publicField(this, "debug", true);
|
|
53717
|
-
__publicField(this, "_debugSphere");
|
|
53718
|
-
__publicField(this, "_debugLine");
|
|
53719
|
-
this._renderer = renderer;
|
|
53720
|
-
this._camera = camera2;
|
|
53721
|
-
this._scene = scene;
|
|
53722
|
-
this._vims = vims;
|
|
53723
|
-
this._section = section;
|
|
53724
|
-
this._renderTarget = new WebGLRenderTarget(width, height, {
|
|
53725
|
-
minFilter: NearestFilter,
|
|
53726
|
-
magFilter: NearestFilter,
|
|
53727
|
-
format: RGBAFormat,
|
|
53728
|
-
type: FloatType,
|
|
53729
|
-
depthBuffer: true
|
|
53730
|
-
});
|
|
53731
|
-
this._pickingMaterial = new PickingMaterial();
|
|
53732
|
-
this._readBuffer = new Float32Array(4);
|
|
53733
|
-
}
|
|
53734
|
-
/**
|
|
53735
|
-
* Updates the render target size to match viewport.
|
|
53736
|
-
*/
|
|
53737
|
-
setSize(width, height) {
|
|
53738
|
-
this._renderTarget.setSize(width, height);
|
|
53739
|
-
}
|
|
53740
|
-
/**
|
|
53741
|
-
* Performs GPU picking at the given screen coordinates.
|
|
53742
|
-
* Returns a result object with element index, world position, and getElement() method.
|
|
53743
|
-
*
|
|
53744
|
-
* @param screenPos Screen position in 0-1 range (0,0 is top-left)
|
|
53745
|
-
* @returns Pick result with element index, world position, and getElement(), or undefined if no hit
|
|
53746
|
-
*/
|
|
53747
|
-
pick(screenPos) {
|
|
53748
|
-
const camera2 = this._camera.three;
|
|
53749
|
-
camera2.updateMatrixWorld(true);
|
|
53750
|
-
const currentRenderTarget = this._renderer.getRenderTarget();
|
|
53751
|
-
const currentOverrideMaterial = this._scene.threeScene.overrideMaterial;
|
|
53752
|
-
const currentBackground = this._scene.threeScene.background;
|
|
53753
|
-
this._pickingMaterial.updateCamera(camera2);
|
|
53754
|
-
if (this._section.active) {
|
|
53755
|
-
this._pickingMaterial.clippingPlanes = this._section.clippingPlanes;
|
|
53756
|
-
} else {
|
|
53757
|
-
this._pickingMaterial.clippingPlanes = [];
|
|
53758
|
-
}
|
|
53759
|
-
this._scene.threeScene.background = null;
|
|
53760
|
-
this._scene.threeScene.overrideMaterial = this._pickingMaterial.material;
|
|
53761
|
-
camera2.layers.disable(1);
|
|
53762
|
-
this._renderer.setRenderTarget(this._renderTarget);
|
|
53763
|
-
this._renderer.setClearColor(0, 0);
|
|
53764
|
-
this._renderer.clear();
|
|
53765
|
-
this._renderer.render(this._scene.threeScene, camera2);
|
|
53766
|
-
this._renderer.setRenderTarget(currentRenderTarget);
|
|
53767
|
-
camera2.layers.enable(1);
|
|
53768
|
-
this._scene.threeScene.overrideMaterial = currentOverrideMaterial;
|
|
53769
|
-
this._scene.threeScene.background = currentBackground;
|
|
53770
|
-
const pixelX = Math.floor(screenPos.x * this._renderTarget.width);
|
|
53771
|
-
const pixelY = Math.floor((1 - screenPos.y) * this._renderTarget.height);
|
|
53772
|
-
this._renderer.readRenderTargetPixels(
|
|
53773
|
-
this._renderTarget,
|
|
53774
|
-
pixelX,
|
|
53775
|
-
pixelY,
|
|
53776
|
-
1,
|
|
53777
|
-
1,
|
|
53778
|
-
this._readBuffer
|
|
53779
|
-
);
|
|
53780
|
-
const depth = this._readBuffer[1];
|
|
53781
|
-
const normalX = this._readBuffer[2];
|
|
53782
|
-
const normalY = this._readBuffer[3];
|
|
53783
|
-
if (depth <= 0) {
|
|
53784
|
-
return void 0;
|
|
53785
|
-
}
|
|
53786
|
-
const dataView = new DataView(this._readBuffer.buffer);
|
|
53787
|
-
const packedId = dataView.getUint32(0, true);
|
|
53788
|
-
const { vimIndex, elementIndex } = unpackPickingId(packedId);
|
|
53789
|
-
const normalZ = Math.sqrt(Math.max(0, 1 - normalX * normalX - normalY * normalY));
|
|
53790
|
-
const worldNormal = new Vector3(normalX, normalY, normalZ).normalize();
|
|
53791
|
-
const worldPosition = this.reconstructWorldPosition(screenPos, depth, camera2);
|
|
53792
|
-
const vim = this._vims.getFromId(vimIndex);
|
|
53793
|
-
const result = new GpuPickResult(elementIndex, vimIndex, worldPosition, worldNormal, vim);
|
|
53794
|
-
if (this.debug) {
|
|
53795
|
-
this.showDebugVisuals(result);
|
|
53796
|
-
}
|
|
53797
|
-
return result;
|
|
53798
|
-
}
|
|
53799
|
-
/**
|
|
53800
|
-
* Shows debug visuals (sphere at hit point, line showing normal direction).
|
|
53801
|
-
*/
|
|
53802
|
-
showDebugVisuals(result) {
|
|
53803
|
-
this.clearDebugVisuals();
|
|
53804
|
-
const sphereGeometry = new SphereGeometry(0.5, 16, 16);
|
|
53805
|
-
const sphereMaterial = new MeshBasicMaterial({ color: 16711680 });
|
|
53806
|
-
this._debugSphere = new Mesh(sphereGeometry, sphereMaterial);
|
|
53807
|
-
this._debugSphere.position.copy(result.worldPosition);
|
|
53808
|
-
this._debugSphere.layers.set(1);
|
|
53809
|
-
this._scene.threeScene.add(this._debugSphere);
|
|
53810
|
-
const lineLength = 2;
|
|
53811
|
-
const lineStart = result.worldPosition.clone();
|
|
53812
|
-
const lineEnd = result.worldPosition.clone().add(result.worldNormal.clone().multiplyScalar(lineLength));
|
|
53813
|
-
const lineGeometry = new BufferGeometry().setFromPoints([lineStart, lineEnd]);
|
|
53814
|
-
const lineMaterial = new LineBasicMaterial({ color: 65280, linewidth: 2 });
|
|
53815
|
-
this._debugLine = new Line(lineGeometry, lineMaterial);
|
|
53816
|
-
this._debugLine.layers.set(1);
|
|
53817
|
-
this._scene.threeScene.add(this._debugLine);
|
|
53818
|
-
this._renderer.domElement.dispatchEvent(new Event("needsUpdate"));
|
|
53819
|
-
}
|
|
53820
|
-
/**
|
|
53821
|
-
* Reconstructs world position from screen coordinates and depth value.
|
|
53822
|
-
*/
|
|
53823
|
-
reconstructWorldPosition(screenPos, depth, camera2) {
|
|
53824
|
-
const ndcX = screenPos.x * 2 - 1;
|
|
53825
|
-
const ndcY = (1 - screenPos.y) * 2 - 1;
|
|
53826
|
-
const rayEnd = new Vector3(ndcX, ndcY, 1).unproject(camera2);
|
|
53827
|
-
const rayDir = rayEnd.sub(camera2.position).normalize();
|
|
53828
|
-
const cameraDir = new Vector3();
|
|
53829
|
-
camera2.getWorldDirection(cameraDir);
|
|
53830
|
-
const t = depth / rayDir.dot(cameraDir);
|
|
53831
|
-
const worldPos = camera2.position.clone().add(rayDir.clone().multiplyScalar(t));
|
|
53832
|
-
return worldPos;
|
|
53833
|
-
}
|
|
53834
|
-
/**
|
|
53835
|
-
* Removes debug visuals (sphere and normal line) from the scene.
|
|
53836
|
-
*/
|
|
53837
|
-
clearDebugVisuals() {
|
|
53838
|
-
if (this._debugSphere) {
|
|
53839
|
-
this._scene.threeScene.remove(this._debugSphere);
|
|
53840
|
-
this._debugSphere.geometry.dispose();
|
|
53841
|
-
this._debugSphere.material.dispose();
|
|
53842
|
-
this._debugSphere = void 0;
|
|
53843
|
-
}
|
|
53844
|
-
if (this._debugLine) {
|
|
53845
|
-
this._scene.threeScene.remove(this._debugLine);
|
|
53846
|
-
this._debugLine.geometry.dispose();
|
|
53847
|
-
this._debugLine.material.dispose();
|
|
53848
|
-
this._debugLine = void 0;
|
|
53849
|
-
}
|
|
53850
|
-
}
|
|
53851
|
-
/**
|
|
53852
|
-
* Raycasts from camera to the screen position to find the first object hit.
|
|
53853
|
-
* Implements IRaycaster interface.
|
|
53854
|
-
* @param position - Screen position in 0-1 range (0,0 is top-left)
|
|
53855
|
-
* @returns A promise that resolves to the raycast result, or undefined if no hit
|
|
53856
|
-
*/
|
|
53857
|
-
raycastFromScreen(position) {
|
|
53858
|
-
return Promise.resolve(this.pick(position));
|
|
53859
|
-
}
|
|
53860
|
-
/**
|
|
53861
|
-
* Raycasts from camera towards a world position to find the first object hit.
|
|
53862
|
-
* Implements IRaycaster interface.
|
|
53863
|
-
* @param position - The world position to raycast towards
|
|
53864
|
-
* @returns A promise that resolves to the raycast result, or undefined if no hit
|
|
53865
|
-
*/
|
|
53866
|
-
raycastFromWorld(position) {
|
|
53867
|
-
const screenPos = this.worldToScreen(position);
|
|
53868
|
-
if (!screenPos) return Promise.resolve(void 0);
|
|
53869
|
-
return Promise.resolve(this.pick(screenPos));
|
|
53870
|
-
}
|
|
53871
|
-
/**
|
|
53872
|
-
* Converts a world position to screen coordinates (0-1 range).
|
|
53873
|
-
* @param worldPos - The world position to convert
|
|
53874
|
-
* @returns Screen position in 0-1 range, or undefined if behind camera
|
|
53875
|
-
*/
|
|
53876
|
-
worldToScreen(worldPos) {
|
|
53877
|
-
const camera2 = this._camera.three;
|
|
53878
|
-
camera2.updateMatrixWorld(true);
|
|
53879
|
-
const ndc = worldPos.clone().project(camera2);
|
|
53880
|
-
if (ndc.z > 1) return void 0;
|
|
53881
|
-
const screenX = (ndc.x + 1) / 2;
|
|
53882
|
-
const screenY = (1 - ndc.y) / 2;
|
|
53883
|
-
return new Vector2(screenX, screenY);
|
|
53884
|
-
}
|
|
53885
|
-
/**
|
|
53886
|
-
* Disposes of all resources.
|
|
53887
|
-
*/
|
|
53888
|
-
dispose() {
|
|
53889
|
-
this.clearDebugVisuals();
|
|
53890
|
-
this._renderTarget.dispose();
|
|
53891
|
-
this._pickingMaterial.dispose();
|
|
53892
|
-
}
|
|
53893
|
-
}
|
|
53894
53943
|
function getAverageBoundingBox(positions, thresholdSpan = 1e3, framingDistanceMultiplier = 2) {
|
|
53895
53944
|
if (positions.length === 0) {
|
|
53896
53945
|
return new Box3();
|
|
@@ -55039,14 +55088,14 @@ void main() {
|
|
|
55039
55088
|
selectAtPointer: async (pos, add) => {
|
|
55040
55089
|
const result = await viewer.raycaster.raycastFromScreen(pos);
|
|
55041
55090
|
if (add) {
|
|
55042
|
-
viewer.selection.add(result.object);
|
|
55091
|
+
viewer.selection.add(result == null ? void 0 : result.object);
|
|
55043
55092
|
} else {
|
|
55044
|
-
viewer.selection.select(result.object);
|
|
55093
|
+
viewer.selection.select(result == null ? void 0 : result.object);
|
|
55045
55094
|
}
|
|
55046
55095
|
},
|
|
55047
55096
|
frameAtPointer: async (pos) => {
|
|
55048
55097
|
const result = await viewer.raycaster.raycastFromScreen(pos);
|
|
55049
|
-
viewer.camera.lerp(0.75).frame(result.object ?? "all");
|
|
55098
|
+
viewer.camera.lerp(0.75).frame((result == null ? void 0 : result.object) ?? "all");
|
|
55050
55099
|
},
|
|
55051
55100
|
zoom: async (value, pos) => {
|
|
55052
55101
|
if (pos) {
|
|
@@ -56349,7 +56398,7 @@ void main() {
|
|
|
56349
56398
|
this.environment = new Environment(this.camera, this.renderer, this.materials, this.settings);
|
|
56350
56399
|
this.selection = createSelection$1();
|
|
56351
56400
|
const size = this.renderer.renderer.getSize(new Vector2());
|
|
56352
|
-
|
|
56401
|
+
const gpuPicker = new GpuPicker(
|
|
56353
56402
|
this.renderer.renderer,
|
|
56354
56403
|
this._camera,
|
|
56355
56404
|
scene,
|
|
@@ -56358,6 +56407,8 @@ void main() {
|
|
|
56358
56407
|
size.x || 1,
|
|
56359
56408
|
size.y || 1
|
|
56360
56409
|
);
|
|
56410
|
+
gpuPicker.setMarkers(this.gizmos.markers);
|
|
56411
|
+
this.raycaster = gpuPicker;
|
|
56361
56412
|
this.viewport.onResize.sub(() => {
|
|
56362
56413
|
const size2 = this.viewport.getParentSize();
|
|
56363
56414
|
this.raycaster.setSize(size2.x, size2.y);
|