浏览代码

Merge branch 'master' into outputRenderTargetXR

David Catuhe 4 年之前
父节点
当前提交
8f8e85c4cb

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

@@ -213,6 +213,7 @@
 - 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))
 - 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))
 - XR tracking state was added to the camera ([#9076](https://github.com/BabylonJS/Babylon.js/issues/9076)) ([RaananW](https://github.com/RaananW))
 - Individual post processing can be applied to the XR rig cameras ([#9038](https://github.com/BabylonJS/Babylon.js/issues/9038)) ([RaananW](https://github.com/RaananW))
 - Individual post processing can be applied to the XR rig cameras ([#9038](https://github.com/BabylonJS/Babylon.js/issues/9038)) ([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
 ### Collisions
 
 

+ 1 - 1
gui/src/2D/advancedDynamicTexture.ts

@@ -565,7 +565,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
                 if (!control.isVisible) {
                 if (!control.isVisible) {
                     continue;
                     continue;
                 }
                 }
-                let mesh = control._linkedMesh;
+                let mesh = control._linkedMesh as AbstractMesh;
                 if (!mesh || mesh.isDisposed()) {
                 if (!mesh || mesh.isDisposed()) {
                     Tools.SetImmediate(() => {
                     Tools.SetImmediate(() => {
                         control.linkWithMesh(null);
                         control.linkWithMesh(null);

+ 4 - 4
gui/src/2D/controls/control.ts

@@ -4,7 +4,7 @@ import { Vector2, Vector3, Matrix } from "babylonjs/Maths/math.vector";
 import { PointerEventTypes, PointerInfoBase } from 'babylonjs/Events/pointerEvents';
 import { PointerEventTypes, PointerInfoBase } from 'babylonjs/Events/pointerEvents';
 import { Logger } from "babylonjs/Misc/logger";
 import { Logger } from "babylonjs/Misc/logger";
 import { Tools } from "babylonjs/Misc/tools";
 import { Tools } from "babylonjs/Misc/tools";
-import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+import { TransformNode } from "babylonjs/Meshes/transformNode";
 import { Scene } from "babylonjs/scene";
 import { Scene } from "babylonjs/scene";
 
 
 import { Container } from "./container";
 import { Container } from "./container";
@@ -87,7 +87,7 @@ export class Control {
     private _isVisible = true;
     private _isVisible = true;
     private _isHighlighted = false;
     private _isHighlighted = false;
     /** @hidden */
     /** @hidden */
-    public _linkedMesh: Nullable<AbstractMesh>;
+    public _linkedMesh: Nullable<TransformNode>;
     private _fontSet = false;
     private _fontSet = false;
     private _dummyVector2 = Vector2.Zero();
     private _dummyVector2 = Vector2.Zero();
     private _downCount = 0;
     private _downCount = 0;
@@ -710,7 +710,7 @@ export class Control {
     /**
     /**
      * Gets the current linked mesh (or null if none)
      * Gets the current linked mesh (or null if none)
      */
      */
-    public get linkedMesh(): Nullable<AbstractMesh> {
+    public get linkedMesh(): Nullable<TransformNode> {
         return this._linkedMesh;
         return this._linkedMesh;
     }
     }
 
 
@@ -1145,7 +1145,7 @@ export class Control {
      * @param mesh defines the mesh to link with
      * @param mesh defines the mesh to link with
      * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
      * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
      */
      */
-    public linkWithMesh(mesh: Nullable<AbstractMesh>): void {
+    public linkWithMesh(mesh: Nullable<TransformNode>): void {
         if (!this._host || this.parent && this.parent !== this._host._rootContainer) {
         if (!this._host || this.parent && this.parent !== this._host._rootContainer) {
             if (mesh) {
             if (mesh) {
                 Tools.Error("Cannot link a control to a mesh if the control is not at root level");
                 Tools.Error("Cannot link a control to a mesh if the control is not at root level");

+ 11 - 0
src/Materials/Node/Blocks/Dual/lightBlock.ts

@@ -50,6 +50,7 @@ export class LightBlock extends NodeMaterialBlock {
         this.registerInput("glossPower", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("glossPower", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("diffuseColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("diffuseColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("specularColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("specularColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("view", NodeMaterialBlockConnectionPointTypes.Matrix, true);
 
 
         this.registerOutput("diffuseOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("diffuseOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("specularOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("specularOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
@@ -114,6 +115,13 @@ export class LightBlock extends NodeMaterialBlock {
     }
     }
 
 
     /**
     /**
+    * Gets the view matrix component
+    */
+    public get view(): NodeMaterialConnectionPoint {
+        return this._inputs[7];
+    }
+
+    /**
      * Gets the diffuse output component
      * Gets the diffuse output component
      */
      */
     public get diffuseOutput(): NodeMaterialConnectionPoint {
     public get diffuseOutput(): NodeMaterialConnectionPoint {
@@ -232,6 +240,9 @@ export class LightBlock extends NodeMaterialBlock {
             });
             });
         } else {
         } else {
             state.compilationString += `vec4 worldPos = ${worldPos.associatedVariableName};\r\n`;
             state.compilationString += `vec4 worldPos = ${worldPos.associatedVariableName};\r\n`;
+            if (this.view.isConnected) {
+                state.compilationString += `mat4 view = ${this.view.associatedVariableName};\r\n`;
+            }
             state.compilationString += state._emitCodeFromInclude("shadowsVertex", comments, {
             state.compilationString += state._emitCodeFromInclude("shadowsVertex", comments, {
                 repeatKey: "maxSimultaneousLights"
                 repeatKey: "maxSimultaneousLights"
             });
             });

+ 11 - 0
src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts

@@ -93,6 +93,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             new NodeMaterialConnectionPointCustomObject("subsurface", this, NodeMaterialConnectionPointDirection.Input, SubSurfaceBlock, "SubSurfaceBlock"));
             new NodeMaterialConnectionPointCustomObject("subsurface", this, NodeMaterialConnectionPointDirection.Input, SubSurfaceBlock, "SubSurfaceBlock"));
         this.registerInput("anisotropy", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
         this.registerInput("anisotropy", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("anisotropy", this, NodeMaterialConnectionPointDirection.Input, AnisotropyBlock, "AnisotropyBlock"));
             new NodeMaterialConnectionPointCustomObject("anisotropy", this, NodeMaterialConnectionPointDirection.Input, AnisotropyBlock, "AnisotropyBlock"));
+        this.registerInput("view", NodeMaterialBlockConnectionPointTypes.Matrix, true);
 
 
         this.registerOutput("ambient", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("ambient", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("diffuse", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("diffuse", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
@@ -477,6 +478,13 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     }
     }
 
 
     /**
     /**
+     * Gets the view matrix parameter
+     */
+    public get view(): NodeMaterialConnectionPoint {
+        return this._inputs[14];
+    }
+
+    /**
      * Gets the ambient output component
      * Gets the ambient output component
      */
      */
     public get ambient(): NodeMaterialConnectionPoint {
     public get ambient(): NodeMaterialConnectionPoint {
@@ -756,6 +764,9 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             });
             });
         } else {
         } else {
             state.compilationString += `vec4 worldPos = ${worldPos.associatedVariableName};\r\n`;
             state.compilationString += `vec4 worldPos = ${worldPos.associatedVariableName};\r\n`;
+            if (this.view.isConnected) {
+                state.compilationString += `mat4 view = ${this.view.associatedVariableName};\r\n`;
+            }
             state.compilationString += state._emitCodeFromInclude("shadowsVertex", comments, {
             state.compilationString += state._emitCodeFromInclude("shadowsVertex", comments, {
                 repeatKey: "maxSimultaneousLights"
                 repeatKey: "maxSimultaneousLights"
             });
             });

+ 1 - 0
src/Materials/Node/nodeMaterialBuildStateSharedData.ts

@@ -138,6 +138,7 @@ export class NodeMaterialBuildStateSharedData {
         this.variableNames["specularBase"] = 0;
         this.variableNames["specularBase"] = 0;
         this.variableNames["worldPos"] = 0;
         this.variableNames["worldPos"] = 0;
         this.variableNames["shadow"] = 0;
         this.variableNames["shadow"] = 0;
+        this.variableNames["view"] = 0;
 
 
         // Exclude known varyings
         // Exclude known varyings
         this.variableNames["vTBN"] = 0;
         this.variableNames["vTBN"] = 0;

+ 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
      * The first rig camera (left eye) will be used to calculate the projection
      */
      */
     disableScenePointerVectorUpdate: boolean;
     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
             // already attached
             return;
             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);
         const { laserPointer, selectionMesh } = this._generateNewMeshPair(xrController.pointer);
 
 
         // get two new meshes
         // get two new meshes
@@ -111,6 +129,17 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             tmpRay: new Ray(new Vector3(), new Vector3()),
             tmpRay: new Ray(new Vector3(), new Vector3()),
             id: WebXRControllerPointerSelection._idCounter++,
             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) {
         switch (xrController.inputSource.targetRayMode) {
             case "tracked-pointer":
             case "tracked-pointer":
                 return this._attachTrackedPointerRayMode(xrController);
                 return this._attachTrackedPointerRayMode(xrController);
@@ -141,6 +170,8 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
     private _scene: Scene;
     private _scene: Scene;
     private _tmpVectorForPickCompare = new Vector3();
     private _tmpVectorForPickCompare = new Vector3();
 
 
+    private _attachedController: string;
+
     /**
     /**
      * The module's name
      * The module's name
      */
      */
@@ -296,7 +327,16 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
 
 
     protected _onXRFrame(_xrFrame: XRFrame) {
     protected _onXRFrame(_xrFrame: XRFrame) {
         Object.keys(this._controllers).forEach((id) => {
         Object.keys(this._controllers).forEach((id) => {
+            // only do this for the selected pointer
             const controllerData = this._controllers[id];
             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;
             let controllerGlobalPosition: Vector3;
 
 
@@ -310,6 +350,10 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             } else {
             } else {
                 return;
                 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!
             // update pointerX and pointerY of the scene. Only if the flag is set to true!
             if (!this._options.disableScenePointerVectorUpdate && controllerGlobalPosition) {
             if (!this._options.disableScenePointerVectorUpdate && controllerGlobalPosition) {
                 const scene = this._xrSessionManager.scene;
                 const scene = this._xrSessionManager.scene;
@@ -350,6 +394,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
                 controllerData.meshUnderPointer = pick.pickedMesh;
                 controllerData.meshUnderPointer = pick.pickedMesh;
             } else {
             } else {
                 controllerData.selectionMesh.isVisible = false;
                 controllerData.selectionMesh.isVisible = false;
+                this._updatePointerDistance(controllerData.laserPointer, 1);
                 controllerData.meshUnderPointer = null;
                 controllerData.meshUnderPointer = null;
             }
             }
         });
         });
@@ -462,7 +507,6 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             return this._attachGazeMode(xrController);
             return this._attachGazeMode(xrController);
         }
         }
         controllerData.onFrameObserver = this._xrSessionManager.onXRFrameObservable.add(() => {
         controllerData.onFrameObserver = this._xrSessionManager.onXRFrameObservable.add(() => {
-            controllerData.laserPointer.isVisible = this.displayLaserPointer;
             (<StandardMaterial>controllerData.laserPointer.material).disableLighting = this.disablePointerLighting;
             (<StandardMaterial>controllerData.laserPointer.material).disableLighting = this.disablePointerLighting;
             (<StandardMaterial>controllerData.selectionMesh.material).disableLighting = this.disableSelectionMeshLighting;
             (<StandardMaterial>controllerData.selectionMesh.material).disableLighting = this.disableSelectionMeshLighting;
 
 
@@ -483,14 +527,21 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
                     if (component.changes.pressed) {
                     if (component.changes.pressed) {
                         const pressed = component.changes.pressed.current;
                         const pressed = component.changes.pressed.current;
                         if (controllerData.pick) {
                         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 {
                             } 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();
         controllerData.laserPointer.dispose();
         // remove from the map
         // remove from the map
         delete this._controllers[xrControllerUniqueId];
         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) {
     private _generateNewMeshPair(meshParent: Node) {