浏览代码

rotate teleport

Trevor Baron 6 年之前
父节点
当前提交
0ab84073ee
共有 1 个文件被更改,包括 121 次插入66 次删除
  1. 121 66
      src/Cameras/XR/webXRInput.ts

+ 121 - 66
src/Cameras/XR/webXRInput.ts

@@ -62,6 +62,8 @@ export class WebXRController {
      */
     public updateFromXRFrame(xrFrame: XRFrame, referenceSpace: XRReferenceSpace) {
         var pose = xrFrame.getPose(this.inputSource.targetRaySpace, referenceSpace);
+
+        // Update the pointer mesh
         if (pose) {
             Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
             if (!this.pointer.getScene().useRightHandedSystem) {
@@ -73,6 +75,7 @@ export class WebXRController {
             this._tmpMatrix.decompose(this.pointer.scaling, this.pointer.rotationQuaternion!, this.pointer.position);
         }
 
+        // Update the grip mesh if it exists
         if (this.inputSource.gripSpace && this.grip) {
             var pose = xrFrame.getPose(this.inputSource.gripSpace, referenceSpace);
             if (pose) {
@@ -88,6 +91,10 @@ export class WebXRController {
         }
     }
 
+    /**
+     * Gets a world space ray coming from the controller
+     * @param result the resulting ray
+     */
     public getWorldPointerRayToRef(result:Ray){
         // Force update to ensure picked point is synced with ray
         var worldMatrix = this.pointer.computeWorldMatrix(true)
@@ -197,7 +204,14 @@ export class WebXRInput implements IDisposable {
     }
 }
 
+/**
+ * Loads a controller model and adds it as a child of the WebXRControllers grip when the controller is created
+ */
 export class WebXRControllerModelLoader {
+    /**
+     * Creates the WebXRControllerModelLoader
+     * @param input xr input that creates the controllers
+     */
     constructor(input: WebXRInput){
         input.onControllerAddedObservable.add((c)=>{
             if(c.inputSource.gamepad && c.inputSource.gamepad.id === "oculus-touch"){
@@ -225,93 +239,94 @@ export class WebXRControllerModelLoader {
                     controllerModel.mesh!.parent = c.grip!
                     controllerModel.mesh!.rotationQuaternion = Quaternion.FromEulerAngles(0,Math.PI,0);
                 })
-            }
-            
+            } 
         })
     }
 }
 
+/**
+ * Handles pointer input automatically for the pointer of XR controllers
+ */
 export class WebXRControllerPointerSelection {
-    private _laserPointer: Mesh;
-    private _gazeTracker: Mesh;
-    private triggerDown = false;
+    
     public static _idCounter = 0;
-    private _id:number;
+    
     private _tmpRay = new Ray(new Vector3(), new Vector3());
     constructor(input: WebXRInput){
-        this._id = WebXRControllerPointerSelection._idCounter++;
+        
         input.onControllerAddedObservable.add((c)=>{
             var scene = c.pointer.getScene();
-            this._laserPointer = Mesh.CreateCylinder("laserPointer", 1, 0.0002, 0.004, 20, 1, scene, false);
-            this._laserPointer.parent = c.pointer
 
+            let _laserPointer: Mesh;
+            let _cursorMesh: Mesh;
+            let triggerDown = false;
+            let _id:number;
+            _id = WebXRControllerPointerSelection._idCounter++;
+
+            // Create a laser pointer for the XR controller
+            _laserPointer = Mesh.CreateCylinder("laserPointer", 1, 0.0002, 0.004, 20, 1, scene, false);
+            _laserPointer.parent = c.pointer
             var laserPointerMaterial = new StandardMaterial("laserPointerMat", scene);
             laserPointerMaterial.emissiveColor = new Color3(0.7, 0.7, 0.7);
             laserPointerMaterial.alpha = 0.6;
-            this._laserPointer.material = laserPointerMaterial;
-            
-            this._laserPointer.rotation.x = Math.PI / 2;
-            this._updatePointerDistance(1)
-            this._laserPointer.isPickable = false;
-
-
-            this._gazeTracker = Mesh.CreateTorus("gazeTracker", 0.0035*3, 0.0025*3, 20, scene, false);
-            this._gazeTracker.bakeCurrentTransformIntoVertices();
-            this._gazeTracker.isPickable = false;
-            this._gazeTracker.isVisible = false;
+            _laserPointer.material = laserPointerMaterial;
+            _laserPointer.rotation.x = Math.PI / 2;
+            this._updatePointerDistance(_laserPointer,1)
+            _laserPointer.isPickable = false;
+
+            // Create a gaze tracker for the  XR controlelr
+            _cursorMesh = Mesh.CreateTorus("gazeTracker", 0.0035*3, 0.0025*3, 20, scene, false);
+            _cursorMesh.bakeCurrentTransformIntoVertices();
+            _cursorMesh.isPickable = false;
+            _cursorMesh.isVisible = false;
             var targetMat = new StandardMaterial("targetMat", scene);
             targetMat.specularColor = Color3.Black();
             targetMat.emissiveColor = new Color3(0.7, 0.7, 0.7);
             targetMat.backFaceCulling = false;
-            this._gazeTracker.material = targetMat;
+            _cursorMesh.material = targetMat;
 
-
-            
-
-            scene.onBeforeRenderObservable.add(()=>{                
+            scene.onBeforeRenderObservable.add(()=>{     
+                // Every frame check collisions/input        
                 c.getWorldPointerRayToRef(this._tmpRay)
                 var pick = scene.pickWithRay(this._tmpRay)
-
                 if(pick){
                     if(c.inputSource.gamepad && c.inputSource.gamepad.buttons[0] && c.inputSource.gamepad.buttons[0].value > 0.7){
-                        if(!this.triggerDown){
-                            scene.simulatePointerDown(pick, { pointerId: this._id });
+                        if(!triggerDown){
+                            scene.simulatePointerDown(pick, { pointerId: _id });
                         }
-                        this.triggerDown = true;
+                        triggerDown = true;
                     }else{
-                        if(this.triggerDown){
-                            scene.simulatePointerUp(pick, { pointerId: this._id });
+                        if(triggerDown){
+                            scene.simulatePointerUp(pick, { pointerId: _id });
                         }
-                        this.triggerDown = false;
+                        triggerDown = false;
                     }
-                    scene.simulatePointerMove(pick, { pointerId: this._id });
+                    scene.simulatePointerMove(pick, { pointerId: _id });
                 }
                 
-
-                
                 if(pick && pick.pickedPoint && pick.hit){
-                    this._updatePointerDistance(pick.distance)
+                    // Update laser state
+                    this._updatePointerDistance(_laserPointer, pick.distance)
 
-                    // Scale based on distance
-                    this._gazeTracker.position.copyFrom(pick.pickedPoint)
-                    this._gazeTracker.scaling.x = Math.sqrt(pick.distance);
-                    this._gazeTracker.scaling.y = Math.sqrt(pick.distance);
-                    this._gazeTracker.scaling.z = Math.sqrt(pick.distance);
+                    // Update cursor state
+                    _cursorMesh.position.copyFrom(pick.pickedPoint)
+                    _cursorMesh.scaling.x = Math.sqrt(pick.distance);
+                    _cursorMesh.scaling.y = Math.sqrt(pick.distance);
+                    _cursorMesh.scaling.z = Math.sqrt(pick.distance);
 
                     // To avoid z-fighting
                     var pickNormal = this._convertNormalToDirectionOfRay(pick.getNormal(), this._tmpRay);
                     let deltaFighting = 0.002;
-                    this._gazeTracker.position.copyFrom(pick.pickedPoint);
+                    _cursorMesh.position.copyFrom(pick.pickedPoint);
                     if (pickNormal) {
                         var axis1 = Vector3.Cross(Axis.Y, pickNormal);
                         var axis2 = Vector3.Cross(pickNormal, axis1);
-                        Vector3.RotationFromAxisToRef(axis2, pickNormal, axis1, this._gazeTracker.rotation);
-                        this._gazeTracker.position.addInPlace(pickNormal.scale(deltaFighting));
+                        Vector3.RotationFromAxisToRef(axis2, pickNormal, axis1, _cursorMesh.rotation);
+                        _cursorMesh.position.addInPlace(pickNormal.scale(deltaFighting));
                     }
-
-                    this._gazeTracker.isVisible = true;
+                    _cursorMesh.isVisible = true;
                 }else{
-                    this._gazeTracker.isVisible = false;
+                    _cursorMesh.isVisible = false;
                 }
             })
         })
@@ -327,24 +342,37 @@ export class WebXRControllerPointerSelection {
         return normal;
     }
 
-    public _updatePointerDistance(distance: number = 100) {
-        this._laserPointer.scaling.y = distance;
-        this._laserPointer.position.z = distance / 2;
+    private _updatePointerDistance(_laserPointer:Mesh, distance: number = 100) {
+        _laserPointer.scaling.y = distance;
+        _laserPointer.position.z = distance / 2;
     }
 }
 
+/**
+ * Enables teleportation
+ */
 export class WebXRControllerTeleportation {
     private _teleportationFillColor: string = "#444444";
     private _teleportationBorderColor: string = "#FFFFFF";
-    private _forwardReadyToTeleport = false;
-    private _backwardReadyToTeleport = false;
+
     private _tmpRay = new Ray(new Vector3(), new Vector3());
     private _tmpVector = new Vector3();
-    constructor(input: WebXRInput, public floorMeshes = []){
+
+    /**
+     * 
+     * @param input 
+     * @param floorMeshes 
+     */
+    constructor(input: WebXRInput, public floorMeshes:Array<AbstractMesh> = []){
         input.onControllerAddedObservable.add((c)=>{
             var scene = c.pointer.getScene();
 
-            // Teleport animation
+            var _forwardReadyToTeleport = false;
+            var _backwardReadyToTeleport = false;
+            var _leftReadyToTeleport = false;
+            var _rightReadyToTeleport = false;
+
+            // Teleport target abd it's animation
             var teleportationTarget = Mesh.CreateGround("teleportationTarget", 2, 2, 2, scene);
             teleportationTarget.isPickable = false;
             var length = 512;
@@ -391,14 +419,15 @@ export class WebXRControllerTeleportation {
             torus.animations.push(animationInnerCircle);
             scene.beginAnimation(torus, 0, 60, true);
 
-
-
+            // Handle user input on every frame
             scene.onBeforeRenderObservable.add(()=>{
-                if(this._forwardReadyToTeleport){
+                // Move the teleportationTarget to where the user is targetting to teleport to
+                if(_forwardReadyToTeleport){
                     c.getWorldPointerRayToRef(this._tmpRay)
-                    var pick = scene.pickWithRay(this._tmpRay)
+                    var pick = scene.pickWithRay(this._tmpRay, (o)=>{
+                        return floorMeshes.indexOf(o) !== -1;
+                    })
                     if(pick && pick.pickedPoint){
-
                         // To avoid z-fighting
                         teleportationTarget.position.copyFrom(pick.pickedPoint);
                         teleportationTarget.position.y += 0.002;
@@ -412,21 +441,25 @@ export class WebXRControllerTeleportation {
 
                 if(c.inputSource.gamepad){
                     if(c.inputSource.gamepad.axes[1]){
+                        // Forward teleportation
                         if(c.inputSource.gamepad.axes[1] < -0.7){
-                            this._forwardReadyToTeleport = true
+                            _forwardReadyToTeleport = true
                         }else{
-                            if(this._forwardReadyToTeleport){
+                            if(_forwardReadyToTeleport){
+                                // Teleport the users feet to where they targetted
                                 this._tmpVector.copyFrom(teleportationTarget.position)
                                 this._tmpVector.y += input.xrExperienceHelper.camera.position.y;
                                 input.xrExperienceHelper.setPositionOfCameraUsingContainer(this._tmpVector)
                             }
-                            this._forwardReadyToTeleport = false
+                            _forwardReadyToTeleport = false
                         }
 
+                        // Backward teleportation
                         if(c.inputSource.gamepad.axes[1] > 0.7){
-                            this._backwardReadyToTeleport = true
+                            _backwardReadyToTeleport = true
                         }else{
-                            if(this._backwardReadyToTeleport){
+                            if(_backwardReadyToTeleport){
+                                // Cast a ray down from behind the user
                                 var camMat = input.xrExperienceHelper.camera.computeWorldMatrix();
                                 var q = new Quaternion()
                                 camMat.decompose(undefined, q, this._tmpRay.origin)
@@ -437,15 +470,37 @@ export class WebXRControllerTeleportation {
                                 this._tmpVector.y = -1.5;
                                 this._tmpVector.normalize()
                                 this._tmpRay.direction.copyFrom(this._tmpVector)
-                                var pick = scene.pickWithRay(this._tmpRay)
+                                var pick = scene.pickWithRay(this._tmpRay, (o)=>{
+                                    return floorMeshes.indexOf(o) !== -1;
+                                })
 
                                 if(pick && pick.pickedPoint){
+                                    // Teleport the users feet to where they targetted
                                     this._tmpVector.copyFrom(pick.pickedPoint)
                                     this._tmpVector.y += input.xrExperienceHelper.camera.position.y;
                                     input.xrExperienceHelper.setPositionOfCameraUsingContainer(this._tmpVector)
                                 }
                             }
-                            this._backwardReadyToTeleport = false
+                            _backwardReadyToTeleport = false
+                        }
+                    }
+
+                    if(c.inputSource.gamepad.axes[0]){
+                        if(c.inputSource.gamepad.axes[0] < -0.7){
+                            _leftReadyToTeleport = true
+                        }else{
+                            if(_leftReadyToTeleport){
+                                input.xrExperienceHelper.rotateCameraByQuaternionUsingContainer(Quaternion.FromEulerAngles(0, -Math.PI/4, 0))
+                            }
+                            _leftReadyToTeleport = false
+                        }
+                        if(c.inputSource.gamepad.axes[0] > 0.7){
+                            _rightReadyToTeleport = true
+                        }else{
+                            if(_rightReadyToTeleport){
+                                input.xrExperienceHelper.rotateCameraByQuaternionUsingContainer(Quaternion.FromEulerAngles(0, Math.PI/4, 0))
+                            }
+                            _rightReadyToTeleport = false
                         }
                     }