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.js
CHANGED
|
@@ -894,7 +894,7 @@ function requireDist$2() {
|
|
|
894
894
|
return dist$3;
|
|
895
895
|
}
|
|
896
896
|
var distExports$2 = requireDist$2();
|
|
897
|
-
const MAX_VIMS =
|
|
897
|
+
const MAX_VIMS = 255;
|
|
898
898
|
let VimCollection$1 = class VimCollection {
|
|
899
899
|
constructor() {
|
|
900
900
|
// Sparse storage indexed by stable ID
|
|
@@ -48649,6 +48649,266 @@ class SimpleInstanceSubmesh {
|
|
|
48649
48649
|
return this.mesh;
|
|
48650
48650
|
}
|
|
48651
48651
|
}
|
|
48652
|
+
const MARKER_VIM_INDEX = 255;
|
|
48653
|
+
function packPickingId(vimIndex, elementIndex) {
|
|
48654
|
+
return (vimIndex & 255) << 24 | elementIndex & 16777215;
|
|
48655
|
+
}
|
|
48656
|
+
function unpackPickingId(packedId) {
|
|
48657
|
+
return {
|
|
48658
|
+
vimIndex: packedId >>> 24,
|
|
48659
|
+
elementIndex: packedId & 16777215
|
|
48660
|
+
};
|
|
48661
|
+
}
|
|
48662
|
+
class GpuPickResult {
|
|
48663
|
+
constructor(elementIndex, vimIndex, worldPosition, worldNormal, vim, marker) {
|
|
48664
|
+
/** The element index in the vim (or marker index if vimIndex === MARKER_VIM_INDEX) */
|
|
48665
|
+
__publicField(this, "elementIndex");
|
|
48666
|
+
/** The vim index identifying which vim the element belongs to (255 = marker) */
|
|
48667
|
+
__publicField(this, "vimIndex");
|
|
48668
|
+
/** The world position of the hit */
|
|
48669
|
+
__publicField(this, "worldPosition");
|
|
48670
|
+
/** The world normal at the hit point */
|
|
48671
|
+
__publicField(this, "worldNormal");
|
|
48672
|
+
/** Reference to the vim containing the element */
|
|
48673
|
+
__publicField(this, "_vim");
|
|
48674
|
+
/** Reference to the marker if this is a marker hit */
|
|
48675
|
+
__publicField(this, "_marker");
|
|
48676
|
+
this.elementIndex = elementIndex;
|
|
48677
|
+
this.vimIndex = vimIndex;
|
|
48678
|
+
this.worldPosition = worldPosition;
|
|
48679
|
+
this.worldNormal = worldNormal;
|
|
48680
|
+
this._vim = vim;
|
|
48681
|
+
this._marker = marker;
|
|
48682
|
+
}
|
|
48683
|
+
/**
|
|
48684
|
+
* The object property for IRaycastResult interface.
|
|
48685
|
+
* Returns the Element3D or Marker for the picked object.
|
|
48686
|
+
*/
|
|
48687
|
+
get object() {
|
|
48688
|
+
return this._marker ?? this.getElement();
|
|
48689
|
+
}
|
|
48690
|
+
/**
|
|
48691
|
+
* Gets the Element3D object for the picked element.
|
|
48692
|
+
* @returns The Element3D object, or undefined if not found or if this is a marker hit
|
|
48693
|
+
*/
|
|
48694
|
+
getElement() {
|
|
48695
|
+
var _a3;
|
|
48696
|
+
return (_a3 = this._vim) == null ? void 0 : _a3.getElementFromIndex(this.elementIndex);
|
|
48697
|
+
}
|
|
48698
|
+
/**
|
|
48699
|
+
* Gets the Marker object if this is a marker hit.
|
|
48700
|
+
* @returns The Marker object, or undefined if this is an element hit
|
|
48701
|
+
*/
|
|
48702
|
+
getMarker() {
|
|
48703
|
+
return this._marker;
|
|
48704
|
+
}
|
|
48705
|
+
}
|
|
48706
|
+
class GpuPicker {
|
|
48707
|
+
constructor(renderer, camera2, scene, vims, section, width, height) {
|
|
48708
|
+
__publicField(this, "_renderer");
|
|
48709
|
+
__publicField(this, "_camera");
|
|
48710
|
+
__publicField(this, "_scene");
|
|
48711
|
+
__publicField(this, "_vims");
|
|
48712
|
+
__publicField(this, "_markers");
|
|
48713
|
+
__publicField(this, "_section");
|
|
48714
|
+
__publicField(this, "_renderTarget");
|
|
48715
|
+
__publicField(this, "_pickingMaterial");
|
|
48716
|
+
__publicField(this, "_readBuffer");
|
|
48717
|
+
// Debug visualization
|
|
48718
|
+
__publicField(this, "debug", true);
|
|
48719
|
+
__publicField(this, "_debugSphere");
|
|
48720
|
+
__publicField(this, "_debugLine");
|
|
48721
|
+
this._renderer = renderer;
|
|
48722
|
+
this._camera = camera2;
|
|
48723
|
+
this._scene = scene;
|
|
48724
|
+
this._vims = vims;
|
|
48725
|
+
this._section = section;
|
|
48726
|
+
this._renderTarget = new WebGLRenderTarget(width, height, {
|
|
48727
|
+
minFilter: NearestFilter,
|
|
48728
|
+
magFilter: NearestFilter,
|
|
48729
|
+
format: RGBAFormat,
|
|
48730
|
+
type: FloatType,
|
|
48731
|
+
depthBuffer: true
|
|
48732
|
+
});
|
|
48733
|
+
this._pickingMaterial = new PickingMaterial();
|
|
48734
|
+
this._readBuffer = new Float32Array(4);
|
|
48735
|
+
}
|
|
48736
|
+
/**
|
|
48737
|
+
* Sets the GizmoMarkers reference for marker picking.
|
|
48738
|
+
* Must be called after gizmos are initialized.
|
|
48739
|
+
*/
|
|
48740
|
+
setMarkers(markers) {
|
|
48741
|
+
this._markers = markers;
|
|
48742
|
+
}
|
|
48743
|
+
/**
|
|
48744
|
+
* Updates the render target size to match viewport.
|
|
48745
|
+
*/
|
|
48746
|
+
setSize(width, height) {
|
|
48747
|
+
this._renderTarget.setSize(width, height);
|
|
48748
|
+
}
|
|
48749
|
+
/**
|
|
48750
|
+
* Performs GPU picking at the given screen coordinates.
|
|
48751
|
+
* Returns a result object with element index, world position, and getElement() method.
|
|
48752
|
+
*
|
|
48753
|
+
* @param screenPos Screen position in 0-1 range (0,0 is top-left)
|
|
48754
|
+
* @returns Pick result with element index, world position, and getElement(), or undefined if no hit
|
|
48755
|
+
*/
|
|
48756
|
+
pick(screenPos) {
|
|
48757
|
+
var _a3;
|
|
48758
|
+
const camera2 = this._camera.three;
|
|
48759
|
+
camera2.updateMatrixWorld(true);
|
|
48760
|
+
const currentRenderTarget = this._renderer.getRenderTarget();
|
|
48761
|
+
const currentOverrideMaterial = this._scene.threeScene.overrideMaterial;
|
|
48762
|
+
const currentBackground = this._scene.threeScene.background;
|
|
48763
|
+
this._pickingMaterial.updateCamera(camera2);
|
|
48764
|
+
if (this._section.active) {
|
|
48765
|
+
this._pickingMaterial.clippingPlanes = this._section.clippingPlanes;
|
|
48766
|
+
} else {
|
|
48767
|
+
this._pickingMaterial.clippingPlanes = [];
|
|
48768
|
+
}
|
|
48769
|
+
this._scene.threeScene.background = null;
|
|
48770
|
+
this._scene.threeScene.overrideMaterial = this._pickingMaterial.material;
|
|
48771
|
+
camera2.layers.disable(1);
|
|
48772
|
+
this._renderer.setRenderTarget(this._renderTarget);
|
|
48773
|
+
this._renderer.setClearColor(0, 0);
|
|
48774
|
+
this._renderer.clear();
|
|
48775
|
+
this._renderer.render(this._scene.threeScene, camera2);
|
|
48776
|
+
this._renderer.setRenderTarget(currentRenderTarget);
|
|
48777
|
+
camera2.layers.enable(1);
|
|
48778
|
+
this._scene.threeScene.overrideMaterial = currentOverrideMaterial;
|
|
48779
|
+
this._scene.threeScene.background = currentBackground;
|
|
48780
|
+
const pixelX = Math.floor(screenPos.x * this._renderTarget.width);
|
|
48781
|
+
const pixelY = Math.floor((1 - screenPos.y) * this._renderTarget.height);
|
|
48782
|
+
this._renderer.readRenderTargetPixels(
|
|
48783
|
+
this._renderTarget,
|
|
48784
|
+
pixelX,
|
|
48785
|
+
pixelY,
|
|
48786
|
+
1,
|
|
48787
|
+
1,
|
|
48788
|
+
this._readBuffer
|
|
48789
|
+
);
|
|
48790
|
+
const depth = this._readBuffer[1];
|
|
48791
|
+
const normalX = this._readBuffer[2];
|
|
48792
|
+
const normalY = this._readBuffer[3];
|
|
48793
|
+
if (depth <= 0) {
|
|
48794
|
+
return void 0;
|
|
48795
|
+
}
|
|
48796
|
+
const dataView = new DataView(this._readBuffer.buffer);
|
|
48797
|
+
const packedId = dataView.getUint32(0, true);
|
|
48798
|
+
const { vimIndex, elementIndex } = unpackPickingId(packedId);
|
|
48799
|
+
const normalZ = Math.sqrt(Math.max(0, 1 - normalX * normalX - normalY * normalY));
|
|
48800
|
+
const worldNormal = new Vector3(normalX, normalY, normalZ).normalize();
|
|
48801
|
+
const worldPosition = this.reconstructWorldPosition(screenPos, depth, camera2);
|
|
48802
|
+
if (vimIndex === MARKER_VIM_INDEX) {
|
|
48803
|
+
const marker = (_a3 = this._markers) == null ? void 0 : _a3.getMarkerFromIndex(elementIndex);
|
|
48804
|
+
const result2 = new GpuPickResult(elementIndex, vimIndex, worldPosition, worldNormal, void 0, marker);
|
|
48805
|
+
if (this.debug) {
|
|
48806
|
+
this.showDebugVisuals(result2);
|
|
48807
|
+
}
|
|
48808
|
+
return result2;
|
|
48809
|
+
}
|
|
48810
|
+
const vim = this._vims.getFromId(vimIndex);
|
|
48811
|
+
const result = new GpuPickResult(elementIndex, vimIndex, worldPosition, worldNormal, vim);
|
|
48812
|
+
if (this.debug) {
|
|
48813
|
+
this.showDebugVisuals(result);
|
|
48814
|
+
}
|
|
48815
|
+
return result;
|
|
48816
|
+
}
|
|
48817
|
+
/**
|
|
48818
|
+
* Shows debug visuals (sphere at hit point, line showing normal direction).
|
|
48819
|
+
*/
|
|
48820
|
+
showDebugVisuals(result) {
|
|
48821
|
+
this.clearDebugVisuals();
|
|
48822
|
+
const sphereGeometry = new SphereGeometry(0.5, 16, 16);
|
|
48823
|
+
const sphereMaterial = new MeshBasicMaterial({ color: 16711680 });
|
|
48824
|
+
this._debugSphere = new Mesh(sphereGeometry, sphereMaterial);
|
|
48825
|
+
this._debugSphere.position.copy(result.worldPosition);
|
|
48826
|
+
this._debugSphere.layers.set(1);
|
|
48827
|
+
this._scene.threeScene.add(this._debugSphere);
|
|
48828
|
+
const lineLength = 2;
|
|
48829
|
+
const lineStart = result.worldPosition.clone();
|
|
48830
|
+
const lineEnd = result.worldPosition.clone().add(result.worldNormal.clone().multiplyScalar(lineLength));
|
|
48831
|
+
const lineGeometry = new BufferGeometry().setFromPoints([lineStart, lineEnd]);
|
|
48832
|
+
const lineMaterial = new LineBasicMaterial({ color: 65280, linewidth: 2 });
|
|
48833
|
+
this._debugLine = new Line(lineGeometry, lineMaterial);
|
|
48834
|
+
this._debugLine.layers.set(1);
|
|
48835
|
+
this._scene.threeScene.add(this._debugLine);
|
|
48836
|
+
this._renderer.domElement.dispatchEvent(new Event("needsUpdate"));
|
|
48837
|
+
}
|
|
48838
|
+
/**
|
|
48839
|
+
* Reconstructs world position from screen coordinates and depth value.
|
|
48840
|
+
*/
|
|
48841
|
+
reconstructWorldPosition(screenPos, depth, camera2) {
|
|
48842
|
+
const ndcX = screenPos.x * 2 - 1;
|
|
48843
|
+
const ndcY = (1 - screenPos.y) * 2 - 1;
|
|
48844
|
+
const rayEnd = new Vector3(ndcX, ndcY, 1).unproject(camera2);
|
|
48845
|
+
const rayDir = rayEnd.sub(camera2.position).normalize();
|
|
48846
|
+
const cameraDir = new Vector3();
|
|
48847
|
+
camera2.getWorldDirection(cameraDir);
|
|
48848
|
+
const t = depth / rayDir.dot(cameraDir);
|
|
48849
|
+
const worldPos = camera2.position.clone().add(rayDir.clone().multiplyScalar(t));
|
|
48850
|
+
return worldPos;
|
|
48851
|
+
}
|
|
48852
|
+
/**
|
|
48853
|
+
* Removes debug visuals (sphere and normal line) from the scene.
|
|
48854
|
+
*/
|
|
48855
|
+
clearDebugVisuals() {
|
|
48856
|
+
if (this._debugSphere) {
|
|
48857
|
+
this._scene.threeScene.remove(this._debugSphere);
|
|
48858
|
+
this._debugSphere.geometry.dispose();
|
|
48859
|
+
this._debugSphere.material.dispose();
|
|
48860
|
+
this._debugSphere = void 0;
|
|
48861
|
+
}
|
|
48862
|
+
if (this._debugLine) {
|
|
48863
|
+
this._scene.threeScene.remove(this._debugLine);
|
|
48864
|
+
this._debugLine.geometry.dispose();
|
|
48865
|
+
this._debugLine.material.dispose();
|
|
48866
|
+
this._debugLine = void 0;
|
|
48867
|
+
}
|
|
48868
|
+
}
|
|
48869
|
+
/**
|
|
48870
|
+
* Raycasts from camera to the screen position to find the first object hit.
|
|
48871
|
+
* Implements IRaycaster interface.
|
|
48872
|
+
* @param position - Screen position in 0-1 range (0,0 is top-left)
|
|
48873
|
+
* @returns A promise that resolves to the raycast result, or undefined if no hit
|
|
48874
|
+
*/
|
|
48875
|
+
raycastFromScreen(position) {
|
|
48876
|
+
return Promise.resolve(this.pick(position));
|
|
48877
|
+
}
|
|
48878
|
+
/**
|
|
48879
|
+
* Raycasts from camera towards a world position to find the first object hit.
|
|
48880
|
+
* Implements IRaycaster interface.
|
|
48881
|
+
* @param position - The world position to raycast towards
|
|
48882
|
+
* @returns A promise that resolves to the raycast result, or undefined if no hit
|
|
48883
|
+
*/
|
|
48884
|
+
raycastFromWorld(position) {
|
|
48885
|
+
const screenPos = this.worldToScreen(position);
|
|
48886
|
+
if (!screenPos) return Promise.resolve(void 0);
|
|
48887
|
+
return Promise.resolve(this.pick(screenPos));
|
|
48888
|
+
}
|
|
48889
|
+
/**
|
|
48890
|
+
* Converts a world position to screen coordinates (0-1 range).
|
|
48891
|
+
* @param worldPos - The world position to convert
|
|
48892
|
+
* @returns Screen position in 0-1 range, or undefined if behind camera
|
|
48893
|
+
*/
|
|
48894
|
+
worldToScreen(worldPos) {
|
|
48895
|
+
const camera2 = this._camera.three;
|
|
48896
|
+
camera2.updateMatrixWorld(true);
|
|
48897
|
+
const ndc = worldPos.clone().project(camera2);
|
|
48898
|
+
if (ndc.z > 1) return void 0;
|
|
48899
|
+
const screenX = (ndc.x + 1) / 2;
|
|
48900
|
+
const screenY = (1 - ndc.y) / 2;
|
|
48901
|
+
return new Vector2(screenX, screenY);
|
|
48902
|
+
}
|
|
48903
|
+
/**
|
|
48904
|
+
* Disposes of all resources.
|
|
48905
|
+
*/
|
|
48906
|
+
dispose() {
|
|
48907
|
+
this.clearDebugVisuals();
|
|
48908
|
+
this._renderTarget.dispose();
|
|
48909
|
+
this._pickingMaterial.dispose();
|
|
48910
|
+
}
|
|
48911
|
+
}
|
|
48652
48912
|
class GizmoMarkers {
|
|
48653
48913
|
/**
|
|
48654
48914
|
* Constructs the marker manager and sets up an initial instanced mesh.
|
|
@@ -48692,6 +48952,12 @@ class GizmoMarkers {
|
|
|
48692
48952
|
mesh.count = 0;
|
|
48693
48953
|
mesh.frustumCulled = false;
|
|
48694
48954
|
mesh.layers.enableAll();
|
|
48955
|
+
const packedIdArray = new Uint32Array(capacity);
|
|
48956
|
+
const packedIdAttr = new InstancedBufferAttribute(packedIdArray, 1);
|
|
48957
|
+
mesh.geometry.setAttribute("packedId", packedIdAttr);
|
|
48958
|
+
const ignoreArray = new Float32Array(capacity);
|
|
48959
|
+
const ignoreAttr = new InstancedBufferAttribute(ignoreArray, 1);
|
|
48960
|
+
mesh.geometry.setAttribute("ignore", ignoreAttr);
|
|
48695
48961
|
this._viewer.renderer.add(mesh);
|
|
48696
48962
|
return mesh;
|
|
48697
48963
|
}
|
|
@@ -48701,12 +48967,20 @@ class GizmoMarkers {
|
|
|
48701
48967
|
resizeMesh() {
|
|
48702
48968
|
const larger = this.createMesh(this._mesh, this._mesh.count * 2);
|
|
48703
48969
|
larger.count = this._mesh.count;
|
|
48970
|
+
const oldPackedId = this._mesh.geometry.getAttribute("packedId");
|
|
48971
|
+
const oldIgnore = this._mesh.geometry.getAttribute("ignore");
|
|
48972
|
+
const newPackedId = larger.geometry.getAttribute("packedId");
|
|
48973
|
+
const newIgnore = larger.geometry.getAttribute("ignore");
|
|
48704
48974
|
for (let i = 0; i < this._mesh.count; i++) {
|
|
48705
48975
|
this._mesh.getMatrixAt(i, this._reusableMatrix);
|
|
48706
48976
|
larger.setMatrixAt(i, this._reusableMatrix);
|
|
48977
|
+
newPackedId.setX(i, oldPackedId.getX(i));
|
|
48978
|
+
newIgnore.setX(i, oldIgnore.getX(i));
|
|
48707
48979
|
const sub = new SimpleInstanceSubmesh(larger, i);
|
|
48708
48980
|
this._markers[i].updateMesh(sub);
|
|
48709
48981
|
}
|
|
48982
|
+
newPackedId.needsUpdate = true;
|
|
48983
|
+
newIgnore.needsUpdate = true;
|
|
48710
48984
|
this._viewer.renderer.remove(this._mesh);
|
|
48711
48985
|
this._mesh = larger;
|
|
48712
48986
|
}
|
|
@@ -48720,8 +48994,12 @@ class GizmoMarkers {
|
|
|
48720
48994
|
if (this._mesh.count === this._mesh.instanceMatrix.count) {
|
|
48721
48995
|
this.resizeMesh();
|
|
48722
48996
|
}
|
|
48997
|
+
const markerIndex = this._mesh.count;
|
|
48723
48998
|
this._mesh.count += 1;
|
|
48724
|
-
const
|
|
48999
|
+
const packedIdAttr = this._mesh.geometry.getAttribute("packedId");
|
|
49000
|
+
packedIdAttr.setX(markerIndex, packPickingId(MARKER_VIM_INDEX, markerIndex));
|
|
49001
|
+
packedIdAttr.needsUpdate = true;
|
|
49002
|
+
const sub = new SimpleInstanceSubmesh(this._mesh, markerIndex);
|
|
48725
49003
|
const marker = new Marker(this._viewer, sub);
|
|
48726
49004
|
marker.position = position;
|
|
48727
49005
|
this._markers.push(marker);
|
|
@@ -48742,7 +49020,10 @@ class GizmoMarkers {
|
|
|
48742
49020
|
this._mesh.getMatrixAt(fromIndex, this._reusableMatrix);
|
|
48743
49021
|
this._mesh.setMatrixAt(destIndex, this._reusableMatrix);
|
|
48744
49022
|
this._mesh.instanceMatrix.needsUpdate = true;
|
|
48745
|
-
const
|
|
49023
|
+
const packedIdAttr = this._mesh.geometry.getAttribute("packedId");
|
|
49024
|
+
packedIdAttr.setX(destIndex, packPickingId(MARKER_VIM_INDEX, destIndex));
|
|
49025
|
+
packedIdAttr.needsUpdate = true;
|
|
49026
|
+
const sub = new SimpleInstanceSubmesh(this._mesh, destIndex);
|
|
48746
49027
|
lastMarker.updateMesh(sub);
|
|
48747
49028
|
}
|
|
48748
49029
|
this._markers.length -= 1;
|
|
@@ -53643,238 +53924,6 @@ class Gizmos {
|
|
|
53643
53924
|
this.axes.dispose();
|
|
53644
53925
|
}
|
|
53645
53926
|
}
|
|
53646
|
-
function packPickingId(vimIndex, elementIndex) {
|
|
53647
|
-
return (vimIndex & 255) << 24 | elementIndex & 16777215;
|
|
53648
|
-
}
|
|
53649
|
-
function unpackPickingId(packedId) {
|
|
53650
|
-
return {
|
|
53651
|
-
vimIndex: packedId >>> 24,
|
|
53652
|
-
elementIndex: packedId & 16777215
|
|
53653
|
-
};
|
|
53654
|
-
}
|
|
53655
|
-
class GpuPickResult {
|
|
53656
|
-
constructor(elementIndex, vimIndex, worldPosition, worldNormal, vim) {
|
|
53657
|
-
/** The element index in the vim */
|
|
53658
|
-
__publicField(this, "elementIndex");
|
|
53659
|
-
/** The vim index identifying which vim the element belongs to */
|
|
53660
|
-
__publicField(this, "vimIndex");
|
|
53661
|
-
/** The world position of the hit */
|
|
53662
|
-
__publicField(this, "worldPosition");
|
|
53663
|
-
/** The world normal at the hit point */
|
|
53664
|
-
__publicField(this, "worldNormal");
|
|
53665
|
-
/** Reference to the vim containing the element */
|
|
53666
|
-
__publicField(this, "_vim");
|
|
53667
|
-
this.elementIndex = elementIndex;
|
|
53668
|
-
this.vimIndex = vimIndex;
|
|
53669
|
-
this.worldPosition = worldPosition;
|
|
53670
|
-
this.worldNormal = worldNormal;
|
|
53671
|
-
this._vim = vim;
|
|
53672
|
-
}
|
|
53673
|
-
/**
|
|
53674
|
-
* The object property for IRaycastResult interface.
|
|
53675
|
-
* Returns the Element3D for the picked element.
|
|
53676
|
-
*/
|
|
53677
|
-
get object() {
|
|
53678
|
-
return this.getElement();
|
|
53679
|
-
}
|
|
53680
|
-
/**
|
|
53681
|
-
* Gets the Element3D object for the picked element.
|
|
53682
|
-
* @returns The Element3D object, or undefined if not found
|
|
53683
|
-
*/
|
|
53684
|
-
getElement() {
|
|
53685
|
-
var _a3;
|
|
53686
|
-
return (_a3 = this._vim) == null ? void 0 : _a3.getElementFromIndex(this.elementIndex);
|
|
53687
|
-
}
|
|
53688
|
-
}
|
|
53689
|
-
class GpuPicker {
|
|
53690
|
-
constructor(renderer, camera2, scene, vims, section, width, height) {
|
|
53691
|
-
__publicField(this, "_renderer");
|
|
53692
|
-
__publicField(this, "_camera");
|
|
53693
|
-
__publicField(this, "_scene");
|
|
53694
|
-
__publicField(this, "_vims");
|
|
53695
|
-
__publicField(this, "_section");
|
|
53696
|
-
__publicField(this, "_renderTarget");
|
|
53697
|
-
__publicField(this, "_pickingMaterial");
|
|
53698
|
-
__publicField(this, "_readBuffer");
|
|
53699
|
-
// Debug visualization
|
|
53700
|
-
__publicField(this, "debug", true);
|
|
53701
|
-
__publicField(this, "_debugSphere");
|
|
53702
|
-
__publicField(this, "_debugLine");
|
|
53703
|
-
this._renderer = renderer;
|
|
53704
|
-
this._camera = camera2;
|
|
53705
|
-
this._scene = scene;
|
|
53706
|
-
this._vims = vims;
|
|
53707
|
-
this._section = section;
|
|
53708
|
-
this._renderTarget = new WebGLRenderTarget(width, height, {
|
|
53709
|
-
minFilter: NearestFilter,
|
|
53710
|
-
magFilter: NearestFilter,
|
|
53711
|
-
format: RGBAFormat,
|
|
53712
|
-
type: FloatType,
|
|
53713
|
-
depthBuffer: true
|
|
53714
|
-
});
|
|
53715
|
-
this._pickingMaterial = new PickingMaterial();
|
|
53716
|
-
this._readBuffer = new Float32Array(4);
|
|
53717
|
-
}
|
|
53718
|
-
/**
|
|
53719
|
-
* Updates the render target size to match viewport.
|
|
53720
|
-
*/
|
|
53721
|
-
setSize(width, height) {
|
|
53722
|
-
this._renderTarget.setSize(width, height);
|
|
53723
|
-
}
|
|
53724
|
-
/**
|
|
53725
|
-
* Performs GPU picking at the given screen coordinates.
|
|
53726
|
-
* Returns a result object with element index, world position, and getElement() method.
|
|
53727
|
-
*
|
|
53728
|
-
* @param screenPos Screen position in 0-1 range (0,0 is top-left)
|
|
53729
|
-
* @returns Pick result with element index, world position, and getElement(), or undefined if no hit
|
|
53730
|
-
*/
|
|
53731
|
-
pick(screenPos) {
|
|
53732
|
-
const camera2 = this._camera.three;
|
|
53733
|
-
camera2.updateMatrixWorld(true);
|
|
53734
|
-
const currentRenderTarget = this._renderer.getRenderTarget();
|
|
53735
|
-
const currentOverrideMaterial = this._scene.threeScene.overrideMaterial;
|
|
53736
|
-
const currentBackground = this._scene.threeScene.background;
|
|
53737
|
-
this._pickingMaterial.updateCamera(camera2);
|
|
53738
|
-
if (this._section.active) {
|
|
53739
|
-
this._pickingMaterial.clippingPlanes = this._section.clippingPlanes;
|
|
53740
|
-
} else {
|
|
53741
|
-
this._pickingMaterial.clippingPlanes = [];
|
|
53742
|
-
}
|
|
53743
|
-
this._scene.threeScene.background = null;
|
|
53744
|
-
this._scene.threeScene.overrideMaterial = this._pickingMaterial.material;
|
|
53745
|
-
camera2.layers.disable(1);
|
|
53746
|
-
this._renderer.setRenderTarget(this._renderTarget);
|
|
53747
|
-
this._renderer.setClearColor(0, 0);
|
|
53748
|
-
this._renderer.clear();
|
|
53749
|
-
this._renderer.render(this._scene.threeScene, camera2);
|
|
53750
|
-
this._renderer.setRenderTarget(currentRenderTarget);
|
|
53751
|
-
camera2.layers.enable(1);
|
|
53752
|
-
this._scene.threeScene.overrideMaterial = currentOverrideMaterial;
|
|
53753
|
-
this._scene.threeScene.background = currentBackground;
|
|
53754
|
-
const pixelX = Math.floor(screenPos.x * this._renderTarget.width);
|
|
53755
|
-
const pixelY = Math.floor((1 - screenPos.y) * this._renderTarget.height);
|
|
53756
|
-
this._renderer.readRenderTargetPixels(
|
|
53757
|
-
this._renderTarget,
|
|
53758
|
-
pixelX,
|
|
53759
|
-
pixelY,
|
|
53760
|
-
1,
|
|
53761
|
-
1,
|
|
53762
|
-
this._readBuffer
|
|
53763
|
-
);
|
|
53764
|
-
const depth = this._readBuffer[1];
|
|
53765
|
-
const normalX = this._readBuffer[2];
|
|
53766
|
-
const normalY = this._readBuffer[3];
|
|
53767
|
-
if (depth <= 0) {
|
|
53768
|
-
return void 0;
|
|
53769
|
-
}
|
|
53770
|
-
const dataView = new DataView(this._readBuffer.buffer);
|
|
53771
|
-
const packedId = dataView.getUint32(0, true);
|
|
53772
|
-
const { vimIndex, elementIndex } = unpackPickingId(packedId);
|
|
53773
|
-
const normalZ = Math.sqrt(Math.max(0, 1 - normalX * normalX - normalY * normalY));
|
|
53774
|
-
const worldNormal = new Vector3(normalX, normalY, normalZ).normalize();
|
|
53775
|
-
const worldPosition = this.reconstructWorldPosition(screenPos, depth, camera2);
|
|
53776
|
-
const vim = this._vims.getFromId(vimIndex);
|
|
53777
|
-
const result = new GpuPickResult(elementIndex, vimIndex, worldPosition, worldNormal, vim);
|
|
53778
|
-
if (this.debug) {
|
|
53779
|
-
this.showDebugVisuals(result);
|
|
53780
|
-
}
|
|
53781
|
-
return result;
|
|
53782
|
-
}
|
|
53783
|
-
/**
|
|
53784
|
-
* Shows debug visuals (sphere at hit point, line showing normal direction).
|
|
53785
|
-
*/
|
|
53786
|
-
showDebugVisuals(result) {
|
|
53787
|
-
this.clearDebugVisuals();
|
|
53788
|
-
const sphereGeometry = new SphereGeometry(0.5, 16, 16);
|
|
53789
|
-
const sphereMaterial = new MeshBasicMaterial({ color: 16711680 });
|
|
53790
|
-
this._debugSphere = new Mesh(sphereGeometry, sphereMaterial);
|
|
53791
|
-
this._debugSphere.position.copy(result.worldPosition);
|
|
53792
|
-
this._debugSphere.layers.set(1);
|
|
53793
|
-
this._scene.threeScene.add(this._debugSphere);
|
|
53794
|
-
const lineLength = 2;
|
|
53795
|
-
const lineStart = result.worldPosition.clone();
|
|
53796
|
-
const lineEnd = result.worldPosition.clone().add(result.worldNormal.clone().multiplyScalar(lineLength));
|
|
53797
|
-
const lineGeometry = new BufferGeometry().setFromPoints([lineStart, lineEnd]);
|
|
53798
|
-
const lineMaterial = new LineBasicMaterial({ color: 65280, linewidth: 2 });
|
|
53799
|
-
this._debugLine = new Line(lineGeometry, lineMaterial);
|
|
53800
|
-
this._debugLine.layers.set(1);
|
|
53801
|
-
this._scene.threeScene.add(this._debugLine);
|
|
53802
|
-
this._renderer.domElement.dispatchEvent(new Event("needsUpdate"));
|
|
53803
|
-
}
|
|
53804
|
-
/**
|
|
53805
|
-
* Reconstructs world position from screen coordinates and depth value.
|
|
53806
|
-
*/
|
|
53807
|
-
reconstructWorldPosition(screenPos, depth, camera2) {
|
|
53808
|
-
const ndcX = screenPos.x * 2 - 1;
|
|
53809
|
-
const ndcY = (1 - screenPos.y) * 2 - 1;
|
|
53810
|
-
const rayEnd = new Vector3(ndcX, ndcY, 1).unproject(camera2);
|
|
53811
|
-
const rayDir = rayEnd.sub(camera2.position).normalize();
|
|
53812
|
-
const cameraDir = new Vector3();
|
|
53813
|
-
camera2.getWorldDirection(cameraDir);
|
|
53814
|
-
const t = depth / rayDir.dot(cameraDir);
|
|
53815
|
-
const worldPos = camera2.position.clone().add(rayDir.clone().multiplyScalar(t));
|
|
53816
|
-
return worldPos;
|
|
53817
|
-
}
|
|
53818
|
-
/**
|
|
53819
|
-
* Removes debug visuals (sphere and normal line) from the scene.
|
|
53820
|
-
*/
|
|
53821
|
-
clearDebugVisuals() {
|
|
53822
|
-
if (this._debugSphere) {
|
|
53823
|
-
this._scene.threeScene.remove(this._debugSphere);
|
|
53824
|
-
this._debugSphere.geometry.dispose();
|
|
53825
|
-
this._debugSphere.material.dispose();
|
|
53826
|
-
this._debugSphere = void 0;
|
|
53827
|
-
}
|
|
53828
|
-
if (this._debugLine) {
|
|
53829
|
-
this._scene.threeScene.remove(this._debugLine);
|
|
53830
|
-
this._debugLine.geometry.dispose();
|
|
53831
|
-
this._debugLine.material.dispose();
|
|
53832
|
-
this._debugLine = void 0;
|
|
53833
|
-
}
|
|
53834
|
-
}
|
|
53835
|
-
/**
|
|
53836
|
-
* Raycasts from camera to the screen position to find the first object hit.
|
|
53837
|
-
* Implements IRaycaster interface.
|
|
53838
|
-
* @param position - Screen position in 0-1 range (0,0 is top-left)
|
|
53839
|
-
* @returns A promise that resolves to the raycast result, or undefined if no hit
|
|
53840
|
-
*/
|
|
53841
|
-
raycastFromScreen(position) {
|
|
53842
|
-
return Promise.resolve(this.pick(position));
|
|
53843
|
-
}
|
|
53844
|
-
/**
|
|
53845
|
-
* Raycasts from camera towards a world position to find the first object hit.
|
|
53846
|
-
* Implements IRaycaster interface.
|
|
53847
|
-
* @param position - The world position to raycast towards
|
|
53848
|
-
* @returns A promise that resolves to the raycast result, or undefined if no hit
|
|
53849
|
-
*/
|
|
53850
|
-
raycastFromWorld(position) {
|
|
53851
|
-
const screenPos = this.worldToScreen(position);
|
|
53852
|
-
if (!screenPos) return Promise.resolve(void 0);
|
|
53853
|
-
return Promise.resolve(this.pick(screenPos));
|
|
53854
|
-
}
|
|
53855
|
-
/**
|
|
53856
|
-
* Converts a world position to screen coordinates (0-1 range).
|
|
53857
|
-
* @param worldPos - The world position to convert
|
|
53858
|
-
* @returns Screen position in 0-1 range, or undefined if behind camera
|
|
53859
|
-
*/
|
|
53860
|
-
worldToScreen(worldPos) {
|
|
53861
|
-
const camera2 = this._camera.three;
|
|
53862
|
-
camera2.updateMatrixWorld(true);
|
|
53863
|
-
const ndc = worldPos.clone().project(camera2);
|
|
53864
|
-
if (ndc.z > 1) return void 0;
|
|
53865
|
-
const screenX = (ndc.x + 1) / 2;
|
|
53866
|
-
const screenY = (1 - ndc.y) / 2;
|
|
53867
|
-
return new Vector2(screenX, screenY);
|
|
53868
|
-
}
|
|
53869
|
-
/**
|
|
53870
|
-
* Disposes of all resources.
|
|
53871
|
-
*/
|
|
53872
|
-
dispose() {
|
|
53873
|
-
this.clearDebugVisuals();
|
|
53874
|
-
this._renderTarget.dispose();
|
|
53875
|
-
this._pickingMaterial.dispose();
|
|
53876
|
-
}
|
|
53877
|
-
}
|
|
53878
53927
|
function getAverageBoundingBox(positions, thresholdSpan = 1e3, framingDistanceMultiplier = 2) {
|
|
53879
53928
|
if (positions.length === 0) {
|
|
53880
53929
|
return new Box3();
|
|
@@ -55023,14 +55072,14 @@ function createAdapter$2(viewer) {
|
|
|
55023
55072
|
selectAtPointer: async (pos, add) => {
|
|
55024
55073
|
const result = await viewer.raycaster.raycastFromScreen(pos);
|
|
55025
55074
|
if (add) {
|
|
55026
|
-
viewer.selection.add(result.object);
|
|
55075
|
+
viewer.selection.add(result == null ? void 0 : result.object);
|
|
55027
55076
|
} else {
|
|
55028
|
-
viewer.selection.select(result.object);
|
|
55077
|
+
viewer.selection.select(result == null ? void 0 : result.object);
|
|
55029
55078
|
}
|
|
55030
55079
|
},
|
|
55031
55080
|
frameAtPointer: async (pos) => {
|
|
55032
55081
|
const result = await viewer.raycaster.raycastFromScreen(pos);
|
|
55033
|
-
viewer.camera.lerp(0.75).frame(result.object ?? "all");
|
|
55082
|
+
viewer.camera.lerp(0.75).frame((result == null ? void 0 : result.object) ?? "all");
|
|
55034
55083
|
},
|
|
55035
55084
|
zoom: async (value, pos) => {
|
|
55036
55085
|
if (pos) {
|
|
@@ -56333,7 +56382,7 @@ let Viewer$3 = class Viewer {
|
|
|
56333
56382
|
this.environment = new Environment(this.camera, this.renderer, this.materials, this.settings);
|
|
56334
56383
|
this.selection = createSelection$1();
|
|
56335
56384
|
const size = this.renderer.renderer.getSize(new Vector2());
|
|
56336
|
-
|
|
56385
|
+
const gpuPicker = new GpuPicker(
|
|
56337
56386
|
this.renderer.renderer,
|
|
56338
56387
|
this._camera,
|
|
56339
56388
|
scene,
|
|
@@ -56342,6 +56391,8 @@ let Viewer$3 = class Viewer {
|
|
|
56342
56391
|
size.x || 1,
|
|
56343
56392
|
size.y || 1
|
|
56344
56393
|
);
|
|
56394
|
+
gpuPicker.setMarkers(this.gizmos.markers);
|
|
56395
|
+
this.raycaster = gpuPicker;
|
|
56345
56396
|
this.viewport.onResize.sub(() => {
|
|
56346
56397
|
const size2 = this.viewport.getParentSize();
|
|
56347
56398
|
this.raycaster.setSize(size2.x, size2.y);
|