瀏覽代碼

Merge pull request #9111 from RaananW/pointerSelectionChanges

[XR] Major changes to pointer selection
David Catuhe 4 年之前
父節點
當前提交
c6a22b967a
共有 2 個文件被更改,包括 74 次插入13 次删除
  1. 1 0
      dist/preview release/what's new.md
  2. 73 13
      src/XR/features/WebXRControllerPointerSelection.ts

+ 1 - 0
dist/preview release/what's new.md

@@ -212,6 +212,7 @@
 - XR's main camera uses the first eye's projection matrix ([#8944](https://github.com/BabylonJS/Babylon.js/issues/8944)) ([RaananW](https://github.com/RaananW))
 - pointerX and pointerY of the scene are now updated when using the pointer selection feature ([#8879](https://github.com/BabylonJS/Babylon.js/issues/8879)) ([RaananW](https://github.com/RaananW))
 - XR tracking state was added to the camera ([#9076](https://github.com/BabylonJS/Babylon.js/issues/9076)) ([RaananW](https://github.com/RaananW))
+- Pointer selection improvements - single/dual hand selection, max ray distance and more ([#7974](https://github.com/BabylonJS/Babylon.js/issues/7974)) ([RaananW](https://github.com/RaananW))
 
 ### Collisions
 

+ 73 - 13
src/XR/features/WebXRControllerPointerSelection.ts

@@ -81,6 +81,28 @@ export interface IWebXRControllerPointerSelectionOptions {
      * The first rig camera (left eye) will be used to calculate the projection
      */
     disableScenePointerVectorUpdate: boolean;
+
+    /**
+     * Enable pointer selection on all controllers instead of switching between them
+     */
+    enablePointerSelectionOnAllControllers?: boolean;
+
+    /**
+     * The preferred hand to give the pointer selection to. This will be prioritized when the controller initialize.
+     * If switch is enabled, it will still allow the user to switch between the different controllers
+     */
+    preferredHandedness?: XRHandedness;
+
+    /**
+     * Disable switching the pointer selection from one controller to the other.
+     * If the preferred hand is set it will be fixed on this hand, and if not it will be fixed on the first controller added to the scene
+     */
+    disableSwitchOnClick?: boolean;
+
+    /**
+     * The maximum distance of the pointer selection feature. Defaults to 100.
+     */
+    maxPointerDistance?: number;
 }
 
 /**
@@ -94,11 +116,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             // already attached
             return;
         }
-        // For now no support for hand-tracked input sources!
-        if (xrController.inputSource.hand && !xrController.inputSource.gamepad) {
-            return;
-        }
-        // only support tracker pointer
+
         const { laserPointer, selectionMesh } = this._generateNewMeshPair(xrController.pointer);
 
         // get two new meshes
@@ -111,6 +129,17 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             tmpRay: new Ray(new Vector3(), new Vector3()),
             id: WebXRControllerPointerSelection._idCounter++,
         };
+
+        if (this._attachedController) {
+            if (!this._options.enablePointerSelectionOnAllControllers && this._options.preferredHandedness && xrController.inputSource.handedness === this._options.preferredHandedness) {
+                this._attachedController = xrController.uniqueId;
+            }
+        } else {
+            if (!this._options.enablePointerSelectionOnAllControllers) {
+                this._attachedController = xrController.uniqueId;
+            }
+        }
+
         switch (xrController.inputSource.targetRayMode) {
             case "tracked-pointer":
                 return this._attachTrackedPointerRayMode(xrController);
@@ -141,6 +170,8 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
     private _scene: Scene;
     private _tmpVectorForPickCompare = new Vector3();
 
+    private _attachedController: string;
+
     /**
      * The module's name
      */
@@ -296,7 +327,16 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
 
     protected _onXRFrame(_xrFrame: XRFrame) {
         Object.keys(this._controllers).forEach((id) => {
+            // only do this for the selected pointer
             const controllerData = this._controllers[id];
+            if (!this._options.enablePointerSelectionOnAllControllers && id !== this._attachedController) {
+                controllerData.selectionMesh.isVisible = false;
+                controllerData.laserPointer.isVisible = false;
+                controllerData.pick = null;
+                return;
+            }
+
+            controllerData.laserPointer.isVisible = this.displayLaserPointer;
 
             let controllerGlobalPosition: Vector3;
 
@@ -310,6 +350,10 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             } else {
                 return;
             }
+
+            if (this._options.maxPointerDistance) {
+                controllerData.tmpRay.length = this._options.maxPointerDistance;
+            }
             // update pointerX and pointerY of the scene. Only if the flag is set to true!
             if (!this._options.disableScenePointerVectorUpdate && controllerGlobalPosition) {
                 const scene = this._xrSessionManager.scene;
@@ -350,6 +394,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
                 controllerData.meshUnderPointer = pick.pickedMesh;
             } else {
                 controllerData.selectionMesh.isVisible = false;
+                this._updatePointerDistance(controllerData.laserPointer, 1);
                 controllerData.meshUnderPointer = null;
             }
         });
@@ -462,7 +507,6 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             return this._attachGazeMode(xrController);
         }
         controllerData.onFrameObserver = this._xrSessionManager.onXRFrameObservable.add(() => {
-            controllerData.laserPointer.isVisible = this.displayLaserPointer;
             (<StandardMaterial>controllerData.laserPointer.material).disableLighting = this.disablePointerLighting;
             (<StandardMaterial>controllerData.selectionMesh.material).disableLighting = this.disableSelectionMeshLighting;
 
@@ -483,14 +527,21 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
                     if (component.changes.pressed) {
                         const pressed = component.changes.pressed.current;
                         if (controllerData.pick) {
-                            if (pressed) {
-                                this._scene.simulatePointerDown(controllerData.pick, { pointerId: controllerData.id });
-                                (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.selectionMeshPickedColor;
-                                (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.laserPointerPickedColor;
+                            if (this._options.enablePointerSelectionOnAllControllers || xrController.uniqueId === this._attachedController) {
+                                if (pressed) {
+                                    this._scene.simulatePointerDown(controllerData.pick, { pointerId: controllerData.id });
+                                    (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.selectionMeshPickedColor;
+                                    (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.laserPointerPickedColor;
+                                } else {
+                                    this._scene.simulatePointerUp(controllerData.pick, { pointerId: controllerData.id });
+                                    (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.selectionMeshDefaultColor;
+                                    (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.laserPointerDefaultColor;
+                                }
                             } else {
-                                this._scene.simulatePointerUp(controllerData.pick, { pointerId: controllerData.id });
-                                (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.selectionMeshDefaultColor;
-                                (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.laserPointerDefaultColor;
+                            }
+                        } else {
+                            if (pressed && !this._options.enablePointerSelectionOnAllControllers && !this._options.disableSwitchOnClick) {
+                                this._attachedController = xrController.uniqueId;
                             }
                         }
                     }
@@ -564,6 +615,15 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
         controllerData.laserPointer.dispose();
         // remove from the map
         delete this._controllers[xrControllerUniqueId];
+        if (this._attachedController === xrControllerUniqueId) {
+            // check for other controllers
+            const keys = Object.keys(this._controllers);
+            if (keys.length) {
+                this._attachedController = keys[0];
+            } else {
+                this._attachedController = "";
+            }
+        }
     }
 
     private _generateNewMeshPair(meshParent: Node) {