diff --git a/packages/dev/core/src/Behaviors/Meshes/baseSixDofDragBehavior.ts b/packages/dev/core/src/Behaviors/Meshes/baseSixDofDragBehavior.ts index 4b301de0c94..bb9b53ae1f7 100644 --- a/packages/dev/core/src/Behaviors/Meshes/baseSixDofDragBehavior.ts +++ b/packages/dev/core/src/Behaviors/Meshes/baseSixDofDragBehavior.ts @@ -297,7 +297,7 @@ export class BaseSixDofDragBehavior implements Behavior { this._virtualMeshesInfo[pointerId] = this._createVirtualMeshInfo(); } const virtualMeshesInfo = this._virtualMeshesInfo[pointerId]; - const isXRNearPointer = (pointerInfo.event).pointerType === "xr-near"; + const isXRPointer = (pointerInfo.event).pointerType === "xr-near" || (pointerInfo.event).pointerType === "xr"; if (pointerInfo.type == PointerEventTypes.POINTERDOWN) { if ( @@ -307,10 +307,10 @@ export class BaseSixDofDragBehavior implements Behavior { pointerInfo.pickInfo.pickedMesh && pointerInfo.pickInfo.pickedPoint && pointerInfo.pickInfo.ray && - (!isXRNearPointer || pointerInfo.pickInfo.aimTransform) && + (!isXRPointer || pointerInfo.pickInfo.aimTransform) && pickPredicate(pointerInfo.pickInfo.pickedMesh) ) { - if (!this.allowMultiPointer && this.currentDraggingPointerIds.length > 0) { + if ((!this.allowMultiPointer || isXRPointer) && this.currentDraggingPointerIds.length > 0) { return; } @@ -326,7 +326,7 @@ export class BaseSixDofDragBehavior implements Behavior { this._ownerNode.computeWorldMatrix(true); const virtualMeshesInfo = this._virtualMeshesInfo[pointerId]; - if (isXRNearPointer) { + if (isXRPointer) { this._dragging = pointerInfo.pickInfo.originMesh ? this._dragType.NEAR_DRAG : this._dragType.DRAG_WITH_CONTROLLER; virtualMeshesInfo.originMesh.position.copyFrom(pointerInfo.pickInfo.aimTransform!.position); if (this._dragging === this._dragType.NEAR_DRAG && pointerInfo.pickInfo.gripTransform) { @@ -352,7 +352,7 @@ export class BaseSixDofDragBehavior implements Behavior { virtualMeshesInfo.startingOrientation.copyFrom(virtualMeshesInfo.dragMesh.rotationQuaternion!); virtualMeshesInfo.startingPivotOrientation.copyFrom(virtualMeshesInfo.pivotMesh.rotationQuaternion!); - if (isXRNearPointer) { + if (isXRPointer) { virtualMeshesInfo.originMesh.addChild(virtualMeshesInfo.dragMesh); virtualMeshesInfo.originMesh.addChild(virtualMeshesInfo.pivotMesh); } else { @@ -416,7 +416,7 @@ export class BaseSixDofDragBehavior implements Behavior { } this._ownerNode.computeWorldMatrix(true); - if (!isXRNearPointer) { + if (!isXRPointer) { this._pointerUpdate2D(pointerInfo.pickInfo.ray!, pointerId, zDragFactor); } else { this._pointerUpdateXR(pointerInfo.pickInfo.aimTransform!, pointerInfo.pickInfo.gripTransform, pointerId, zDragFactor); diff --git a/packages/dev/core/src/Behaviors/Meshes/sixDofDragBehavior.ts b/packages/dev/core/src/Behaviors/Meshes/sixDofDragBehavior.ts index 20b6aeb01f5..137a7a9d67d 100644 --- a/packages/dev/core/src/Behaviors/Meshes/sixDofDragBehavior.ts +++ b/packages/dev/core/src/Behaviors/Meshes/sixDofDragBehavior.ts @@ -66,12 +66,17 @@ export class SixDofDragBehavior extends BaseSixDofDragBehavior { /** * Attaches the six DoF drag behavior + * In XR mode the mesh and its children will have their isNearGrabbable property set to true * @param ownerNode The mesh that will be dragged around once attached */ public attach(ownerNode: Mesh): void { super.attach(ownerNode); ownerNode.isNearGrabbable = true; + // if it has children, make sure they are grabbable too + ownerNode.getChildMeshes().forEach((m) => { + m.isNearGrabbable = true; + }); // Node that will save the owner's transform this._virtualTransformNode = new TransformNode("virtual_sixDof", BaseSixDofDragBehavior._virtualScene); @@ -255,7 +260,6 @@ export class SixDofDragBehavior extends BaseSixDofDragBehavior { super.detach(); if (this._ownerNode) { - (this._ownerNode as Mesh).isNearGrabbable = false; this._ownerNode.getScene().onBeforeRenderObservable.remove(this._sceneRenderObserver); } diff --git a/packages/dev/core/src/Meshes/abstractMesh.ts b/packages/dev/core/src/Meshes/abstractMesh.ts index 25d7e222e6f..b782a7d7be5 100644 --- a/packages/dev/core/src/Meshes/abstractMesh.ts +++ b/packages/dev/core/src/Meshes/abstractMesh.ts @@ -432,12 +432,15 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl public isPickable = true; /** - * Gets or sets a boolean indicating if the mesh can be near picked. Default is false + * Gets or sets a boolean indicating if the mesh can be near picked (touched by the XR controller or hands). Default is false */ public isNearPickable = false; /** - * Gets or sets a boolean indicating if the mesh can be near grabbed. Default is false + * Gets or sets a boolean indicating if the mesh can be grabbed. Default is false. + * Setting this to true, while using the XR near interaction feature, will trigger a pointer event when the mesh is grabbed. + * Grabbing means that the controller is using the squeeze or main trigger button to grab the mesh. + * This is different from nearPickable which only triggers the event when the mesh is touched by the controller */ public isNearGrabbable = false; diff --git a/packages/dev/core/src/XR/features/WebXRControllerPointerSelection.ts b/packages/dev/core/src/XR/features/WebXRControllerPointerSelection.ts index 6d196730d1c..43464637618 100644 --- a/packages/dev/core/src/XR/features/WebXRControllerPointerSelection.ts +++ b/packages/dev/core/src/XR/features/WebXRControllerPointerSelection.ts @@ -700,6 +700,17 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature { } } else { if (pressed && !this._options.enablePointerSelectionOnAllControllers && !this._options.disableSwitchOnClick) { + // force a pointer up if switching controllers + // get the controller that was attached before + const prevController = this._controllers[this._attachedController]; + if (prevController && prevController.pointerDownTriggered && !prevController.finalPointerUpTriggered) { + this._augmentPointerInit(pointerEventInit, prevController.id, prevController.screenCoordinates); + this._scene.simulatePointerUp(new PickingInfo(), { + pointerId: prevController.id, + pointerType: "xr", + }); + prevController.finalPointerUpTriggered = true; + } this._attachedController = xrController.uniqueId; } }