Browse Source

Prettifier definition file (#8571)

* Prettier definition

* formatting the webxr code as an example

* singlequote off
Raanan Weber 5 years ago
parent
commit
ca8a620e6c
32 changed files with 1457 additions and 1434 deletions
  1. 5 0
      .prettierrc
  2. 7 8
      src/XR/features/WebXRAbstractFeature.ts
  3. 33 29
      src/XR/features/WebXRAnchorSystem.ts
  4. 16 9
      src/XR/features/WebXRBackgroundRemover.ts
  5. 42 42
      src/XR/features/WebXRControllerPhysics.ts
  6. 90 60
      src/XR/features/WebXRControllerPointerSelection.ts
  7. 86 67
      src/XR/features/WebXRControllerTeleportation.ts
  8. 34 25
      src/XR/features/WebXRHitTest.ts
  9. 25 19
      src/XR/features/WebXRHitTestLegacy.ts
  10. 22 14
      src/XR/features/WebXRPlaneDetector.ts
  11. 2 2
      src/XR/features/index.ts
  12. 1 1
      src/XR/index.ts
  13. 1 1
      src/XR/motionController/index.ts
  14. 56 49
      src/XR/motionController/webXRAbstractMotionController.ts
  15. 16 16
      src/XR/motionController/webXRControllerComponent.ts
  16. 45 50
      src/XR/motionController/webXRGenericMotionController.ts
  17. 124 135
      src/XR/motionController/webXRHTCViveMotionController.ts
  18. 303 385
      src/XR/motionController/webXRMicrosoftMixedRealityController.ts
  19. 38 37
      src/XR/motionController/webXRMotionControllerManager.ts
  20. 145 160
      src/XR/motionController/webXROculusTouchMotionController.ts
  21. 34 29
      src/XR/motionController/webXRProfiledMotionController.ts
  22. 16 17
      src/XR/webXRCamera.ts
  23. 63 64
      src/XR/webXRDefaultExperience.ts
  24. 22 18
      src/XR/webXREnterExitUI.ts
  25. 73 60
      src/XR/webXRExperienceHelper.ts
  26. 18 18
      src/XR/webXRFeaturesManager.ts
  27. 15 9
      src/XR/webXRInput.ts
  28. 33 33
      src/XR/webXRInputSource.ts
  29. 15 16
      src/XR/webXRManagedOutputCanvas.ts
  30. 72 56
      src/XR/webXRSessionManager.ts
  31. 3 3
      src/XR/webXRTypes.ts
  32. 2 2
      tslint.json

+ 5 - 0
.prettierrc

@@ -0,0 +1,5 @@
+{
+    "trailingComma": "es5",
+    "tabWidth": 4,
+    "printWidth": 300
+  }

+ 7 - 8
src/XR/features/WebXRAbstractFeature.ts

@@ -1,7 +1,7 @@
-import { IWebXRFeature } from '../webXRFeaturesManager';
-import { Observer, Observable, EventState } from '../../Misc/observable';
-import { Nullable } from '../../types';
-import { WebXRSessionManager } from '../webXRSessionManager';
+import { IWebXRFeature } from "../webXRFeaturesManager";
+import { Observer, Observable, EventState } from "../../Misc/observable";
+import { Nullable } from "../../types";
+import { WebXRSessionManager } from "../webXRSessionManager";
 
 /**
  * This is the base class for all WebXR features.
@@ -24,8 +24,7 @@ export abstract class WebXRAbstractFeature implements IWebXRFeature {
      * Construct a new (abstract) WebXR feature
      * @param _xrSessionManager the xr session manager for this feature
      */
-    constructor(protected _xrSessionManager: WebXRSessionManager) {
-    }
+    constructor(protected _xrSessionManager: WebXRSessionManager) {}
 
     /**
      * Is this feature attached
@@ -89,7 +88,7 @@ export abstract class WebXRAbstractFeature implements IWebXRFeature {
     protected _addNewAttachObserver<T>(observable: Observable<T>, callback: (eventData: T, eventState: EventState) => void) {
         this._removeOnDetach.push({
             observable,
-            observer: observable.add(callback)
+            observer: observable.add(callback),
         });
     }
 
@@ -99,4 +98,4 @@ export abstract class WebXRAbstractFeature implements IWebXRFeature {
      * @param _xrFrame the current frame
      */
     protected abstract _onXRFrame(_xrFrame: XRFrame): void;
-}
+}

+ 33 - 29
src/XR/features/WebXRAnchorSystem.ts

@@ -1,11 +1,11 @@
-import { WebXRFeatureName, WebXRFeaturesManager } from '../webXRFeaturesManager';
-import { WebXRSessionManager } from '../webXRSessionManager';
-import { Observable } from '../../Misc/observable';
-import { Matrix, Vector3, Quaternion } from '../../Maths/math.vector';
-import { TransformNode } from '../../Meshes/transformNode';
-import { WebXRAbstractFeature } from './WebXRAbstractFeature';
-import { IWebXRHitResult } from './WebXRHitTest';
-import { Tools } from '../../Misc/tools';
+import { WebXRFeatureName, WebXRFeaturesManager } from "../webXRFeaturesManager";
+import { WebXRSessionManager } from "../webXRSessionManager";
+import { Observable } from "../../Misc/observable";
+import { Matrix, Vector3, Quaternion } from "../../Maths/math.vector";
+import { TransformNode } from "../../Meshes/transformNode";
+import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
+import { IWebXRHitResult } from "./WebXRHitTest";
+import { Tools } from "../../Misc/tools";
 
 /**
  * Configuration options of the anchor system
@@ -134,7 +134,7 @@ export class WebXRAnchorSystem extends WebXRAbstractFeature {
         }
         return {
             position: this._tmpVector,
-            rotationQuaternion: this._tmpQuaternion
+            rotationQuaternion: this._tmpQuaternion,
         };
     }
 
@@ -152,15 +152,13 @@ export class WebXRAnchorSystem extends WebXRAbstractFeature {
         // convert to XR space (right handed) if needed
         this._populateTmpTransformation(position, rotationQuaternion);
         // the matrix that we'll use
-        const m = new XRRigidTransform({x: this._tmpVector.x, y: this._tmpVector.y, z: this._tmpVector.z},
-                                       {x: this._tmpQuaternion.x, y: this._tmpQuaternion.y, z: this._tmpQuaternion.z, w: this._tmpQuaternion.w});
+        const m = new XRRigidTransform({ x: this._tmpVector.x, y: this._tmpVector.y, z: this._tmpVector.z }, { x: this._tmpQuaternion.x, y: this._tmpQuaternion.y, z: this._tmpQuaternion.z, w: this._tmpQuaternion.w });
         if (!hitTestResult.xrHitResult.createAnchor) {
             throw new Error('Anchors not enabled in this browsed. Add "anchors" to optional features');
         } else {
             try {
                 return hitTestResult.xrHitResult.createAnchor(m);
-            }
-            catch (error) {
+            } catch (error) {
                 throw new Error(error);
             }
         }
@@ -182,8 +180,7 @@ export class WebXRAnchorSystem extends WebXRAbstractFeature {
         // convert to XR space (right handed) if needed
         this._populateTmpTransformation(position, rotationQuaternion);
         // the matrix that we'll use
-        const xrTransformation = new XRRigidTransform({x: this._tmpVector.x, y: this._tmpVector.y, z: this._tmpVector.z},
-                                                      {x: this._tmpQuaternion.x, y: this._tmpQuaternion.y, z: this._tmpQuaternion.z, w: this._tmpQuaternion.w});
+        const xrTransformation = new XRRigidTransform({ x: this._tmpVector.x, y: this._tmpVector.y, z: this._tmpVector.z }, { x: this._tmpQuaternion.x, y: this._tmpQuaternion.y, z: this._tmpQuaternion.z, w: this._tmpQuaternion.w });
         if (forceCreateInCurrentFrame && this.attached && this._xrSessionManager.currentFrame) {
             return this._createAnchorAtTransformation(xrTransformation, this._xrSessionManager.currentFrame);
         } else {
@@ -192,7 +189,7 @@ export class WebXRAnchorSystem extends WebXRAbstractFeature {
                 this._futureAnchors.push({
                     xrTransformation,
                     resolve,
-                    reject
+                    reject,
                 });
             });
         }
@@ -232,14 +229,18 @@ export class WebXRAnchorSystem extends WebXRAbstractFeature {
     }
 
     protected _onXRFrame(frame: XRFrame) {
-        if (!this.attached || !frame) { return; }
+        if (!this.attached || !frame) {
+            return;
+        }
 
         const trackedAnchors = frame.trackedAnchors;
         if (trackedAnchors) {
-            const toRemove = this._trackedAnchors.filter((anchor) => !trackedAnchors.has(anchor.xrAnchor)).map((anchor) => {
-                const index = this._trackedAnchors.indexOf(anchor);
-                return index;
-            });
+            const toRemove = this._trackedAnchors
+                .filter((anchor) => !trackedAnchors.has(anchor.xrAnchor))
+                .map((anchor) => {
+                    const index = this._trackedAnchors.indexOf(anchor);
+                    return index;
+                });
             let idxTracker = 0;
             toRemove.forEach((index) => {
                 const anchor = this._trackedAnchors.splice(index - idxTracker, 1)[0];
@@ -251,7 +252,7 @@ export class WebXRAnchorSystem extends WebXRAbstractFeature {
                 if (!this._lastFrameDetected.has(xrAnchor)) {
                     const newAnchor: Partial<IWebXRAnchor> = {
                         id: anchorIdProvider++,
-                        xrAnchor: xrAnchor
+                        xrAnchor: xrAnchor,
                     };
                     const anchor = this._updateAnchorWithXRFrame(xrAnchor, newAnchor, frame);
                     this._trackedAnchors.push(anchor);
@@ -282,7 +283,7 @@ export class WebXRAnchorSystem extends WebXRAbstractFeature {
                 return;
             }
             if (!frame.createAnchor) {
-                futureAnchor.reject('Anchors not enabled in this browser');
+                futureAnchor.reject("Anchors not enabled in this browser");
             }
             this._createAnchorAtTransformation(futureAnchor.xrTransformation, frame).then(futureAnchor.resolve, futureAnchor.reject);
         }
@@ -325,17 +326,20 @@ export class WebXRAnchorSystem extends WebXRAbstractFeature {
         if (xrFrame.createAnchor) {
             try {
                 return xrFrame.createAnchor(xrTransformation, this._referenceSpaceForFrameAnchors ?? this._xrSessionManager.referenceSpace);
-            }
-            catch (error) {
+            } catch (error) {
                 throw new Error(error);
             }
         } else {
-            throw new Error('Anchors are not enabled in your browser');
+            throw new Error("Anchors are not enabled in your browser");
         }
     }
 }
 
 // register the plugin
-WebXRFeaturesManager.AddWebXRFeature(WebXRAnchorSystem.Name, (xrSessionManager, options) => {
-    return () => new WebXRAnchorSystem(xrSessionManager, options);
-}, WebXRAnchorSystem.Version);
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRAnchorSystem.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRAnchorSystem(xrSessionManager, options);
+    },
+    WebXRAnchorSystem.Version
+);

+ 16 - 9
src/XR/features/WebXRBackgroundRemover.ts

@@ -1,8 +1,8 @@
 import { WebXRFeaturesManager, WebXRFeatureName } from "../webXRFeaturesManager";
-import { WebXRSessionManager } from '../webXRSessionManager';
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { Observable } from '../../Misc/observable';
-import { WebXRAbstractFeature } from './WebXRAbstractFeature';
+import { WebXRSessionManager } from "../webXRSessionManager";
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { Observable } from "../../Misc/observable";
+import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
 
 /**
  * Options interface for the background remover plugin
@@ -57,11 +57,13 @@ export class WebXRBackgroundRemover extends WebXRAbstractFeature {
      * @param _xrSessionManager the session manager for this module
      * @param options read-only options to be used in this module
      */
-    constructor(_xrSessionManager: WebXRSessionManager,
+    constructor(
+        _xrSessionManager: WebXRSessionManager,
         /**
          * read-only options to be used in this module
          */
-        public readonly options: IWebXRBackgroundRemoverOptions = {}) {
+        public readonly options: IWebXRBackgroundRemoverOptions = {}
+    ) {
         super(_xrSessionManager);
     }
 
@@ -132,6 +134,11 @@ export class WebXRBackgroundRemover extends WebXRAbstractFeature {
 }
 
 //register the plugin
-WebXRFeaturesManager.AddWebXRFeature(WebXRBackgroundRemover.Name, (xrSessionManager, options) => {
-    return () => new WebXRBackgroundRemover(xrSessionManager, options);
-}, WebXRBackgroundRemover.Version, true);
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRBackgroundRemover.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRBackgroundRemover(xrSessionManager, options);
+    },
+    WebXRBackgroundRemover.Version,
+    true
+);

+ 42 - 42
src/XR/features/WebXRControllerPhysics.ts

@@ -7,8 +7,8 @@ import { WebXRSessionManager } from "../webXRSessionManager";
 import { AbstractMesh } from "../../Meshes/abstractMesh";
 import { SphereBuilder } from "../../Meshes/Builders/sphereBuilder";
 import { WebXRFeatureName, WebXRFeaturesManager } from "../webXRFeaturesManager";
-import { Logger } from '../../Misc/logger';
-import { Nullable } from '../../types';
+import { Logger } from "../../Misc/logger";
+import { Nullable } from "../../types";
 
 /**
  * Options for the controller physics feature
@@ -29,7 +29,7 @@ export class IWebXRControllerPhysicsOptions {
         /**
          * the size of the impostor. Defaults to 10cm
          */
-        impostorSize?: number | { width: number, height: number, depth: number };
+        impostorSize?: number | { width: number; height: number; depth: number };
         /**
          * Friction definitions
          */
@@ -55,7 +55,7 @@ export class IWebXRControllerPhysicsOptions {
         /**
          * the size of the impostor. Defaults to 10cm
          */
-        impostorSize?: number | { width: number, height: number, depth: number };
+        impostorSize?: number | { width: number; height: number; depth: number };
         /**
          * Friction definitions
          */
@@ -76,8 +76,7 @@ export class IWebXRControllerPhysicsOptions {
  * including naive calculation of their linear and angular velocity
  */
 export class WebXRControllerPhysics extends WebXRAbstractFeature {
-    private _attachController = (xrController: WebXRInputSource
-    ) => {
+    private _attachController = (xrController: WebXRInputSource) => {
         if (this._controllers[xrController.uniqueId]) {
             // already attached
             return;
@@ -91,24 +90,24 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
                 motionController.onModelLoadedObservable.addOnce(() => {
                     const impostor = new PhysicsImpostor(motionController.rootMesh!, PhysicsImpostor.MeshImpostor, {
                         mass: 0,
-                        ...this._options.physicsProperties
+                        ...this._options.physicsProperties,
                     });
                     const controllerMesh = xrController.grip || xrController.pointer;
                     this._controllers[xrController.uniqueId] = {
                         xrController,
                         impostor,
                         oldPos: controllerMesh.position.clone(),
-                        oldRotation: controllerMesh.rotationQuaternion!.clone()
+                        oldRotation: controllerMesh.rotationQuaternion!.clone(),
                     };
                 });
             });
         } else {
             const impostorType: number = this._options.physicsProperties!.impostorType || PhysicsImpostor.SphereImpostor;
-            const impostorSize: number | { width: number, height: number, depth: number } = this._options.physicsProperties!.impostorSize || 0.1;
-            const impostorMesh = SphereBuilder.CreateSphere('impostor-mesh-' + xrController.uniqueId, {
-                diameterX: typeof impostorSize === 'number' ? impostorSize : impostorSize.width,
-                diameterY: typeof impostorSize === 'number' ? impostorSize : impostorSize.height,
-                diameterZ: typeof impostorSize === 'number' ? impostorSize : impostorSize.depth
+            const impostorSize: number | { width: number; height: number; depth: number } = this._options.physicsProperties!.impostorSize || 0.1;
+            const impostorMesh = SphereBuilder.CreateSphere("impostor-mesh-" + xrController.uniqueId, {
+                diameterX: typeof impostorSize === "number" ? impostorSize : impostorSize.width,
+                diameterY: typeof impostorSize === "number" ? impostorSize : impostorSize.height,
+                diameterZ: typeof impostorSize === "number" ? impostorSize : impostorSize.depth,
             });
             impostorMesh.isVisible = this._debugMode;
             impostorMesh.isPickable = false;
@@ -118,25 +117,25 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
             impostorMesh.rotationQuaternion!.copyFrom(controllerMesh.rotationQuaternion!);
             const impostor = new PhysicsImpostor(impostorMesh, impostorType, {
                 mass: 0,
-                ...this._options.physicsProperties
+                ...this._options.physicsProperties,
             });
             this._controllers[xrController.uniqueId] = {
                 xrController,
                 impostor,
-                impostorMesh
+                impostorMesh,
             };
         }
-    }
+    };
 
     private _controllers: {
         [id: string]: {
             xrController: WebXRInputSource;
-            impostorMesh?: AbstractMesh,
-            impostor: PhysicsImpostor
+            impostorMesh?: AbstractMesh;
+            impostor: PhysicsImpostor;
             oldPos?: Vector3;
-            oldSpeed?: Vector3,
+            oldSpeed?: Vector3;
             oldRotation?: Quaternion;
-        }
+        };
     } = {};
     private _debugMode = false;
     private _delta: number = 0;
@@ -165,8 +164,7 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
     constructor(_xrSessionManager: WebXRSessionManager, private readonly _options: IWebXRControllerPhysicsOptions) {
         super(_xrSessionManager);
         if (!this._options.physicsProperties) {
-            this._options.physicsProperties = {
-            };
+            this._options.physicsProperties = {};
         }
     }
 
@@ -218,13 +216,13 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
             const params = this._options.headsetImpostorParams || {
                 impostorType: PhysicsImpostor.SphereImpostor,
                 restitution: 0.8,
-                impostorSize: 0.3
+                impostorSize: 0.3,
             };
             const impostorSize = params.impostorSize || 0.3;
-            this._headsetMesh = SphereBuilder.CreateSphere('headset-mesh', {
-                diameterX: typeof impostorSize === 'number' ? impostorSize : impostorSize.width,
-                diameterY: typeof impostorSize === 'number' ? impostorSize : impostorSize.height,
-                diameterZ: typeof impostorSize === 'number' ? impostorSize : impostorSize.depth
+            this._headsetMesh = SphereBuilder.CreateSphere("headset-mesh", {
+                diameterX: typeof impostorSize === "number" ? impostorSize : impostorSize.width,
+                diameterY: typeof impostorSize === "number" ? impostorSize : impostorSize.height,
+                diameterZ: typeof impostorSize === "number" ? impostorSize : impostorSize.depth,
             });
             this._headsetMesh.rotationQuaternion = new Quaternion();
             this._headsetMesh.isVisible = false;
@@ -283,20 +281,15 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
      * Update the physics properties provided in the constructor
      * @param newProperties the new properties object
      */
-    public setPhysicsProperties(newProperties: {
-        impostorType?: number,
-        impostorSize?: number | { width: number, height: number, depth: number },
-        friction?: number,
-        restitution?: number
-    }) {
+    public setPhysicsProperties(newProperties: { impostorType?: number; impostorSize?: number | { width: number; height: number; depth: number }; friction?: number; restitution?: number }) {
         this._options.physicsProperties = {
             ...this._options.physicsProperties,
-            ...newProperties
+            ...newProperties,
         };
     }
 
     protected _onXRFrame(_xrFrame: any): void {
-        this._delta = (this._xrSessionManager.currentTimestamp - this._lastTimestamp);
+        this._delta = this._xrSessionManager.currentTimestamp - this._lastTimestamp;
         this._lastTimestamp = this._xrSessionManager.currentTimestamp;
         if (this._headsetMesh) {
             this._headsetMesh.position.copyFrom(this._options.xrInput.xrCamera.position);
@@ -313,7 +306,7 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
             this._tmpVector.scaleInPlace(1000 / this._delta);
             controllerData.impostor.setLinearVelocity(this._tmpVector);
             if (this._debugMode) {
-                console.log(this._tmpVector, 'linear');
+                console.log(this._tmpVector, "linear");
             }
 
             if (!comparedQuaternion.equalsWithEpsilon(controllerMesh.rotationQuaternion!)) {
@@ -326,11 +319,11 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
                     this._tmpVector.scaleInPlace(2);
                 } else {
                     const angle = 2 * Math.atan2(len, this._tmpQuaternion.w);
-                    this._tmpVector.scaleInPlace((angle / (len * (this._delta / 1000))));
+                    this._tmpVector.scaleInPlace(angle / (len * (this._delta / 1000)));
                 }
                 controllerData.impostor.setAngularVelocity(this._tmpVector);
                 if (this._debugMode) {
-                    console.log(this._tmpVector, this._tmpQuaternion, 'angular');
+                    console.log(this._tmpVector, this._tmpQuaternion, "angular");
                 }
             }
             comparedPosition.copyFrom(controllerMesh.position);
@@ -340,7 +333,9 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
 
     private _detachController(xrControllerUniqueId: string) {
         const controllerData = this._controllers[xrControllerUniqueId];
-        if (!controllerData) { return; }
+        if (!controllerData) {
+            return;
+        }
         if (controllerData.impostorMesh) {
             controllerData.impostorMesh.dispose();
         }
@@ -350,6 +345,11 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
 }
 
 //register the plugin
-WebXRFeaturesManager.AddWebXRFeature(WebXRControllerPhysics.Name, (xrSessionManager, options) => {
-    return () => new WebXRControllerPhysics(xrSessionManager, options);
-}, WebXRControllerPhysics.Version, true);
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRControllerPhysics.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRControllerPhysics(xrSessionManager, options);
+    },
+    WebXRControllerPhysics.Version,
+    true
+);

+ 90 - 60
src/XR/features/WebXRControllerPointerSelection.ts

@@ -1,23 +1,23 @@
 import { WebXRFeaturesManager, WebXRFeatureName } from "../webXRFeaturesManager";
-import { WebXRSessionManager } from '../webXRSessionManager';
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { Observer } from '../../Misc/observable';
-import { WebXRInput } from '../webXRInput';
-import { WebXRInputSource } from '../webXRInputSource';
-import { Scene } from '../../scene';
-import { WebXRControllerComponent } from '../motionController/webXRControllerComponent';
-import { Nullable } from '../../types';
-import { Vector3 } from '../../Maths/math.vector';
-import { Color3 } from '../../Maths/math.color';
-import { Axis } from '../../Maths/math.axis';
-import { StandardMaterial } from '../../Materials/standardMaterial';
-import { CylinderBuilder } from '../../Meshes/Builders/cylinderBuilder';
-import { TorusBuilder } from '../../Meshes/Builders/torusBuilder';
-import { Ray } from '../../Culling/ray';
-import { PickingInfo } from '../../Collisions/pickingInfo';
-import { WebXRAbstractFeature } from './WebXRAbstractFeature';
-import { UtilityLayerRenderer } from '../../Rendering/utilityLayerRenderer';
-import { WebXRAbstractMotionController } from '../motionController/webXRAbstractMotionController';
+import { WebXRSessionManager } from "../webXRSessionManager";
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { Observer } from "../../Misc/observable";
+import { WebXRInput } from "../webXRInput";
+import { WebXRInputSource } from "../webXRInputSource";
+import { Scene } from "../../scene";
+import { WebXRControllerComponent } from "../motionController/webXRControllerComponent";
+import { Nullable } from "../../types";
+import { Vector3 } from "../../Maths/math.vector";
+import { Color3 } from "../../Maths/math.color";
+import { Axis } from "../../Maths/math.axis";
+import { StandardMaterial } from "../../Materials/standardMaterial";
+import { CylinderBuilder } from "../../Meshes/Builders/cylinderBuilder";
+import { TorusBuilder } from "../../Meshes/Builders/torusBuilder";
+import { Ray } from "../../Culling/ray";
+import { PickingInfo } from "../../Collisions/pickingInfo";
+import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
+import { UtilityLayerRenderer } from "../../Rendering/utilityLayerRenderer";
+import { WebXRAbstractMotionController } from "../motionController/webXRAbstractMotionController";
 
 /**
  * Options interface for the pointer selection module
@@ -90,7 +90,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             meshUnderPointer: null,
             pick: null,
             tmpRay: new Ray(new Vector3(), new Vector3()),
-            id: WebXRControllerPointerSelection._idCounter++
+            id: WebXRControllerPointerSelection._idCounter++,
         };
         switch (xrController.inputSource.targetRayMode) {
             case "tracked-pointer":
@@ -100,7 +100,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             case "screen":
                 return this._attachScreenRayMode(xrController);
         }
-    }
+    };
 
     private _controllers: {
         [controllerUniqueId: string]: {
@@ -115,7 +115,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
             id: number;
             tmpRay: Ray;
             // event support
-            eventListeners?: {[event in XREventType]?: ((event: XRInputSourceEvent) => void)};
+            eventListeners?: { [event in XREventType]?: (event: XRInputSourceEvent) => void };
         };
     } = {};
     private _scene: Scene;
@@ -259,8 +259,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
 
             // Every frame check collisions/input
             controllerData.xrController.getWorldPointerRayToRef(controllerData.tmpRay);
-            controllerData.pick = this._scene.pickWithRay(controllerData.tmpRay,
-                this._scene.pointerMovePredicate || this.raySelectionPredicate);
+            controllerData.pick = this._scene.pickWithRay(controllerData.tmpRay, this._scene.pointerMovePredicate || this.raySelectionPredicate);
 
             const pick = controllerData.pick;
 
@@ -297,20 +296,26 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
         const controllerData = this._controllers[xrController.uniqueId];
         // attached when touched, detaches when raised
         const timeToSelect = this._options.timeToSelect || 3000;
-        const sceneToRenderTo = this._options.useUtilityLayer ? (this._options.customUtilityLayerScene || UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene) : this._scene;
+        const sceneToRenderTo = this._options.useUtilityLayer ? this._options.customUtilityLayerScene || UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene : this._scene;
         let oldPick = new PickingInfo();
-        let discMesh = TorusBuilder.CreateTorus("selection", {
-            diameter: 0.0035 * 15,
-            thickness: 0.0025 * 6,
-            tessellation: 20
-        }, sceneToRenderTo);
+        let discMesh = TorusBuilder.CreateTorus(
+            "selection",
+            {
+                diameter: 0.0035 * 15,
+                thickness: 0.0025 * 6,
+                tessellation: 20,
+            },
+            sceneToRenderTo
+        );
         discMesh.isVisible = false;
         discMesh.isPickable = false;
         discMesh.parent = controllerData.selectionMesh;
         let timer = 0;
         let downTriggered = false;
         controllerData.onFrameObserver = this._xrSessionManager.onXRFrameObservable.add(() => {
-            if (!controllerData.pick) { return; }
+            if (!controllerData.pick) {
+                return;
+            }
             controllerData.laserPointer.material!.alpha = 0;
             discMesh.isVisible = false;
             if (controllerData.pick.hit) {
@@ -329,7 +334,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
                         }
                         discMesh.isVisible = false;
                     } else {
-                        const scaleFactor = 1 - (timer / timeToSelect);
+                        const scaleFactor = 1 - timer / timeToSelect;
                         discMesh.scaling.set(scaleFactor, scaleFactor, scaleFactor);
                     }
                 } else {
@@ -366,7 +371,9 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
         const controllerData = this._controllers[xrController.uniqueId];
         let downTriggered = false;
         controllerData.onFrameObserver = this._xrSessionManager.onXRFrameObservable.add(() => {
-            if (!controllerData.pick || (this._options.disablePointerUpOnTouchOut && downTriggered)) { return; }
+            if (!controllerData.pick || (this._options.disablePointerUpOnTouchOut && downTriggered)) {
+                return;
+            }
             if (!downTriggered) {
                 this._scene.simulatePointerDown(controllerData.pick, { pointerId: controllerData.id });
                 downTriggered = true;
@@ -418,7 +425,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
                             } else {
                                 this._scene.simulatePointerUp(controllerData.pick, { pointerId: controllerData.id });
                                 (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.selectionMeshDefaultColor;
-                        (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.laserPointerDefaultColor;
+                                (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.laserPointerDefaultColor;
                             }
                         }
                     }
@@ -449,11 +456,11 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
 
             controllerData.eventListeners = {
                 selectend: selectEndListener,
-                selectstart: selectStartListener
+                selectstart: selectStartListener,
             };
 
-            this._xrSessionManager.session.addEventListener('selectstart', selectStartListener);
-            this._xrSessionManager.session.addEventListener('selectend', selectEndListener);
+            this._xrSessionManager.session.addEventListener("selectstart", selectStartListener);
+            this._xrSessionManager.session.addEventListener("selectend", selectEndListener);
         }
     }
 
@@ -469,7 +476,9 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
 
     private _detachController(xrControllerUniqueId: string) {
         const controllerData = this._controllers[xrControllerUniqueId];
-        if (!controllerData) { return; }
+        if (!controllerData) {
+            return;
+        }
         if (controllerData.selectionComponent) {
             if (controllerData.onButtonChangedObserver) {
                 controllerData.selectionComponent.onButtonStateChangedObservable.remove(controllerData.onButtonChangedObserver);
@@ -493,14 +502,18 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
     }
 
     private _generateNewMeshPair(xrController: WebXRInputSource) {
-        const sceneToRenderTo = this._options.useUtilityLayer ? (this._options.customUtilityLayerScene || UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene) : this._scene;
-        const laserPointer = CylinderBuilder.CreateCylinder("laserPointer", {
-            height: 1,
-            diameterTop: 0.0002,
-            diameterBottom: 0.004,
-            tessellation: 20,
-            subdivisions: 1
-        }, sceneToRenderTo);
+        const sceneToRenderTo = this._options.useUtilityLayer ? this._options.customUtilityLayerScene || UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene : this._scene;
+        const laserPointer = CylinderBuilder.CreateCylinder(
+            "laserPointer",
+            {
+                height: 1,
+                diameterTop: 0.0002,
+                diameterBottom: 0.004,
+                tessellation: 20,
+                subdivisions: 1,
+            },
+            sceneToRenderTo
+        );
         laserPointer.parent = xrController.pointer;
         let laserPointerMaterial = new StandardMaterial("laserPointerMat", sceneToRenderTo);
         laserPointerMaterial.emissiveColor = this.laserPointerDefaultColor;
@@ -511,11 +524,15 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
         laserPointer.isPickable = false;
 
         // Create a gaze tracker for the  XR controller
-        const selectionMesh = TorusBuilder.CreateTorus("gazeTracker", {
-            diameter: 0.0035 * 3,
-            thickness: 0.0025 * 3,
-            tessellation: 20
-        }, sceneToRenderTo);
+        const selectionMesh = TorusBuilder.CreateTorus(
+            "gazeTracker",
+            {
+                diameter: 0.0035 * 3,
+                thickness: 0.0025 * 3,
+                tessellation: 20,
+            },
+            sceneToRenderTo
+        );
         selectionMesh.bakeCurrentTransformIntoVertices();
         selectionMesh.isPickable = false;
         selectionMesh.isVisible = false;
@@ -532,20 +549,28 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
 
         return {
             laserPointer,
-            selectionMesh
+            selectionMesh,
         };
     }
 
     private _pickingMoved(oldPick: PickingInfo, newPick: PickingInfo) {
-        if (!oldPick.hit || !newPick.hit) { return true; }
-        if (!oldPick.pickedMesh || !oldPick.pickedPoint || !newPick.pickedMesh || !newPick.pickedPoint) { return true; }
-        if (oldPick.pickedMesh !== newPick.pickedMesh) { return true; }
+        if (!oldPick.hit || !newPick.hit) {
+            return true;
+        }
+        if (!oldPick.pickedMesh || !oldPick.pickedPoint || !newPick.pickedMesh || !newPick.pickedPoint) {
+            return true;
+        }
+        if (oldPick.pickedMesh !== newPick.pickedMesh) {
+            return true;
+        }
         oldPick.pickedPoint?.subtractToRef(newPick.pickedPoint, this._tmpVectorForPickCompare);
         this._tmpVectorForPickCompare.set(Math.abs(this._tmpVectorForPickCompare.x), Math.abs(this._tmpVectorForPickCompare.y), Math.abs(this._tmpVectorForPickCompare.z));
         const delta = (this._options.gazeModePointerMovedFactor || 1) * 0.01 * newPick.distance;
         const length = this._tmpVectorForPickCompare.length();
         console.log(delta, length, newPick.distance);
-        if (length > delta) { return true; }
+        if (length > delta) {
+            return true;
+        }
         return false;
     }
 
@@ -555,7 +580,7 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
         if (this._scene.useRightHandedSystem) {
             distance *= -1;
         }
-        _laserPointer.position.z = (distance / 2) + 0.05;
+        _laserPointer.position.z = distance / 2 + 0.05;
     }
 
     /** @hidden */
@@ -566,6 +591,11 @@ export class WebXRControllerPointerSelection extends WebXRAbstractFeature {
 }
 
 //register the plugin
-WebXRFeaturesManager.AddWebXRFeature(WebXRControllerPointerSelection.Name, (xrSessionManager, options) => {
-    return () => new WebXRControllerPointerSelection(xrSessionManager, options);
-}, WebXRControllerPointerSelection.Version, true);
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRControllerPointerSelection.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRControllerPointerSelection(xrSessionManager, options);
+    },
+    WebXRControllerPointerSelection.Version,
+    true
+);

+ 86 - 67
src/XR/features/WebXRControllerTeleportation.ts

@@ -1,31 +1,31 @@
-import { IWebXRFeature, WebXRFeaturesManager, WebXRFeatureName } from '../webXRFeaturesManager';
-import { Observer } from '../../Misc/observable';
-import { WebXRSessionManager } from '../webXRSessionManager';
-import { Nullable } from '../../types';
-import { WebXRInput } from '../webXRInput';
-import { WebXRInputSource } from '../webXRInputSource';
-import { WebXRControllerComponent, IWebXRMotionControllerAxesValue } from '../motionController/webXRControllerComponent';
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { Vector3, Quaternion } from '../../Maths/math.vector';
-import { Ray } from '../../Culling/ray';
-import { Material } from '../../Materials/material';
-import { DynamicTexture } from '../../Materials/Textures/dynamicTexture';
-import { CylinderBuilder } from '../../Meshes/Builders/cylinderBuilder';
-import { SineEase, EasingFunction } from '../../Animations/easing';
-import { Animation } from '../../Animations/animation';
-import { Axis } from '../../Maths/math.axis';
-import { StandardMaterial } from '../../Materials/standardMaterial';
-import { GroundBuilder } from '../../Meshes/Builders/groundBuilder';
-import { TorusBuilder } from '../../Meshes/Builders/torusBuilder';
-import { PickingInfo } from '../../Collisions/pickingInfo';
-import { Curve3 } from '../../Maths/math.path';
-import { LinesBuilder } from '../../Meshes/Builders/linesBuilder';
-import { WebXRAbstractFeature } from './WebXRAbstractFeature';
-import { Color3 } from '../../Maths/math.color';
-import { Scene } from '../../scene';
-import { UtilityLayerRenderer } from '../../Rendering/utilityLayerRenderer';
-import { PointerEventTypes } from '../../Events/pointerEvents';
-import { setAndStartTimer } from '../../Misc/timer';
+import { IWebXRFeature, WebXRFeaturesManager, WebXRFeatureName } from "../webXRFeaturesManager";
+import { Observer } from "../../Misc/observable";
+import { WebXRSessionManager } from "../webXRSessionManager";
+import { Nullable } from "../../types";
+import { WebXRInput } from "../webXRInput";
+import { WebXRInputSource } from "../webXRInputSource";
+import { WebXRControllerComponent, IWebXRMotionControllerAxesValue } from "../motionController/webXRControllerComponent";
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { Vector3, Quaternion } from "../../Maths/math.vector";
+import { Ray } from "../../Culling/ray";
+import { Material } from "../../Materials/material";
+import { DynamicTexture } from "../../Materials/Textures/dynamicTexture";
+import { CylinderBuilder } from "../../Meshes/Builders/cylinderBuilder";
+import { SineEase, EasingFunction } from "../../Animations/easing";
+import { Animation } from "../../Animations/animation";
+import { Axis } from "../../Maths/math.axis";
+import { StandardMaterial } from "../../Materials/standardMaterial";
+import { GroundBuilder } from "../../Meshes/Builders/groundBuilder";
+import { TorusBuilder } from "../../Meshes/Builders/torusBuilder";
+import { PickingInfo } from "../../Collisions/pickingInfo";
+import { Curve3 } from "../../Maths/math.path";
+import { LinesBuilder } from "../../Meshes/Builders/linesBuilder";
+import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
+import { Color3 } from "../../Maths/math.color";
+import { Scene } from "../../scene";
+import { UtilityLayerRenderer } from "../../Rendering/utilityLayerRenderer";
+import { PointerEventTypes } from "../../Events/pointerEvents";
+import { setAndStartTimer } from "../../Misc/timer";
 
 /**
  * The options container for the teleportation module
@@ -127,7 +127,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
                 currentRotation: number;
                 baseRotation: number;
                 rotating: boolean;
-            }
+            };
             onAxisChangedObserver?: Nullable<Observer<IWebXRMotionControllerAxesValue>>;
             onButtonChangedObserver?: Nullable<Observer<WebXRControllerComponent>>;
         };
@@ -238,7 +238,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
         }
 
         // Safety reset
-        this._currentTeleportationControllerId = '';
+        this._currentTeleportationControllerId = "";
 
         this._options.xrInput.controllers.forEach(this._attachController);
         this._addNewAttachObserver(this._options.xrInput.onControllerAddedObservable, this._attachController);
@@ -260,7 +260,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
         });
 
         this._setTargetMeshVisibility(false);
-        this._currentTeleportationControllerId = '';
+        this._currentTeleportationControllerId = "";
 
         return true;
     }
@@ -331,7 +331,9 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
     protected _onXRFrame(_xrFrame: XRFrame) {
         const frame = this._xrSessionManager.currentFrame;
         const scene = this._xrSessionManager.scene;
-        if (!this.attach || !frame) { return; }
+        if (!this.attach || !frame) {
+            return;
+        }
 
         // render target if needed
         const targetMesh = this._options.teleportationTargetMesh;
@@ -352,8 +354,10 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
                 // pick grounds that are LOWER only. upper will use parabolic path
                 let pick = scene.pickWithRay(this._tmpRay, (o) => {
                     const index = this._floorMeshes.indexOf(o);
-                    if (index === -1) { return false; }
-                    return (this._floorMeshes[index].absolutePosition.y < this._options.xrInput.xrCamera.position.y);
+                    if (index === -1) {
+                        return false;
+                    }
+                    return this._floorMeshes[index].absolutePosition.y < this._options.xrInput.xrCamera.position.y;
                 });
                 if (pick && pick.pickedPoint) {
                     hitPossible = true;
@@ -364,7 +368,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
                     if (this.parabolicRayEnabled) {
                         // radius compensation according to pointer rotation around X
                         const xRotation = controllerData.xrController.pointer.rotationQuaternion!.toEulerAngles().x;
-                        const compensation = (1 + ((Math.PI / 2) - Math.abs(xRotation)));
+                        const compensation = 1 + (Math.PI / 2 - Math.abs(xRotation));
                         // check parabolic ray
                         const radius = this.parabolicCheckRadius * compensation;
                         this._tmpRay.origin.addToRef(this._tmpRay.direction.scale(radius * 2), this._tmpVector);
@@ -407,18 +411,17 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
                 backwards: false,
                 rotating: false,
                 currentRotation: 0,
-                baseRotation: 0
-            }
+                baseRotation: 0,
+            },
         };
         const controllerData = this._controllers[xrController.uniqueId];
         // motion controller only available to gamepad-enabled input sources.
-        if (controllerData.xrController.inputSource.targetRayMode === 'tracked-pointer'
-            && controllerData.xrController.inputSource.gamepad) {
+        if (controllerData.xrController.inputSource.targetRayMode === "tracked-pointer" && controllerData.xrController.inputSource.gamepad) {
             // motion controller support
             xrController.onMotionControllerInitObservable.addOnce(() => {
                 if (xrController.motionController) {
                     const movementController = xrController.motionController.getComponentOfType(WebXRControllerComponent.THUMBSTICK_TYPE) || xrController.motionController.getComponentOfType(WebXRControllerComponent.TOUCHPAD_TYPE);
-                if (!movementController || this._options.useMainComponentOnly) {
+                    if (!movementController || this._options.useMainComponentOnly) {
                         // use trigger to move on long press
                         const mainComponent = xrController.motionController.getMainComponent();
                         if (!mainComponent) {
@@ -442,7 +445,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
                                             if (this._currentTeleportationControllerId === controllerData.xrController.uniqueId && controllerData.teleportationState.forward) {
                                                 this._teleportForward(xrController.uniqueId);
                                             }
-                                        }
+                                        },
                                     });
                                 } else {
                                     controllerData.teleportationState.forward = false;
@@ -517,7 +520,6 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
                 }
             });
         } else {
-
             this._xrSessionManager.scene.onPointerObservable.add((pointerInfo) => {
                 if (pointerInfo.type === PointerEventTypes.POINTERDOWN) {
                     controllerData.teleportationState.forward = true;
@@ -532,7 +534,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
                             if (this._currentTeleportationControllerId === controllerData.xrController.uniqueId && controllerData.teleportationState.forward) {
                                 this._teleportForward(xrController.uniqueId);
                             }
-                        }
+                        },
                     });
                 } else if (pointerInfo.type === PointerEventTypes.POINTERUP) {
                     controllerData.teleportationState.forward = false;
@@ -540,12 +542,12 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
                 }
             });
         }
-    }
+    };
 
     private _createDefaultTargetMesh() {
         // set defaults
         this._options.defaultTargetMeshOptions = this._options.defaultTargetMeshOptions || {};
-        const sceneToRenderTo = this._options.useUtilityLayer ? (this._options.customUtilityLayerScene || UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene) : this._xrSessionManager.scene;
+        const sceneToRenderTo = this._options.useUtilityLayer ? this._options.customUtilityLayerScene || UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene : this._xrSessionManager.scene;
         let teleportationTarget = GroundBuilder.CreateGround("teleportationTarget", { width: 2, height: 2, subdivisions: 2 }, sceneToRenderTo);
         teleportationTarget.isPickable = false;
         let length = 512;
@@ -567,11 +569,15 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
         const teleportationCircleMaterial = new StandardMaterial("teleportationPlaneMaterial", sceneToRenderTo);
         teleportationCircleMaterial.diffuseTexture = dynamicTexture;
         teleportationTarget.material = teleportationCircleMaterial;
-        let torus = TorusBuilder.CreateTorus("torusTeleportation", {
-            diameter: 0.75,
-            thickness: 0.1,
-            tessellation: 20
-        }, sceneToRenderTo);
+        let torus = TorusBuilder.CreateTorus(
+            "torusTeleportation",
+            {
+                diameter: 0.75,
+                thickness: 0.1,
+                tessellation: 20,
+            },
+            sceneToRenderTo
+        );
         torus.isPickable = false;
         torus.parent = teleportationTarget;
         if (!this._options.defaultTargetMeshOptions.disableAnimation) {
@@ -579,15 +585,15 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
             let keys = [];
             keys.push({
                 frame: 0,
-                value: 0
+                value: 0,
             });
             keys.push({
                 frame: 30,
-                value: 0.4
+                value: 0.4,
             });
             keys.push({
                 frame: 60,
-                value: 0
+                value: 0,
             });
             animationInnerCircle.setKeys(keys);
             let easingFunction = new SineEase();
@@ -635,7 +641,9 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
 
     private _detachController(xrControllerUniqueId: string) {
         const controllerData = this._controllers[xrControllerUniqueId];
-        if (!controllerData) { return; }
+        if (!controllerData) {
+            return;
+        }
         if (controllerData.teleportationComponent) {
             if (controllerData.onAxisChangedObserver) {
                 controllerData.teleportationComponent.onAxisValueChangedObservable.remove(controllerData.onAxisChangedObserver);
@@ -665,7 +673,9 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
     }
 
     private _setTargetMeshPosition(newPosition: Vector3) {
-        if (!this._options.teleportationTargetMesh) { return; }
+        if (!this._options.teleportationTargetMesh) {
+            return;
+        }
         const snapPosition = this._findClosestSnapPointWithRadius(newPosition);
         this._snappedToPoint = !!snapPosition;
         if (this.snapPointsOnly && !this._snappedToPoint && this._teleportationRingMaterial) {
@@ -678,10 +688,16 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
     }
 
     private _setTargetMeshVisibility(visible: boolean) {
-        if (!this._options.teleportationTargetMesh) { return; }
-        if (this._options.teleportationTargetMesh.isVisible === visible) { return; }
+        if (!this._options.teleportationTargetMesh) {
+            return;
+        }
+        if (this._options.teleportationTargetMesh.isVisible === visible) {
+            return;
+        }
         this._options.teleportationTargetMesh.isVisible = visible;
-        this._options.teleportationTargetMesh.getChildren(undefined, false).forEach((m) => { (<any>(m)).isVisible = visible; });
+        this._options.teleportationTargetMesh.getChildren(undefined, false).forEach((m) => {
+            (<any>m).isVisible = visible;
+        });
 
         if (!visible) {
             if (this._quadraticBezierCurve) {
@@ -698,15 +714,13 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
     }
 
     private _showParabolicPath(pickInfo: PickingInfo) {
-        if (!pickInfo.pickedPoint) { return; }
+        if (!pickInfo.pickedPoint) {
+            return;
+        }
 
         const controllerData = this._controllers[this._currentTeleportationControllerId];
 
-        const quadraticBezierVectors = Curve3.CreateQuadraticBezier(
-            controllerData.xrController.pointer.absolutePosition,
-            pickInfo.ray!.origin,
-            pickInfo.pickedPoint,
-            25);
+        const quadraticBezierVectors = Curve3.CreateQuadraticBezier(controllerData.xrController.pointer.absolutePosition, pickInfo.ray!.origin, pickInfo.pickedPoint, 25);
 
         if (this._quadraticBezierCurve) {
             this._quadraticBezierCurve.dispose();
@@ -736,6 +750,11 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
     }
 }
 
-WebXRFeaturesManager.AddWebXRFeature(WebXRMotionControllerTeleportation.Name, (xrSessionManager, options) => {
-    return () => new WebXRMotionControllerTeleportation(xrSessionManager, options);
-}, WebXRMotionControllerTeleportation.Version, true);
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRMotionControllerTeleportation.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRMotionControllerTeleportation(xrSessionManager, options);
+    },
+    WebXRMotionControllerTeleportation.Version,
+    true
+);

+ 34 - 25
src/XR/features/WebXRHitTest.ts

@@ -1,11 +1,11 @@
-import { WebXRFeaturesManager, WebXRFeatureName } from '../webXRFeaturesManager';
-import { WebXRSessionManager } from '../webXRSessionManager';
-import { Observable } from '../../Misc/observable';
-import { Vector3, Matrix, Quaternion } from '../../Maths/math.vector';
-import { WebXRAbstractFeature } from './WebXRAbstractFeature';
-import { IWebXRLegacyHitTestOptions, IWebXRLegacyHitResult, IWebXRHitTestFeature } from './WebXRHitTestLegacy';
-import { Tools } from '../../Misc/tools';
-import { Nullable } from '../../types';
+import { WebXRFeaturesManager, WebXRFeatureName } from "../webXRFeaturesManager";
+import { WebXRSessionManager } from "../webXRSessionManager";
+import { Observable } from "../../Misc/observable";
+import { Vector3, Matrix, Quaternion } from "../../Maths/math.vector";
+import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
+import { IWebXRLegacyHitTestOptions, IWebXRLegacyHitResult, IWebXRHitTestFeature } from "./WebXRHitTestLegacy";
+import { Tools } from "../../Misc/tools";
+import { Nullable } from "../../types";
 
 /**
  * Options used for hit testing (version 2)
@@ -82,10 +82,10 @@ export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestF
         const offsetRay = new XRRay(this.options.offsetRay || {});
         const options: XRHitTestOptionsInit = {
             space: this.options.useReferenceSpace ? referenceSpace : this._xrSessionManager.viewerReferenceSpace,
-            offsetRay: offsetRay
+            offsetRay: offsetRay,
         };
         if (!options.space) {
-            Tools.Warn('waiting for viewer reference space to initialize');
+            Tools.Warn("waiting for viewer reference space to initialize");
             return;
         }
         this._xrSessionManager.session.requestHitTestSource(options).then((hitTestSource) => {
@@ -94,7 +94,7 @@ export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestF
             }
             this._xrHitTestSource = hitTestSource;
         });
-    }
+    };
 
     /**
      * The module's name
@@ -127,13 +127,15 @@ export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestF
      * @param _xrSessionManager an instance of WebXRSessionManager
      * @param options options to use when constructing this feature
      */
-    constructor(_xrSessionManager: WebXRSessionManager,
+    constructor(
+        _xrSessionManager: WebXRSessionManager,
         /**
          * options to use when constructing this feature
          */
-        public readonly options: IWebXRHitTestOptions = {}) {
+        public readonly options: IWebXRHitTestOptions = {}
+    ) {
         super(_xrSessionManager);
-        Tools.Warn('Hit test is an experimental and unstable feature. make sure you enable optionalFeatures when creating the XR session');
+        Tools.Warn("Hit test is an experimental and unstable feature. make sure you enable optionalFeatures when creating the XR session");
     }
 
     /**
@@ -155,12 +157,14 @@ export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestF
         }
         if (this.options.enableTransientHitTest) {
             const offsetRay = new XRRay(this.options.transientOffsetRay || {});
-            this._xrSessionManager.session.requestHitTestSourceForTransientInput({
-                profile : 'generic-touchscreen',
-                offsetRay
-            }).then((hitSource) => {
-                this._transientXrHitTestSource = hitSource;
-            });
+            this._xrSessionManager.session
+                .requestHitTestSourceForTransientInput({
+                    profile: "generic-touchscreen",
+                    offsetRay,
+                })
+                .then((hitSource) => {
+                    this._transientXrHitTestSource = hitSource;
+                });
         }
 
         return true;
@@ -220,7 +224,7 @@ export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestF
     }
 
     private _processWebXRHitTestResult(hitTestResults: XRHitTestResult[], inputSource?: XRInputSource) {
-        const results : IWebXRHitResult[] = [];
+        const results: IWebXRHitResult[] = [];
         hitTestResults.forEach((hitTestResult) => {
             const pose = hitTestResult.getPose(this._xrSessionManager.referenceSpace);
             if (!pose) {
@@ -244,7 +248,7 @@ export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestF
                 transformationMatrix: this.autoCloneTransformation ? this._tmpMat.clone() : this._tmpMat,
                 inputSource: inputSource,
                 isTransient: !!inputSource,
-                xrHitResult: hitTestResult
+                xrHitResult: hitTestResult,
             };
             results.push(result);
         });
@@ -256,6 +260,11 @@ export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestF
 }
 
 //register the plugin versions
-WebXRFeaturesManager.AddWebXRFeature(WebXRHitTest.Name, (xrSessionManager, options) => {
-    return () => new WebXRHitTest(xrSessionManager, options);
-}, WebXRHitTest.Version, false);
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRHitTest.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRHitTest(xrSessionManager, options);
+    },
+    WebXRHitTest.Version,
+    false
+);

+ 25 - 19
src/XR/features/WebXRHitTestLegacy.ts

@@ -1,9 +1,9 @@
-import { WebXRFeaturesManager, WebXRFeatureName, IWebXRFeature } from '../webXRFeaturesManager';
-import { WebXRSessionManager } from '../webXRSessionManager';
-import { Observable } from '../../Misc/observable';
-import { Vector3, Matrix } from '../../Maths/math.vector';
-import { TransformNode } from '../../Meshes/transformNode';
-import { WebXRAbstractFeature } from './WebXRAbstractFeature';
+import { WebXRFeaturesManager, WebXRFeatureName, IWebXRFeature } from "../webXRFeaturesManager";
+import { WebXRSessionManager } from "../webXRSessionManager";
+import { Observable } from "../../Misc/observable";
+import { Vector3, Matrix } from "../../Maths/math.vector";
+import { TransformNode } from "../../Meshes/transformNode";
+import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
 
 // the plugin is registered at the end of the file
 
@@ -50,7 +50,7 @@ export interface IWebXRLegacyHitResult {
  * Hit test (or Ray-casting) is used to interact with the real world.
  * For further information read here - https://github.com/immersive-web/hit-test
  */
-export class WebXRHitTestLegacy extends WebXRAbstractFeature  implements IWebXRHitTestFeature<IWebXRLegacyHitResult> {
+export class WebXRHitTestLegacy extends WebXRAbstractFeature implements IWebXRHitTestFeature<IWebXRLegacyHitResult> {
     // in XR space z-forward is negative
     private _direction = new Vector3(0, 0, -1);
     private _mat = new Matrix();
@@ -82,11 +82,13 @@ export class WebXRHitTestLegacy extends WebXRAbstractFeature  implements IWebXRH
      * @param _xrSessionManager an instance of WebXRSessionManager
      * @param options options to use when constructing this feature
      */
-    constructor(_xrSessionManager: WebXRSessionManager,
+    constructor(
+        _xrSessionManager: WebXRSessionManager,
         /**
          * options to use when constructing this feature
          */
-        public readonly options: IWebXRLegacyHitTestOptions = {}) {
+        public readonly options: IWebXRLegacyHitTestOptions = {}
+    ) {
         super(_xrSessionManager);
     }
 
@@ -133,7 +135,7 @@ export class WebXRHitTestLegacy extends WebXRAbstractFeature  implements IWebXRH
             return false;
         }
         if (this.options.testOnPointerDownOnly) {
-            this._xrSessionManager.session.addEventListener('select', this._onSelect, false);
+            this._xrSessionManager.session.addEventListener("select", this._onSelect, false);
         }
 
         return true;
@@ -151,7 +153,7 @@ export class WebXRHitTestLegacy extends WebXRAbstractFeature  implements IWebXRH
         }
         // disable select
         this._onSelectEnabled = false;
-        this._xrSessionManager.session.removeEventListener('select', this._onSelect);
+        this._xrSessionManager.session.removeEventListener("select", this._onSelect);
         return true;
     }
 
@@ -177,8 +179,7 @@ export class WebXRHitTestLegacy extends WebXRAbstractFeature  implements IWebXRH
         Vector3.TransformCoordinatesFromFloatsToRef(0, 0, -1, this._mat, this._direction);
         this._direction.subtractInPlace(this._origin);
         this._direction.normalize();
-        let ray = new XRRay((<DOMPointReadOnly>{ x: this._origin.x, y: this._origin.y, z: this._origin.z, w: 0 }),
-            (<DOMPointReadOnly>{ x: this._direction.x, y: this._direction.y, z: this._direction.z, w: 0 }));
+        let ray = new XRRay(<DOMPointReadOnly>{ x: this._origin.x, y: this._origin.y, z: this._origin.z, w: 0 }, <DOMPointReadOnly>{ x: this._direction.x, y: this._direction.y, z: this._direction.z, w: 0 });
         WebXRHitTestLegacy.XRHitTestWithRay(this._xrSessionManager.session, ray, this._xrSessionManager.referenceSpace).then(this._onHitTestResults);
     }
 
@@ -194,13 +195,13 @@ export class WebXRHitTestLegacy extends WebXRAbstractFeature  implements IWebXRH
             }
             return {
                 xrHitResult: result,
-                transformationMatrix: mat
+                transformationMatrix: mat,
             };
         });
 
         this.lastNativeXRHitResults = xrResults;
         this.onHitTestResultObservable.notifyObservers(mats);
-    }
+    };
 
     // can be done using pointerdown event, and xrSessionManager.currentFrame
     private _onSelect = (event: XRInputSourceEvent) => {
@@ -208,10 +209,15 @@ export class WebXRHitTestLegacy extends WebXRAbstractFeature  implements IWebXRH
             return;
         }
         WebXRHitTestLegacy.XRHitTestWithSelectEvent(event, this._xrSessionManager.referenceSpace);
-    }
+    };
 }
 
 //register the plugin versions
-WebXRFeaturesManager.AddWebXRFeature(WebXRHitTestLegacy.Name, (xrSessionManager, options) => {
-    return () => new WebXRHitTestLegacy(xrSessionManager, options);
-}, WebXRHitTestLegacy.Version, false);
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRHitTestLegacy.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRHitTestLegacy(xrSessionManager, options);
+    },
+    WebXRHitTestLegacy.Version,
+    false
+);

+ 22 - 14
src/XR/features/WebXRPlaneDetector.ts

@@ -1,9 +1,9 @@
-import { WebXRFeaturesManager, WebXRFeatureName } from '../webXRFeaturesManager';
-import { TransformNode } from '../../Meshes/transformNode';
-import { WebXRSessionManager } from '../webXRSessionManager';
-import { Observable } from '../../Misc/observable';
-import { Vector3, Matrix } from '../../Maths/math.vector';
-import { WebXRAbstractFeature } from './WebXRAbstractFeature';
+import { WebXRFeaturesManager, WebXRFeatureName } from "../webXRFeaturesManager";
+import { TransformNode } from "../../Meshes/transformNode";
+import { WebXRSessionManager } from "../webXRSessionManager";
+import { Observable } from "../../Misc/observable";
+import { Vector3, Matrix } from "../../Maths/math.vector";
+import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
 
 /**
  * Options used in the plane detector module
@@ -133,14 +133,18 @@ export class WebXRPlaneDetector extends WebXRAbstractFeature {
     }
 
     protected _onXRFrame(frame: XRFrame) {
-        if (!this.attached || !this._enabled || !frame) { return; }
+        if (!this.attached || !this._enabled || !frame) {
+            return;
+        }
         // const timestamp = this.xrSessionManager.currentTimestamp;
 
         const detectedPlanes = frame.worldInformation.detectedPlanes;
         if (detectedPlanes) {
-            const toRemove = this._detectedPlanes.filter((plane) => !detectedPlanes.has(plane.xrPlane)).map((plane) => {
-                return this._detectedPlanes.indexOf(plane);
-            });
+            const toRemove = this._detectedPlanes
+                .filter((plane) => !detectedPlanes.has(plane.xrPlane))
+                .map((plane) => {
+                    return this._detectedPlanes.indexOf(plane);
+                });
             let idxTracker = 0;
             toRemove.forEach((index) => {
                 const plane = this._detectedPlanes.splice(index - idxTracker, 1)[0];
@@ -153,7 +157,7 @@ export class WebXRPlaneDetector extends WebXRAbstractFeature {
                     const newPlane: Partial<IWebXRPlane> = {
                         id: planeIdProvider++,
                         xrPlane: xrPlane,
-                        polygonDefinition: []
+                        polygonDefinition: [],
                     };
                     const plane = this._updatePlaneWithXRPlane(xrPlane, newPlane, frame);
                     this._detectedPlanes.push(plane);
@@ -220,6 +224,10 @@ export class WebXRPlaneDetector extends WebXRAbstractFeature {
 }
 
 //register the plugin
-WebXRFeaturesManager.AddWebXRFeature(WebXRPlaneDetector.Name, (xrSessionManager, options) => {
-    return () => new WebXRPlaneDetector(xrSessionManager, options);
-}, WebXRPlaneDetector.Version);
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRPlaneDetector.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRPlaneDetector(xrSessionManager, options);
+    },
+    WebXRPlaneDetector.Version
+);

+ 2 - 2
src/XR/features/index.ts

@@ -4,5 +4,5 @@ export * from "./WebXRPlaneDetector";
 export * from "./WebXRBackgroundRemover";
 export * from "./WebXRControllerTeleportation";
 export * from "./WebXRControllerPointerSelection";
-export * from './WebXRControllerPhysics';
-export * from './WebXRHitTest';
+export * from "./WebXRControllerPhysics";
+export * from "./WebXRHitTest";

+ 1 - 1
src/XR/index.ts

@@ -9,4 +9,4 @@ export * from "./webXRSessionManager";
 export * from "./webXRDefaultExperience";
 export * from "./webXRFeaturesManager";
 export * from "./features/index";
-export * from "./motionController/index";
+export * from "./motionController/index";

+ 1 - 1
src/XR/motionController/index.ts

@@ -5,4 +5,4 @@ export * from "./webXRMicrosoftMixedRealityController";
 export * from "./webXRMotionControllerManager";
 export * from "./webXROculusTouchMotionController";
 export * from "./webXRHTCViveMotionController";
-export * from "./webXRProfiledMotionController";
+export * from "./webXRProfiledMotionController";

+ 56 - 49
src/XR/motionController/webXRAbstractMotionController.ts

@@ -1,12 +1,12 @@
-import { IDisposable, Scene } from '../../scene';
-import { WebXRControllerComponent } from './webXRControllerComponent';
-import { Observable } from '../../Misc/observable';
-import { Logger } from '../../Misc/logger';
-import { SceneLoader } from '../../Loading/sceneLoader';
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { Nullable } from '../../types';
-import { Quaternion, Vector3 } from '../../Maths/math.vector';
-import { Mesh } from '../../Meshes/mesh';
+import { IDisposable, Scene } from "../../scene";
+import { WebXRControllerComponent } from "./webXRControllerComponent";
+import { Observable } from "../../Misc/observable";
+import { Logger } from "../../Misc/logger";
+import { SceneLoader } from "../../Loading/sceneLoader";
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { Nullable } from "../../types";
+import { Quaternion, Vector3 } from "../../Maths/math.vector";
+import { Mesh } from "../../Meshes/mesh";
 
 /**
  * Handedness type in xrInput profiles. These can be used to define layouts in the Layout Map.
@@ -95,13 +95,13 @@ export interface IMotionControllerLayout {
                      * Max movement node
                      */
                     maxNodeName?: string;
-                }
-            }
+                };
+            };
             /**
              * If touch enabled, what is the name of node to display user feedback
              */
             touchPointNodeName?: string;
-        }
+        };
     };
     /**
      * Is it xr standard mapping or not
@@ -202,8 +202,8 @@ export interface IMinimalMotionControllerObject {
      */
     buttons: Array<{
         /**
-        * Value of the button/trigger
-        */
+         * Value of the button/trigger
+         */
         value: number;
         /**
          * If the button/trigger is currently touched
@@ -219,7 +219,7 @@ export interface IMinimalMotionControllerObject {
      * EXPERIMENTAL haptic support.
      */
     hapticActuators?: Array<{
-        pulse: (value: number, duration: number) => Promise<boolean>
+        pulse: (value: number, duration: number) => Promise<boolean>;
     }>;
 }
 
@@ -230,7 +230,9 @@ export interface IMinimalMotionControllerObject {
  */
 export abstract class WebXRAbstractMotionController implements IDisposable {
     private _initComponent = (id: string) => {
-        if (!id) { return; }
+        if (!id) {
+            return;
+        }
         const componentDef = this.layout.components[id];
         const type = componentDef.type;
         const buttonIndex = componentDef.gamepadIndices.button;
@@ -241,7 +243,7 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
         }
 
         this.components[id] = new WebXRControllerComponent(id, type, buttonIndex, axes);
-    }
+    };
 
     private _modelReady: boolean = false;
 
@@ -250,7 +252,7 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
      * Components have a ComponentType and can also have both button and axis definitions
      */
     public readonly components: {
-        [id: string]: WebXRControllerComponent
+        [id: string]: WebXRControllerComponent;
     } = {};
 
     /**
@@ -278,7 +280,9 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
      * @param handedness handedness (left/right/none) of this controller
      * @param _doNotLoadControllerMesh set this flag to ignore the mesh loading
      */
-    constructor(protected scene: Scene, protected layout: IMotionControllerLayout,
+    constructor(
+        protected scene: Scene,
+        protected layout: IMotionControllerLayout,
         /**
          * The gamepad object correlating to this controller
          */
@@ -287,7 +291,8 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
          * handedness (left/right/none) of this controller
          */
         public handedness: MotionControllerHandedness,
-        _doNotLoadControllerMesh: boolean = false) {
+        _doNotLoadControllerMesh: boolean = false
+    ) {
         // initialize the components
         if (layout.components) {
             Object.keys(layout.components).forEach(this._initComponent);
@@ -311,7 +316,9 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
      * @return an array of components with this type
      */
     public getAllComponentsOfType(type: MotionControllerComponentType): WebXRControllerComponent[] {
-        return this.getComponentIds().map((id) => this.components[id]).filter((component) => component.type === type);
+        return this.getComponentIds()
+            .map((id) => this.components[id])
+            .filter((component) => component.type === type);
     }
 
     /**
@@ -363,21 +370,29 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
             loadingParams = this._getFilenameAndPath();
         }
         return new Promise((resolve, reject) => {
-            SceneLoader.ImportMesh("", loadingParams.path, loadingParams.filename, this.scene, (meshes: AbstractMesh[]) => {
-                if (useGeneric) {
-                    this._getGenericParentMesh(meshes);
-                } else {
-                    this._setRootMesh(meshes);
+            SceneLoader.ImportMesh(
+                "",
+                loadingParams.path,
+                loadingParams.filename,
+                this.scene,
+                (meshes: AbstractMesh[]) => {
+                    if (useGeneric) {
+                        this._getGenericParentMesh(meshes);
+                    } else {
+                        this._setRootMesh(meshes);
+                    }
+                    this._processLoadedModel(meshes);
+                    this._modelReady = true;
+                    this.onModelLoadedObservable.notifyObservers(this);
+                    resolve(true);
+                },
+                null,
+                (_scene: Scene, message: string) => {
+                    Logger.Log(message);
+                    Logger.Warn(`Failed to retrieve controller model of type ${this.profileId} from the remote server: ${loadingParams.path}${loadingParams.filename}`);
+                    reject(message);
                 }
-                this._processLoadedModel(meshes);
-                this._modelReady = true;
-                this.onModelLoadedObservable.notifyObservers(this);
-                resolve(true);
-            }, null, (_scene: Scene, message: string) => {
-                Logger.Log(message);
-                Logger.Warn(`Failed to retrieve controller model of type ${this.profileId} from the remote server: ${loadingParams.path}${loadingParams.filename}`);
-                reject(message);
-            });
+            );
         });
     }
 
@@ -442,16 +457,8 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
 
         // Convert from gamepad value range (-1 to +1) to lerp range (0 to 1)
         let lerpValue = fixValueCoordinates ? axisValue * 0.5 + 0.5 : axisValue;
-        Quaternion.SlerpToRef(
-            axisMap.minMesh.rotationQuaternion,
-            axisMap.maxMesh.rotationQuaternion,
-            lerpValue,
-            axisMap.valueMesh.rotationQuaternion);
-        Vector3.LerpToRef(
-            axisMap.minMesh.position,
-            axisMap.maxMesh.position,
-            lerpValue,
-            axisMap.valueMesh.position);
+        Quaternion.SlerpToRef(axisMap.minMesh.rotationQuaternion, axisMap.maxMesh.rotationQuaternion, lerpValue, axisMap.valueMesh.rotationQuaternion);
+        Vector3.LerpToRef(axisMap.minMesh.position, axisMap.maxMesh.position, lerpValue, axisMap.valueMesh.position);
     }
 
     /**
@@ -469,7 +476,7 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
      * Get the filename and path for this controller's model
      * @returns a map of filename and path
      */
-    protected abstract _getFilenameAndPath(): { filename: string, path: string };
+    protected abstract _getFilenameAndPath(): { filename: string; path: string };
     /**
      * This function is called before the mesh is loaded. It checks for loading constraints.
      * For example, this function can check if the GLB loader is available
@@ -494,10 +501,10 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
      */
     protected abstract _updateModel(xrFrame: XRFrame): void;
 
-    private _getGenericFilenameAndPath(): { filename: string, path: string } {
+    private _getGenericFilenameAndPath(): { filename: string; path: string } {
         return {
             filename: "generic.babylon",
-            path: "https://controllers.babylonjs.com/generic/"
+            path: "https://controllers.babylonjs.com/generic/",
         };
     }
 
@@ -513,4 +520,4 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
 
         this.rootMesh.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);
     }
-}
+}

+ 16 - 16
src/XR/motionController/webXRControllerComponent.ts

@@ -1,6 +1,6 @@
 import { IMinimalMotionControllerObject, MotionControllerComponentType } from "./webXRAbstractMotionController";
-import { Observable } from '../../Misc/observable';
-import { IDisposable } from '../../scene';
+import { Observable } from "../../Misc/observable";
+import { IDisposable } from "../../scene";
 
 /**
  * X-Y values for axes in WebXR
@@ -57,7 +57,7 @@ export interface IWebXRMotionControllerComponentChanges {
 export class WebXRControllerComponent implements IDisposable {
     private _axes: IWebXRMotionControllerAxesValue = {
         x: 0,
-        y: 0
+        y: 0,
     };
     private _changes: IWebXRMotionControllerComponentChanges = {};
     private _currentValue: number = 0;
@@ -90,7 +90,7 @@ export class WebXRControllerComponent implements IDisposable {
      * If axes are available for this component (like a touchpad or thumbstick) the observers will be notified when
      * the axes data changes
      */
-    public onAxisValueChangedObservable: Observable<{ x: number, y: number }> = new Observable();
+    public onAxisValueChangedObservable: Observable<{ x: number; y: number }> = new Observable();
     /**
      * Observers registered here will be triggered when the state of a button changes
      * State change is either pressed / touched / value
@@ -116,8 +116,8 @@ export class WebXRControllerComponent implements IDisposable {
          */
         public type: MotionControllerComponentType,
         private _buttonIndex: number = -1,
-        private _axesIndices: number[] = []) {
-    }
+        private _axesIndices: number[] = []
+    ) {}
 
     /**
      * The current axes data. If this component has no axes it will still return an object { x: 0, y: 0 }
@@ -204,7 +204,7 @@ export class WebXRControllerComponent implements IDisposable {
             if (this._currentValue !== button.value) {
                 this.changes.value = {
                     current: button.value,
-                    previous: this._currentValue
+                    previous: this._currentValue,
                 };
                 buttonUpdated = true;
                 this._currentValue = button.value;
@@ -212,7 +212,7 @@ export class WebXRControllerComponent implements IDisposable {
             if (this._touched !== button.touched) {
                 this.changes.touched = {
                     current: button.touched,
-                    previous: this._touched
+                    previous: this._touched,
                 };
                 buttonUpdated = true;
                 this._touched = button.touched;
@@ -220,7 +220,7 @@ export class WebXRControllerComponent implements IDisposable {
             if (this._pressed !== button.pressed) {
                 this.changes.pressed = {
                     current: button.pressed,
-                    previous: this._pressed
+                    previous: this._pressed,
                 };
                 buttonUpdated = true;
                 this._pressed = button.pressed;
@@ -232,12 +232,12 @@ export class WebXRControllerComponent implements IDisposable {
                 this.changes.axes = {
                     current: {
                         x: nativeController.axes[this._axesIndices[0]],
-                        y: this._axes.y
+                        y: this._axes.y,
                     },
                     previous: {
                         x: this._axes.x,
-                        y: this._axes.y
-                    }
+                        y: this._axes.y,
+                    },
                 };
                 this._axes.x = nativeController.axes[this._axesIndices[0]];
                 axesUpdate = true;
@@ -250,12 +250,12 @@ export class WebXRControllerComponent implements IDisposable {
                     this.changes.axes = {
                         current: {
                             x: this._axes.x,
-                            y: nativeController.axes[this._axesIndices[1]]
+                            y: nativeController.axes[this._axesIndices[1]],
                         },
                         previous: {
                             x: this._axes.x,
-                            y: this._axes.y
-                        }
+                            y: this._axes.y,
+                        },
                     };
                 }
                 this._axes.y = nativeController.axes[this._axesIndices[1]];
@@ -272,4 +272,4 @@ export class WebXRControllerComponent implements IDisposable {
             this.onAxisValueChangedObservable.notifyObservers(this._axes);
         }
     }
-}
+}

+ 45 - 50
src/XR/motionController/webXRGenericMotionController.ts

@@ -1,13 +1,8 @@
-import {
-    WebXRAbstractMotionController,
-    IMinimalMotionControllerObject,
-    MotionControllerHandedness,
-    IMotionControllerLayoutMap
-} from "./webXRAbstractMotionController";
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { Scene } from '../../scene';
-import { Mesh } from '../../Meshes/mesh';
-import { Quaternion } from '../../Maths/math.vector';
+import { WebXRAbstractMotionController, IMinimalMotionControllerObject, MotionControllerHandedness, IMotionControllerLayoutMap } from "./webXRAbstractMotionController";
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { Scene } from "../../scene";
+import { Mesh } from "../../Meshes/mesh";
+import { Quaternion } from "../../Maths/math.vector";
 
 /**
  * A generic trigger-only motion controller for WebXR
@@ -24,10 +19,10 @@ export class WebXRGenericTriggerMotionController extends WebXRAbstractMotionCont
         super(scene, GenericTriggerLayout[handedness], gamepadObject, handedness);
     }
 
-    protected _getFilenameAndPath(): { filename: string; path: string; } {
+    protected _getFilenameAndPath(): { filename: string; path: string } {
         return {
             filename: "generic.babylon",
-            path: "https://controllers.babylonjs.com/generic/"
+            path: "https://controllers.babylonjs.com/generic/",
         };
     }
 
@@ -59,52 +54,52 @@ export class WebXRGenericTriggerMotionController extends WebXRAbstractMotionCont
 
 // https://github.com/immersive-web/webxr-input-profiles/blob/master/packages/registry/profiles/generic/generic-trigger-touchpad-thumbstick.json
 const GenericTriggerLayout: IMotionControllerLayoutMap = {
-    "left": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    left: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {}
-            }
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {},
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "generic-trigger-left",
-        "assetPath": "left.glb"
+        gamepadMapping: "xr-standard",
+        rootNodeName: "generic-trigger-left",
+        assetPath: "left.glb",
     },
-    "right": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    right: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {}
-            }
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {},
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "generic-trigger-right",
-        "assetPath": "right.glb"
+        gamepadMapping: "xr-standard",
+        rootNodeName: "generic-trigger-right",
+        assetPath: "right.glb",
     },
-    "none": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    none: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {}
-            }
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {},
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "generic-trigger-none",
-        "assetPath": "none.glb"
-    }
-};
+        gamepadMapping: "xr-standard",
+        rootNodeName: "generic-trigger-none",
+        assetPath: "none.glb",
+    },
+};

+ 124 - 135
src/XR/motionController/webXRHTCViveMotionController.ts

@@ -1,14 +1,9 @@
-import {
-    IMotionControllerLayoutMap,
-    IMinimalMotionControllerObject,
-    MotionControllerHandedness,
-    WebXRAbstractMotionController
-} from "./webXRAbstractMotionController";
-import { Scene } from '../../scene';
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { Mesh } from '../../Meshes/mesh';
-import { Quaternion } from '../../Maths/math.vector';
-import { WebXRMotionControllerManager } from './webXRMotionControllerManager';
+import { IMotionControllerLayoutMap, IMinimalMotionControllerObject, MotionControllerHandedness, WebXRAbstractMotionController } from "./webXRAbstractMotionController";
+import { Scene } from "../../scene";
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { Mesh } from "../../Meshes/mesh";
+import { Quaternion } from "../../Maths/math.vector";
+import { WebXRMotionControllerManager } from "./webXRMotionControllerManager";
 
 /**
  * The motion controller class for the standard HTC-Vive controllers
@@ -19,11 +14,11 @@ export class WebXRHTCViveMotionController extends WebXRAbstractMotionController
     /**
      * The base url used to load the left and right controller models
      */
-    public static MODEL_BASE_URL: string = 'https://controllers.babylonjs.com/vive/';
+    public static MODEL_BASE_URL: string = "https://controllers.babylonjs.com/vive/";
     /**
      * File name for the controller model.
      */
-    public static MODEL_FILENAME: string = 'wand.babylon';
+    public static MODEL_FILENAME: string = "wand.babylon";
 
     public profileId = "htc-vive";
 
@@ -33,19 +28,17 @@ export class WebXRHTCViveMotionController extends WebXRAbstractMotionController
      * @param gamepadObject the corresponding gamepad object
      * @param handedness the handedness of the controller
      */
-    constructor(scene: Scene,
-        gamepadObject: IMinimalMotionControllerObject,
-        handedness: MotionControllerHandedness) {
+    constructor(scene: Scene, gamepadObject: IMinimalMotionControllerObject, handedness: MotionControllerHandedness) {
         super(scene, HTCViveLayout[handedness], gamepadObject, handedness);
     }
 
-    protected _getFilenameAndPath(): { filename: string; path: string; } {
+    protected _getFilenameAndPath(): { filename: string; path: string } {
         let filename = WebXRHTCViveMotionController.MODEL_FILENAME;
         let path = WebXRHTCViveMotionController.MODEL_BASE_URL;
 
         return {
             filename,
-            path
+            path,
         };
     }
 
@@ -57,19 +50,25 @@ export class WebXRHTCViveMotionController extends WebXRAbstractMotionController
         this.getComponentIds().forEach((id) => {
             const comp = id && this.getComponent(id);
             if (comp) {
-                comp.onButtonStateChangedObservable.add((component) => {
-                    if (!this.rootMesh || this.disableAnimation) { return; }
-
-                    switch (id) {
-                        case "xr-standard-trigger":
-                            (<AbstractMesh>(this._modelRootNode.getChildren()[6])).rotation.x = -component.value * 0.15;
-                            return;
-                        case "xr-standard-touchpad":
+                comp.onButtonStateChangedObservable.add(
+                    (component) => {
+                        if (!this.rootMesh || this.disableAnimation) {
                             return;
-                        case "xr-standard-squeeze":
-                            return;
-                    }
-                }, undefined, true);
+                        }
+
+                        switch (id) {
+                            case "xr-standard-trigger":
+                                (<AbstractMesh>this._modelRootNode.getChildren()[6]).rotation.x = -component.value * 0.15;
+                                return;
+                            case "xr-standard-touchpad":
+                                return;
+                            case "xr-standard-squeeze":
+                                return;
+                        }
+                    },
+                    undefined,
+                    true
+                );
             }
         });
     }
@@ -77,7 +76,9 @@ export class WebXRHTCViveMotionController extends WebXRAbstractMotionController
     protected _setRootMesh(meshes: AbstractMesh[]): void {
         this.rootMesh = new Mesh(this.profileId + " " + this.handedness, this.scene);
 
-        meshes.forEach((mesh) => { mesh.isPickable = false; });
+        meshes.forEach((mesh) => {
+            mesh.isPickable = false;
+        });
         this._modelRootNode = meshes[1];
         this._modelRootNode.parent = this.rootMesh;
         if (!this.scene.useRightHandedSystem) {
@@ -92,7 +93,7 @@ export class WebXRHTCViveMotionController extends WebXRAbstractMotionController
 
 // register the profile
 WebXRMotionControllerManager.RegisterController("htc-vive", (xrInput: XRInputSource, scene: Scene) => {
-    return new WebXRHTCViveMotionController(scene, <any>(xrInput.gamepad), xrInput.handedness);
+    return new WebXRHTCViveMotionController(scene, <any>xrInput.gamepad, xrInput.handedness);
 });
 
 // WebXRMotionControllerManager.RegisterController("htc-vive-legacy", (xrInput: XRInputSource, scene: Scene) => {
@@ -100,142 +101,130 @@ WebXRMotionControllerManager.RegisterController("htc-vive", (xrInput: XRInputSou
 // });
 
 const HTCViveLayout: IMotionControllerLayoutMap = {
-    "left": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    left: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {},
             },
             "xr-standard-squeeze": {
-                "type": "squeeze",
-                "gamepadIndices": {
-                    "button": 1
+                type: "squeeze",
+                gamepadIndices: {
+                    button: 1,
                 },
-                "rootNodeName": "xr_standard_squeeze",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_squeeze",
+                visualResponses: {},
             },
             "xr-standard-touchpad": {
-                "type": "touchpad",
-                "gamepadIndices": {
-                    "button": 2,
-                    "xAxis": 0,
-                    "yAxis": 1
-                },
-                "rootNodeName": "xr_standard_touchpad",
-                "visualResponses": {
+                type: "touchpad",
+                gamepadIndices: {
+                    button: 2,
+                    xAxis: 0,
+                    yAxis: 1,
                 },
+                rootNodeName: "xr_standard_touchpad",
+                visualResponses: {},
             },
-            "menu": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 4
+            menu: {
+                type: "button",
+                gamepadIndices: {
+                    button: 4,
                 },
-                "rootNodeName": "menu",
-                "visualResponses": {
-                }
-            }
+                rootNodeName: "menu",
+                visualResponses: {},
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "htc_vive_none",
-        "assetPath": "none.glb"
+        gamepadMapping: "xr-standard",
+        rootNodeName: "htc_vive_none",
+        assetPath: "none.glb",
     },
-    "right": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    right: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {},
             },
             "xr-standard-squeeze": {
-                "type": "squeeze",
-                "gamepadIndices": {
-                    "button": 1
+                type: "squeeze",
+                gamepadIndices: {
+                    button: 1,
                 },
-                "rootNodeName": "xr_standard_squeeze",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_squeeze",
+                visualResponses: {},
             },
             "xr-standard-touchpad": {
-                "type": "touchpad",
-                "gamepadIndices": {
-                    "button": 2,
-                    "xAxis": 0,
-                    "yAxis": 1
-                },
-                "rootNodeName": "xr_standard_touchpad",
-                "visualResponses": {
+                type: "touchpad",
+                gamepadIndices: {
+                    button: 2,
+                    xAxis: 0,
+                    yAxis: 1,
                 },
+                rootNodeName: "xr_standard_touchpad",
+                visualResponses: {},
             },
-            "menu": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 4
+            menu: {
+                type: "button",
+                gamepadIndices: {
+                    button: 4,
                 },
-                "rootNodeName": "menu",
-                "visualResponses": {
-                }
-            }
+                rootNodeName: "menu",
+                visualResponses: {},
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "htc_vive_none",
-        "assetPath": "none.glb"
+        gamepadMapping: "xr-standard",
+        rootNodeName: "htc_vive_none",
+        assetPath: "none.glb",
     },
-    "none": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    none: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {},
             },
             "xr-standard-squeeze": {
-                "type": "squeeze",
-                "gamepadIndices": {
-                    "button": 1
+                type: "squeeze",
+                gamepadIndices: {
+                    button: 1,
                 },
-                "rootNodeName": "xr_standard_squeeze",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_squeeze",
+                visualResponses: {},
             },
             "xr-standard-touchpad": {
-                "type": "touchpad",
-                "gamepadIndices": {
-                    "button": 2,
-                    "xAxis": 0,
-                    "yAxis": 1
-                },
-                "rootNodeName": "xr_standard_touchpad",
-                "visualResponses": {
+                type: "touchpad",
+                gamepadIndices: {
+                    button: 2,
+                    xAxis: 0,
+                    yAxis: 1,
                 },
+                rootNodeName: "xr_standard_touchpad",
+                visualResponses: {},
             },
-            "menu": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 4
+            menu: {
+                type: "button",
+                gamepadIndices: {
+                    button: 4,
                 },
-                "rootNodeName": "menu",
-                "visualResponses": {
-                }
-            }
+                rootNodeName: "menu",
+                visualResponses: {},
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "htc-vive-none",
-        "assetPath": "none.glb"
-    }
+        gamepadMapping: "xr-standard",
+        rootNodeName: "htc-vive-none",
+        assetPath: "none.glb",
+    },
 };

+ 303 - 385
src/XR/motionController/webXRMicrosoftMixedRealityController.ts

@@ -1,16 +1,11 @@
-import {
-    WebXRAbstractMotionController,
-    IMinimalMotionControllerObject,
-    MotionControllerHandedness,
-    IMotionControllerLayoutMap
-} from "./webXRAbstractMotionController";
-import { WebXRMotionControllerManager } from './webXRMotionControllerManager';
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { Scene } from '../../scene';
-import { Mesh } from '../../Meshes/mesh';
-import { Quaternion } from '../../Maths/math.vector';
-import { SceneLoader } from '../../Loading/sceneLoader';
-import { Logger } from '../../Misc/logger';
+import { WebXRAbstractMotionController, IMinimalMotionControllerObject, MotionControllerHandedness, IMotionControllerLayoutMap } from "./webXRAbstractMotionController";
+import { WebXRMotionControllerManager } from "./webXRMotionControllerManager";
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { Scene } from "../../scene";
+import { Mesh } from "../../Meshes/mesh";
+import { Quaternion } from "../../Maths/math.vector";
+import { SceneLoader } from "../../Loading/sceneLoader";
+import { Logger } from "../../Misc/logger";
 
 /**
  * The motion controller class for all microsoft mixed reality controllers
@@ -19,69 +14,69 @@ export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionCon
     // use this in the future - https://github.com/immersive-web/webxr-input-profiles/tree/master/packages/assets/profiles/microsoft
     protected readonly _mapping = {
         defaultButton: {
-            "valueNodeName": "VALUE",
-            "unpressedNodeName": "UNPRESSED",
-            "pressedNodeName": "PRESSED"
+            valueNodeName: "VALUE",
+            unpressedNodeName: "UNPRESSED",
+            pressedNodeName: "PRESSED",
         },
         defaultAxis: {
-            "valueNodeName": "VALUE",
-            "minNodeName": "MIN",
-            "maxNodeName": "MAX"
+            valueNodeName: "VALUE",
+            minNodeName: "MIN",
+            maxNodeName: "MAX",
         },
         buttons: {
             "xr-standard-trigger": {
-                "rootNodeName": "SELECT",
-                "componentProperty": "button",
-                "states": ["default", "touched", "pressed"]
+                rootNodeName: "SELECT",
+                componentProperty: "button",
+                states: ["default", "touched", "pressed"],
             },
             "xr-standard-squeeze": {
-                "rootNodeName": "GRASP",
-                "componentProperty": "state",
-                "states": ["pressed"]
+                rootNodeName: "GRASP",
+                componentProperty: "state",
+                states: ["pressed"],
             },
             "xr-standard-touchpad": {
-                "rootNodeName": "TOUCHPAD_PRESS",
-                "labelAnchorNodeName": "squeeze-label",
-                "touchPointNodeName": "TOUCH" // TODO - use this for visual feedback
+                rootNodeName: "TOUCHPAD_PRESS",
+                labelAnchorNodeName: "squeeze-label",
+                touchPointNodeName: "TOUCH", // TODO - use this for visual feedback
             },
             "xr-standard-thumbstick": {
-                "rootNodeName": "THUMBSTICK_PRESS",
-                "componentProperty": "state",
-                "states": ["pressed"],
-            }
+                rootNodeName: "THUMBSTICK_PRESS",
+                componentProperty: "state",
+                states: ["pressed"],
+            },
         },
         axes: {
             "xr-standard-touchpad": {
                 "x-axis": {
-                    "rootNodeName": "TOUCHPAD_TOUCH_X"
+                    rootNodeName: "TOUCHPAD_TOUCH_X",
                 },
                 "y-axis": {
-                    "rootNodeName": "TOUCHPAD_TOUCH_Y"
-                }
+                    rootNodeName: "TOUCHPAD_TOUCH_Y",
+                },
             },
             "xr-standard-thumbstick": {
                 "x-axis": {
-                    "rootNodeName": "THUMBSTICK_X"
+                    rootNodeName: "THUMBSTICK_X",
                 },
                 "y-axis": {
-                    "rootNodeName": "THUMBSTICK_Y"
-                }
-            }
-        }
+                    rootNodeName: "THUMBSTICK_Y",
+                },
+            },
+        },
     };
 
     /**
      * The base url used to load the left and right controller models
      */
-    public static MODEL_BASE_URL: string = 'https://controllers.babylonjs.com/microsoft/';
+    public static MODEL_BASE_URL: string = "https://controllers.babylonjs.com/microsoft/";
     /**
      * The name of the left controller model file
      */
-    public static MODEL_LEFT_FILENAME: string = 'left.glb';
+    public static MODEL_LEFT_FILENAME: string = "left.glb";
     /**
      * The name of the right controller model file
      */
-    public static MODEL_RIGHT_FILENAME: string = 'right.glb';
+    public static MODEL_RIGHT_FILENAME: string = "right.glb";
 
     public profileId = "microsoft-mixed-reality";
 
@@ -89,33 +84,35 @@ export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionCon
         super(scene, MixedRealityProfile["left-right"], gamepadObject, handedness);
     }
 
-    protected _getFilenameAndPath(): { filename: string; path: string; } {
+    protected _getFilenameAndPath(): { filename: string; path: string } {
         let filename = "";
-        if (this.handedness === 'left') {
+        if (this.handedness === "left") {
             filename = WebXRMicrosoftMixedRealityController.MODEL_LEFT_FILENAME;
-        }
-        else { // Right is the default if no hand is specified
+        } else {
+            // Right is the default if no hand is specified
             filename = WebXRMicrosoftMixedRealityController.MODEL_RIGHT_FILENAME;
         }
 
-        const device = 'default';
-        let path = WebXRMicrosoftMixedRealityController.MODEL_BASE_URL + device + '/';
+        const device = "default";
+        let path = WebXRMicrosoftMixedRealityController.MODEL_BASE_URL + device + "/";
         return {
             filename,
-            path
+            path,
         };
     }
 
     protected _getModelLoadingConstraints(): boolean {
         const glbLoaded = SceneLoader.IsPluginForExtensionAvailable(".glb");
         if (!glbLoaded) {
-            Logger.Warn('glTF / glb loaded was not registered, using generic controller instead');
+            Logger.Warn("glTF / glb loaded was not registered, using generic controller instead");
         }
         return glbLoaded;
     }
 
     protected _processLoadedModel(_meshes: AbstractMesh[]): void {
-        if (!this.rootMesh) { return; }
+        if (!this.rootMesh) {
+            return;
+        }
 
         // Button Meshes
         this.getComponentIds().forEach((id, i) => {
@@ -126,13 +123,13 @@ export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionCon
                 const buttonMap = (<any>this._mapping.buttons)[id];
                 const buttonMeshName = buttonMap.rootNodeName;
                 if (!buttonMeshName) {
-                    Logger.Log('Skipping unknown button at index: ' + i + ' with mapped name: ' + id);
+                    Logger.Log("Skipping unknown button at index: " + i + " with mapped name: " + id);
                     return;
                 }
 
                 var buttonMesh = this._getChildByName(this.rootMesh, buttonMeshName);
                 if (!buttonMesh) {
-                    Logger.Warn('Missing button mesh with name: ' + buttonMeshName);
+                    Logger.Warn("Missing button mesh with name: " + buttonMeshName);
                     return;
                 }
 
@@ -143,16 +140,19 @@ export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionCon
                 if (buttonMap.valueMesh && buttonMap.pressedMesh && buttonMap.unpressedMesh) {
                     const comp = this.getComponent(id);
                     if (comp) {
-                        comp.onButtonStateChangedObservable.add((component) => {
-                            this._lerpTransform(buttonMap, component.value);
-                        }, undefined, true);
+                        comp.onButtonStateChangedObservable.add(
+                            (component) => {
+                                this._lerpTransform(buttonMap, component.value);
+                            },
+                            undefined,
+                            true
+                        );
                     }
                 } else {
                     // If we didn't find the mesh, it simply means this button won't have transforms applied as mapped button value changes.
-                    Logger.Warn('Missing button submesh under mesh with name: ' + buttonMeshName);
+                    Logger.Warn("Missing button submesh under mesh with name: " + buttonMeshName);
                 }
             }
-
         });
 
         // Axis Meshes
@@ -163,12 +163,14 @@ export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionCon
             }
 
             ["x-axis", "y-axis"].forEach((axis) => {
-                if (!this.rootMesh) { return; }
+                if (!this.rootMesh) {
+                    return;
+                }
                 const axisMap = (<any>this._mapping.axes)[id][axis];
 
                 var axisMesh = this._getChildByName(this.rootMesh, axisMap.rootNodeName);
                 if (!axisMesh) {
-                    Logger.Warn('Missing axis mesh with name: ' + axisMap.rootNodeName);
+                    Logger.Warn("Missing axis mesh with name: " + axisMap.rootNodeName);
                     return;
                 }
 
@@ -178,17 +180,19 @@ export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionCon
 
                 if (axisMap.valueMesh && axisMap.minMesh && axisMap.maxMesh) {
                     if (comp) {
-                        comp.onAxisValueChangedObservable.add((axisValues) => {
-                            const value = axis === "x-axis" ? axisValues.x : axisValues.y;
-                            this._lerpTransform(axisMap, value, true);
-                        }, undefined, true);
+                        comp.onAxisValueChangedObservable.add(
+                            (axisValues) => {
+                                const value = axis === "x-axis" ? axisValues.x : axisValues.y;
+                                this._lerpTransform(axisMap, value, true);
+                            },
+                            undefined,
+                            true
+                        );
                     }
-
                 } else {
                     // If we didn't find the mesh, it simply means this button won't have transforms applied as mapped button value changes.
-                    Logger.Warn('Missing axis submesh under mesh with name: ' + axisMap.rootNodeName);
+                    Logger.Warn("Missing axis submesh under mesh with name: " + axisMap.rootNodeName);
                 }
-
             });
         });
     }
@@ -225,365 +229,279 @@ export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionCon
 
 // register the profile
 WebXRMotionControllerManager.RegisterController("windows-mixed-reality", (xrInput: XRInputSource, scene: Scene) => {
-    return new WebXRMicrosoftMixedRealityController(scene, <any>(xrInput.gamepad), xrInput.handedness);
+    return new WebXRMicrosoftMixedRealityController(scene, <any>xrInput.gamepad, xrInput.handedness);
 });
 
 // https://github.com/immersive-web/webxr-input-profiles/blob/master/packages/registry/profiles/microsoft/microsoft-mixed-reality.json
 const MixedRealityProfile: IMotionControllerLayoutMap = {
-    "left": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    left: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
+                },
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {
+                    xr_standard_trigger_pressed: {
+                        componentProperty: "button",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_trigger_pressed_value",
+                        minNodeName: "xr_standard_trigger_pressed_min",
+                        maxNodeName: "xr_standard_trigger_pressed_max",
+                    },
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {
-                    "xr_standard_trigger_pressed": {
-                        "componentProperty": "button",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_trigger_pressed_value",
-                        "minNodeName": "xr_standard_trigger_pressed_min",
-                        "maxNodeName": "xr_standard_trigger_pressed_max"
-                    }
-                }
             },
             "xr-standard-squeeze": {
-                "type": "squeeze",
-                "gamepadIndices": {
-                    "button": 1
+                type: "squeeze",
+                gamepadIndices: {
+                    button: 1,
+                },
+                rootNodeName: "xr_standard_squeeze",
+                visualResponses: {
+                    xr_standard_squeeze_pressed: {
+                        componentProperty: "button",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_squeeze_pressed_value",
+                        minNodeName: "xr_standard_squeeze_pressed_min",
+                        maxNodeName: "xr_standard_squeeze_pressed_max",
+                    },
                 },
-                "rootNodeName": "xr_standard_squeeze",
-                "visualResponses": {
-                    "xr_standard_squeeze_pressed": {
-                        "componentProperty": "button",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_squeeze_pressed_value",
-                        "minNodeName": "xr_standard_squeeze_pressed_min",
-                        "maxNodeName": "xr_standard_squeeze_pressed_max"
-                    }
-                }
             },
             "xr-standard-touchpad": {
-                "type": "touchpad",
-                "gamepadIndices": {
-                    "button": 2,
-                    "xAxis": 0,
-                    "yAxis": 1
+                type: "touchpad",
+                gamepadIndices: {
+                    button: 2,
+                    xAxis: 0,
+                    yAxis: 1,
                 },
-                "rootNodeName": "xr_standard_touchpad",
-                "visualResponses": {
-                    "xr_standard_touchpad_pressed": {
-                        "componentProperty": "button",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_pressed_value",
-                        "minNodeName": "xr_standard_touchpad_pressed_min",
-                        "maxNodeName": "xr_standard_touchpad_pressed_max"
+                rootNodeName: "xr_standard_touchpad",
+                visualResponses: {
+                    xr_standard_touchpad_pressed: {
+                        componentProperty: "button",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_pressed_value",
+                        minNodeName: "xr_standard_touchpad_pressed_min",
+                        maxNodeName: "xr_standard_touchpad_pressed_max",
                     },
-                    "xr_standard_touchpad_xaxis_pressed": {
-                        "componentProperty": "xAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_xaxis_pressed_value",
-                        "minNodeName": "xr_standard_touchpad_xaxis_pressed_min",
-                        "maxNodeName": "xr_standard_touchpad_xaxis_pressed_max"
+                    xr_standard_touchpad_xaxis_pressed: {
+                        componentProperty: "xAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_xaxis_pressed_value",
+                        minNodeName: "xr_standard_touchpad_xaxis_pressed_min",
+                        maxNodeName: "xr_standard_touchpad_xaxis_pressed_max",
                     },
-                    "xr_standard_touchpad_yaxis_pressed": {
-                        "componentProperty": "yAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_yaxis_pressed_value",
-                        "minNodeName": "xr_standard_touchpad_yaxis_pressed_min",
-                        "maxNodeName": "xr_standard_touchpad_yaxis_pressed_max"
+                    xr_standard_touchpad_yaxis_pressed: {
+                        componentProperty: "yAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_yaxis_pressed_value",
+                        minNodeName: "xr_standard_touchpad_yaxis_pressed_min",
+                        maxNodeName: "xr_standard_touchpad_yaxis_pressed_max",
                     },
-                    "xr_standard_touchpad_xaxis_touched": {
-                        "componentProperty": "xAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_xaxis_touched_value",
-                        "minNodeName": "xr_standard_touchpad_xaxis_touched_min",
-                        "maxNodeName": "xr_standard_touchpad_xaxis_touched_max"
+                    xr_standard_touchpad_xaxis_touched: {
+                        componentProperty: "xAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_xaxis_touched_value",
+                        minNodeName: "xr_standard_touchpad_xaxis_touched_min",
+                        maxNodeName: "xr_standard_touchpad_xaxis_touched_max",
                     },
-                    "xr_standard_touchpad_yaxis_touched": {
-                        "componentProperty": "yAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_yaxis_touched_value",
-                        "minNodeName": "xr_standard_touchpad_yaxis_touched_min",
-                        "maxNodeName": "xr_standard_touchpad_yaxis_touched_max"
+                    xr_standard_touchpad_yaxis_touched: {
+                        componentProperty: "yAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_yaxis_touched_value",
+                        minNodeName: "xr_standard_touchpad_yaxis_touched_min",
+                        maxNodeName: "xr_standard_touchpad_yaxis_touched_max",
+                    },
+                    xr_standard_touchpad_axes_touched: {
+                        componentProperty: "state",
+                        states: ["touched", "pressed"],
+                        valueNodeProperty: "visibility",
+                        valueNodeName: "xr_standard_touchpad_axes_touched_value",
                     },
-                    "xr_standard_touchpad_axes_touched": {
-                        "componentProperty": "state",
-                        "states": [
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "visibility",
-                        "valueNodeName": "xr_standard_touchpad_axes_touched_value"
-                    }
                 },
-                "touchPointNodeName": "xr_standard_touchpad_axes_touched_value"
+                touchPointNodeName: "xr_standard_touchpad_axes_touched_value",
             },
             "xr-standard-thumbstick": {
-                "type": "thumbstick",
-                "gamepadIndices": {
-                    "button": 3,
-                    "xAxis": 2,
-                    "yAxis": 3
+                type: "thumbstick",
+                gamepadIndices: {
+                    button: 3,
+                    xAxis: 2,
+                    yAxis: 3,
                 },
-                "rootNodeName": "xr_standard_thumbstick",
-                "visualResponses": {
-                    "xr_standard_thumbstick_pressed": {
-                        "componentProperty": "button",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_thumbstick_pressed_value",
-                        "minNodeName": "xr_standard_thumbstick_pressed_min",
-                        "maxNodeName": "xr_standard_thumbstick_pressed_max"
+                rootNodeName: "xr_standard_thumbstick",
+                visualResponses: {
+                    xr_standard_thumbstick_pressed: {
+                        componentProperty: "button",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_thumbstick_pressed_value",
+                        minNodeName: "xr_standard_thumbstick_pressed_min",
+                        maxNodeName: "xr_standard_thumbstick_pressed_max",
                     },
-                    "xr_standard_thumbstick_xaxis_pressed": {
-                        "componentProperty": "xAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_thumbstick_xaxis_pressed_value",
-                        "minNodeName": "xr_standard_thumbstick_xaxis_pressed_min",
-                        "maxNodeName": "xr_standard_thumbstick_xaxis_pressed_max"
+                    xr_standard_thumbstick_xaxis_pressed: {
+                        componentProperty: "xAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_thumbstick_xaxis_pressed_value",
+                        minNodeName: "xr_standard_thumbstick_xaxis_pressed_min",
+                        maxNodeName: "xr_standard_thumbstick_xaxis_pressed_max",
                     },
-                    "xr_standard_thumbstick_yaxis_pressed": {
-                        "componentProperty": "yAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_thumbstick_yaxis_pressed_value",
-                        "minNodeName": "xr_standard_thumbstick_yaxis_pressed_min",
-                        "maxNodeName": "xr_standard_thumbstick_yaxis_pressed_max"
-                    }
-                }
-            }
+                    xr_standard_thumbstick_yaxis_pressed: {
+                        componentProperty: "yAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_thumbstick_yaxis_pressed_value",
+                        minNodeName: "xr_standard_thumbstick_yaxis_pressed_min",
+                        maxNodeName: "xr_standard_thumbstick_yaxis_pressed_max",
+                    },
+                },
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "microsoft-mixed-reality-left",
-        "assetPath": "left.glb"
+        gamepadMapping: "xr-standard",
+        rootNodeName: "microsoft-mixed-reality-left",
+        assetPath: "left.glb",
     },
-    "right": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    right: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
+                },
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {
+                    xr_standard_trigger_pressed: {
+                        componentProperty: "button",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_trigger_pressed_value",
+                        minNodeName: "xr_standard_trigger_pressed_min",
+                        maxNodeName: "xr_standard_trigger_pressed_max",
+                    },
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {
-                    "xr_standard_trigger_pressed": {
-                        "componentProperty": "button",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_trigger_pressed_value",
-                        "minNodeName": "xr_standard_trigger_pressed_min",
-                        "maxNodeName": "xr_standard_trigger_pressed_max"
-                    }
-                }
             },
             "xr-standard-squeeze": {
-                "type": "squeeze",
-                "gamepadIndices": {
-                    "button": 1
+                type: "squeeze",
+                gamepadIndices: {
+                    button: 1,
+                },
+                rootNodeName: "xr_standard_squeeze",
+                visualResponses: {
+                    xr_standard_squeeze_pressed: {
+                        componentProperty: "button",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_squeeze_pressed_value",
+                        minNodeName: "xr_standard_squeeze_pressed_min",
+                        maxNodeName: "xr_standard_squeeze_pressed_max",
+                    },
                 },
-                "rootNodeName": "xr_standard_squeeze",
-                "visualResponses": {
-                    "xr_standard_squeeze_pressed": {
-                        "componentProperty": "button",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_squeeze_pressed_value",
-                        "minNodeName": "xr_standard_squeeze_pressed_min",
-                        "maxNodeName": "xr_standard_squeeze_pressed_max"
-                    }
-                }
             },
             "xr-standard-touchpad": {
-                "type": "touchpad",
-                "gamepadIndices": {
-                    "button": 2,
-                    "xAxis": 0,
-                    "yAxis": 1
+                type: "touchpad",
+                gamepadIndices: {
+                    button: 2,
+                    xAxis: 0,
+                    yAxis: 1,
                 },
-                "rootNodeName": "xr_standard_touchpad",
-                "visualResponses": {
-                    "xr_standard_touchpad_pressed": {
-                        "componentProperty": "button",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_pressed_value",
-                        "minNodeName": "xr_standard_touchpad_pressed_min",
-                        "maxNodeName": "xr_standard_touchpad_pressed_max"
+                rootNodeName: "xr_standard_touchpad",
+                visualResponses: {
+                    xr_standard_touchpad_pressed: {
+                        componentProperty: "button",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_pressed_value",
+                        minNodeName: "xr_standard_touchpad_pressed_min",
+                        maxNodeName: "xr_standard_touchpad_pressed_max",
                     },
-                    "xr_standard_touchpad_xaxis_pressed": {
-                        "componentProperty": "xAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_xaxis_pressed_value",
-                        "minNodeName": "xr_standard_touchpad_xaxis_pressed_min",
-                        "maxNodeName": "xr_standard_touchpad_xaxis_pressed_max"
+                    xr_standard_touchpad_xaxis_pressed: {
+                        componentProperty: "xAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_xaxis_pressed_value",
+                        minNodeName: "xr_standard_touchpad_xaxis_pressed_min",
+                        maxNodeName: "xr_standard_touchpad_xaxis_pressed_max",
                     },
-                    "xr_standard_touchpad_yaxis_pressed": {
-                        "componentProperty": "yAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_yaxis_pressed_value",
-                        "minNodeName": "xr_standard_touchpad_yaxis_pressed_min",
-                        "maxNodeName": "xr_standard_touchpad_yaxis_pressed_max"
+                    xr_standard_touchpad_yaxis_pressed: {
+                        componentProperty: "yAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_yaxis_pressed_value",
+                        minNodeName: "xr_standard_touchpad_yaxis_pressed_min",
+                        maxNodeName: "xr_standard_touchpad_yaxis_pressed_max",
                     },
-                    "xr_standard_touchpad_xaxis_touched": {
-                        "componentProperty": "xAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_xaxis_touched_value",
-                        "minNodeName": "xr_standard_touchpad_xaxis_touched_min",
-                        "maxNodeName": "xr_standard_touchpad_xaxis_touched_max"
+                    xr_standard_touchpad_xaxis_touched: {
+                        componentProperty: "xAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_xaxis_touched_value",
+                        minNodeName: "xr_standard_touchpad_xaxis_touched_min",
+                        maxNodeName: "xr_standard_touchpad_xaxis_touched_max",
                     },
-                    "xr_standard_touchpad_yaxis_touched": {
-                        "componentProperty": "yAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_touchpad_yaxis_touched_value",
-                        "minNodeName": "xr_standard_touchpad_yaxis_touched_min",
-                        "maxNodeName": "xr_standard_touchpad_yaxis_touched_max"
+                    xr_standard_touchpad_yaxis_touched: {
+                        componentProperty: "yAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_touchpad_yaxis_touched_value",
+                        minNodeName: "xr_standard_touchpad_yaxis_touched_min",
+                        maxNodeName: "xr_standard_touchpad_yaxis_touched_max",
+                    },
+                    xr_standard_touchpad_axes_touched: {
+                        componentProperty: "state",
+                        states: ["touched", "pressed"],
+                        valueNodeProperty: "visibility",
+                        valueNodeName: "xr_standard_touchpad_axes_touched_value",
                     },
-                    "xr_standard_touchpad_axes_touched": {
-                        "componentProperty": "state",
-                        "states": [
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "visibility",
-                        "valueNodeName": "xr_standard_touchpad_axes_touched_value"
-                    }
                 },
-                "touchPointNodeName": "xr_standard_touchpad_axes_touched_value"
+                touchPointNodeName: "xr_standard_touchpad_axes_touched_value",
             },
             "xr-standard-thumbstick": {
-                "type": "thumbstick",
-                "gamepadIndices": {
-                    "button": 3,
-                    "xAxis": 2,
-                    "yAxis": 3
+                type: "thumbstick",
+                gamepadIndices: {
+                    button: 3,
+                    xAxis: 2,
+                    yAxis: 3,
                 },
-                "rootNodeName": "xr_standard_thumbstick",
-                "visualResponses": {
-                    "xr_standard_thumbstick_pressed": {
-                        "componentProperty": "button",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_thumbstick_pressed_value",
-                        "minNodeName": "xr_standard_thumbstick_pressed_min",
-                        "maxNodeName": "xr_standard_thumbstick_pressed_max"
+                rootNodeName: "xr_standard_thumbstick",
+                visualResponses: {
+                    xr_standard_thumbstick_pressed: {
+                        componentProperty: "button",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_thumbstick_pressed_value",
+                        minNodeName: "xr_standard_thumbstick_pressed_min",
+                        maxNodeName: "xr_standard_thumbstick_pressed_max",
                     },
-                    "xr_standard_thumbstick_xaxis_pressed": {
-                        "componentProperty": "xAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_thumbstick_xaxis_pressed_value",
-                        "minNodeName": "xr_standard_thumbstick_xaxis_pressed_min",
-                        "maxNodeName": "xr_standard_thumbstick_xaxis_pressed_max"
+                    xr_standard_thumbstick_xaxis_pressed: {
+                        componentProperty: "xAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_thumbstick_xaxis_pressed_value",
+                        minNodeName: "xr_standard_thumbstick_xaxis_pressed_min",
+                        maxNodeName: "xr_standard_thumbstick_xaxis_pressed_max",
                     },
-                    "xr_standard_thumbstick_yaxis_pressed": {
-                        "componentProperty": "yAxis",
-                        "states": [
-                            "default",
-                            "touched",
-                            "pressed"
-                        ],
-                        "valueNodeProperty": "transform",
-                        "valueNodeName": "xr_standard_thumbstick_yaxis_pressed_value",
-                        "minNodeName": "xr_standard_thumbstick_yaxis_pressed_min",
-                        "maxNodeName": "xr_standard_thumbstick_yaxis_pressed_max"
-                    }
-                }
-            }
+                    xr_standard_thumbstick_yaxis_pressed: {
+                        componentProperty: "yAxis",
+                        states: ["default", "touched", "pressed"],
+                        valueNodeProperty: "transform",
+                        valueNodeName: "xr_standard_thumbstick_yaxis_pressed_value",
+                        minNodeName: "xr_standard_thumbstick_yaxis_pressed_min",
+                        maxNodeName: "xr_standard_thumbstick_yaxis_pressed_max",
+                    },
+                },
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "microsoft-mixed-reality-right",
-        "assetPath": "right.glb"
-    }
-};
+        gamepadMapping: "xr-standard",
+        rootNodeName: "microsoft-mixed-reality-right",
+        assetPath: "right.glb",
+    },
+};

+ 38 - 37
src/XR/motionController/webXRMotionControllerManager.ts

@@ -1,10 +1,8 @@
-import {
-    WebXRAbstractMotionController, IMotionControllerProfile,
-} from './webXRAbstractMotionController';
-import { WebXRGenericTriggerMotionController } from './webXRGenericMotionController';
-import { Scene } from '../../scene';
-import { Tools } from '../../Misc/tools';
-import { WebXRProfiledMotionController } from './webXRProfiledMotionController';
+import { WebXRAbstractMotionController, IMotionControllerProfile } from "./webXRAbstractMotionController";
+import { WebXRGenericTriggerMotionController } from "./webXRGenericMotionController";
+import { Scene } from "../../scene";
+import { Tools } from "../../Misc/tools";
+import { WebXRProfiledMotionController } from "./webXRProfiledMotionController";
 
 /**
  * A construction function type to create a new controller based on an xrInput object
@@ -108,7 +106,7 @@ export class WebXRMotionControllerManager {
         // legacy support - try using the gamepad id
         if (xrInput.gamepad && xrInput.gamepad.id) {
             switch (xrInput.gamepad.id) {
-                case (xrInput.gamepad.id.match(/oculus touch/gi) ? xrInput.gamepad.id : undefined):
+                case xrInput.gamepad.id.match(/oculus touch/gi) ? xrInput.gamepad.id : undefined:
                     // oculus in gamepad id
                     profileArray.push("oculus-touch-v2");
                     break;
@@ -132,7 +130,6 @@ export class WebXRMotionControllerManager {
             return firstFunction.call(this, profileArray, xrInput, scene).catch(() => {
                 return secondFunction.call(this, profileArray, xrInput, scene);
             });
-
         } else {
             // use only available functions
             return this._LoadProfilesFromAvailableControllers(profileArray, xrInput, scene);
@@ -169,41 +166,45 @@ export class WebXRMotionControllerManager {
      * @return a promise that resolves to a map of profiles available online
      */
     public static UpdateProfilesList() {
-        this._ProfilesList = Tools.LoadFileAsync(this.BaseRepositoryUrl + '/profiles/profilesList.json', false).then((data) => {
+        this._ProfilesList = Tools.LoadFileAsync(this.BaseRepositoryUrl + "/profiles/profilesList.json", false).then((data) => {
             return JSON.parse(data.toString());
         });
         return this._ProfilesList;
     }
 
     private static _LoadProfileFromRepository(profileArray: string[], xrInput: XRInputSource, scene: Scene): Promise<WebXRAbstractMotionController> {
-        return Promise.resolve().then(() => {
-            if (!this._ProfilesList) {
-                return this.UpdateProfilesList();
-            } else {
-                return this._ProfilesList;
-            }
-        }).then((profilesList: { [profile: string]: string }) => {
-            // load the right profile
-            for (let i = 0; i < profileArray.length; ++i) {
-                // defensive
-                if (!profileArray[i]) {
-                    continue;
+        return Promise.resolve()
+            .then(() => {
+                if (!this._ProfilesList) {
+                    return this.UpdateProfilesList();
+                } else {
+                    return this._ProfilesList;
                 }
-                if (profilesList[profileArray[i]]) {
-                    return profileArray[i];
+            })
+            .then((profilesList: { [profile: string]: string }) => {
+                // load the right profile
+                for (let i = 0; i < profileArray.length; ++i) {
+                    // defensive
+                    if (!profileArray[i]) {
+                        continue;
+                    }
+                    if (profilesList[profileArray[i]]) {
+                        return profileArray[i];
+                    }
                 }
-            }
 
-            throw new Error(`neither controller ${profileArray[0]} nor all fallbacks were found in the repository,`);
-        }).then((profileToLoad: string) => {
-            // load the profile
-            if (!this._ProfileLoadingPromises[profileToLoad]) {
-                this._ProfileLoadingPromises[profileToLoad] = Tools.LoadFileAsync(`${this.BaseRepositoryUrl}/profiles/${profileToLoad}/profile.json`, false).then((data) => <IMotionControllerProfile>JSON.parse(data as string));
-            }
-            return this._ProfileLoadingPromises[profileToLoad];
-        }).then((profile: IMotionControllerProfile) => {
-            return new WebXRProfiledMotionController(scene, xrInput, profile, this.BaseRepositoryUrl);
-        });
+                throw new Error(`neither controller ${profileArray[0]} nor all fallbacks were found in the repository,`);
+            })
+            .then((profileToLoad: string) => {
+                // load the profile
+                if (!this._ProfileLoadingPromises[profileToLoad]) {
+                    this._ProfileLoadingPromises[profileToLoad] = Tools.LoadFileAsync(`${this.BaseRepositoryUrl}/profiles/${profileToLoad}/profile.json`, false).then((data) => <IMotionControllerProfile>JSON.parse(data as string));
+                }
+                return this._ProfileLoadingPromises[profileToLoad];
+            })
+            .then((profile: IMotionControllerProfile) => {
+                return new WebXRProfiledMotionController(scene, xrInput, profile, this.BaseRepositoryUrl);
+            });
     }
 
     private static _LoadProfilesFromAvailableControllers(profileArray: string[], xrInput: XRInputSource, scene: Scene) {
@@ -228,8 +229,8 @@ export class WebXRMotionControllerManager {
 
 // register the generic profile(s) here so we will at least have them
 WebXRMotionControllerManager.RegisterController(WebXRGenericTriggerMotionController.ProfileId, (xrInput: XRInputSource, scene: Scene) => {
-    return new WebXRGenericTriggerMotionController(scene, <any>(xrInput.gamepad), xrInput.handedness);
+    return new WebXRGenericTriggerMotionController(scene, <any>xrInput.gamepad, xrInput.handedness);
 });
 
 // register fallbacks
-WebXRMotionControllerManager.DefaultFallbacks();
+WebXRMotionControllerManager.DefaultFallbacks();

+ 145 - 160
src/XR/motionController/webXROculusTouchMotionController.ts

@@ -1,14 +1,9 @@
-import {
-    WebXRAbstractMotionController,
-    IMinimalMotionControllerObject,
-    MotionControllerHandedness,
-    IMotionControllerLayoutMap
-} from "./webXRAbstractMotionController";
-import { WebXRMotionControllerManager } from './webXRMotionControllerManager';
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { Scene } from '../../scene';
-import { Mesh } from '../../Meshes/mesh';
-import { Quaternion } from '../../Maths/math.vector';
+import { WebXRAbstractMotionController, IMinimalMotionControllerObject, MotionControllerHandedness, IMotionControllerLayoutMap } from "./webXRAbstractMotionController";
+import { WebXRMotionControllerManager } from "./webXRMotionControllerManager";
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { Scene } from "../../scene";
+import { Mesh } from "../../Meshes/mesh";
+import { Quaternion } from "../../Maths/math.vector";
 
 /**
  * The motion controller class for oculus touch (quest, rift).
@@ -20,43 +15,39 @@ export class WebXROculusTouchMotionController extends WebXRAbstractMotionControl
     /**
      * The base url used to load the left and right controller models
      */
-    public static MODEL_BASE_URL: string = 'https://controllers.babylonjs.com/oculus/';
+    public static MODEL_BASE_URL: string = "https://controllers.babylonjs.com/oculus/";
     /**
      * The name of the left controller model file
      */
-    public static MODEL_LEFT_FILENAME: string = 'left.babylon';
+    public static MODEL_LEFT_FILENAME: string = "left.babylon";
     /**
      * The name of the right controller model file
      */
-    public static MODEL_RIGHT_FILENAME: string = 'right.babylon';
+    public static MODEL_RIGHT_FILENAME: string = "right.babylon";
     /**
      * Base Url for the Quest controller model.
      */
-    public static QUEST_MODEL_BASE_URL: string = 'https://controllers.babylonjs.com/oculusQuest/';
+    public static QUEST_MODEL_BASE_URL: string = "https://controllers.babylonjs.com/oculusQuest/";
 
     public profileId = "oculus-touch";
 
-    constructor(scene: Scene,
-        gamepadObject: IMinimalMotionControllerObject,
-        handedness: MotionControllerHandedness,
-        legacyMapping: boolean = false,
-        private _forceLegacyControllers: boolean = false) {
+    constructor(scene: Scene, gamepadObject: IMinimalMotionControllerObject, handedness: MotionControllerHandedness, legacyMapping: boolean = false, private _forceLegacyControllers: boolean = false) {
         super(scene, OculusTouchLayouts[handedness], gamepadObject, handedness);
     }
 
-    protected _getFilenameAndPath(): { filename: string; path: string; } {
+    protected _getFilenameAndPath(): { filename: string; path: string } {
         let filename = "";
-        if (this.handedness === 'left') {
+        if (this.handedness === "left") {
             filename = WebXROculusTouchMotionController.MODEL_LEFT_FILENAME;
-        }
-        else { // Right is the default if no hand is specified
+        } else {
+            // Right is the default if no hand is specified
             filename = WebXROculusTouchMotionController.MODEL_RIGHT_FILENAME;
         }
 
         let path = this._isQuest() ? WebXROculusTouchMotionController.QUEST_MODEL_BASE_URL : WebXROculusTouchMotionController.MODEL_BASE_URL;
         return {
             filename,
-            path
+            path,
         };
     }
 
@@ -66,53 +57,57 @@ export class WebXROculusTouchMotionController extends WebXRAbstractMotionControl
 
     protected _processLoadedModel(_meshes: AbstractMesh[]): void {
         const isQuest = this._isQuest();
-        const triggerDirection = this.handedness === 'right' ? -1 : 1;
+        const triggerDirection = this.handedness === "right" ? -1 : 1;
 
         this.getComponentIds().forEach((id) => {
             const comp = id && this.getComponent(id);
             if (comp) {
-                comp.onButtonStateChangedObservable.add((component) => {
-                    if (!this.rootMesh || this.disableAnimation) { return; }
-
-                    switch (id) {
-                        case "xr-standard-trigger": // index trigger
-                            if (!isQuest) {
-                                (<AbstractMesh>(this._modelRootNode.getChildren()[3])).rotation.x = -component.value * 0.20;
-                                (<AbstractMesh>(this._modelRootNode.getChildren()[3])).position.y = -component.value * 0.005;
-                                (<AbstractMesh>(this._modelRootNode.getChildren()[3])).position.z = -component.value * 0.005;
-                            }
-                            return;
-                        case "xr-standard-squeeze":  // secondary trigger
-                            if (!isQuest) {
-                                (<AbstractMesh>(this._modelRootNode.getChildren()[4])).position.x = triggerDirection * component.value * 0.0035;
-                            }
+                comp.onButtonStateChangedObservable.add(
+                    (component) => {
+                        if (!this.rootMesh || this.disableAnimation) {
                             return;
-                        case "xr-standard-thumbstick": // thumbstick
-                            return;
-                        case "a-button":
-                        case "x-button":
-                            if (!isQuest) {
-                                if (component.pressed) {
-                                    (<AbstractMesh>(this._modelRootNode.getChildren()[1])).position.y = -0.001;
+                        }
+
+                        switch (id) {
+                            case "xr-standard-trigger": // index trigger
+                                if (!isQuest) {
+                                    (<AbstractMesh>this._modelRootNode.getChildren()[3]).rotation.x = -component.value * 0.2;
+                                    (<AbstractMesh>this._modelRootNode.getChildren()[3]).position.y = -component.value * 0.005;
+                                    (<AbstractMesh>this._modelRootNode.getChildren()[3]).position.z = -component.value * 0.005;
                                 }
-                                else {
-                                    (<AbstractMesh>(this._modelRootNode.getChildren()[1])).position.y = 0;
+                                return;
+                            case "xr-standard-squeeze": // secondary trigger
+                                if (!isQuest) {
+                                    (<AbstractMesh>this._modelRootNode.getChildren()[4]).position.x = triggerDirection * component.value * 0.0035;
                                 }
-                            }
-                            return;
-                        case "b-button":
-                        case "y-button":
-                            if (!isQuest) {
-                                if (component.pressed) {
-                                    (<AbstractMesh>(this._modelRootNode.getChildren()[2])).position.y = -0.001;
+                                return;
+                            case "xr-standard-thumbstick": // thumbstick
+                                return;
+                            case "a-button":
+                            case "x-button":
+                                if (!isQuest) {
+                                    if (component.pressed) {
+                                        (<AbstractMesh>this._modelRootNode.getChildren()[1]).position.y = -0.001;
+                                    } else {
+                                        (<AbstractMesh>this._modelRootNode.getChildren()[1]).position.y = 0;
+                                    }
                                 }
-                                else {
-                                    (<AbstractMesh>(this._modelRootNode.getChildren()[2])).position.y = 0;
+                                return;
+                            case "b-button":
+                            case "y-button":
+                                if (!isQuest) {
+                                    if (component.pressed) {
+                                        (<AbstractMesh>this._modelRootNode.getChildren()[2]).position.y = -0.001;
+                                    } else {
+                                        (<AbstractMesh>this._modelRootNode.getChildren()[2]).position.y = 0;
+                                    }
                                 }
-                            }
-                            return;
-                    }
-                }, undefined, true);
+                                return;
+                        }
+                    },
+                    undefined,
+                    true
+                );
             }
         });
     }
@@ -123,7 +118,9 @@ export class WebXROculusTouchMotionController extends WebXRAbstractMotionControl
             this.rootMesh.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);
         }
 
-        meshes.forEach((mesh) => { mesh.isPickable = false; });
+        meshes.forEach((mesh) => {
+            mesh.isPickable = false;
+        });
         if (this._isQuest()) {
             this._modelRootNode = meshes[0];
         } else {
@@ -150,140 +147,128 @@ export class WebXROculusTouchMotionController extends WebXRAbstractMotionControl
 
 // register the profile
 WebXRMotionControllerManager.RegisterController("oculus-touch", (xrInput: XRInputSource, scene: Scene) => {
-    return new WebXROculusTouchMotionController(scene, <any>(xrInput.gamepad), xrInput.handedness);
+    return new WebXROculusTouchMotionController(scene, <any>xrInput.gamepad, xrInput.handedness);
 });
 
 WebXRMotionControllerManager.RegisterController("oculus-touch-legacy", (xrInput: XRInputSource, scene: Scene) => {
-    return new WebXROculusTouchMotionController(scene, <any>(xrInput.gamepad), xrInput.handedness, true);
+    return new WebXROculusTouchMotionController(scene, <any>xrInput.gamepad, xrInput.handedness, true);
 });
 
 const OculusTouchLayouts: IMotionControllerLayoutMap = {
-    "left": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    left: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {},
             },
             "xr-standard-squeeze": {
-                "type": "squeeze",
-                "gamepadIndices": {
-                    "button": 1
+                type: "squeeze",
+                gamepadIndices: {
+                    button: 1,
                 },
-                "rootNodeName": "xr_standard_squeeze",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_squeeze",
+                visualResponses: {},
             },
             "xr-standard-thumbstick": {
-                "type": "thumbstick",
-                "gamepadIndices": {
-                    "button": 3,
-                    "xAxis": 2,
-                    "yAxis": 3
+                type: "thumbstick",
+                gamepadIndices: {
+                    button: 3,
+                    xAxis: 2,
+                    yAxis: 3,
                 },
-                "rootNodeName": "xr_standard_thumbstick",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_thumbstick",
+                visualResponses: {},
             },
             "x-button": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 4
+                type: "button",
+                gamepadIndices: {
+                    button: 4,
                 },
-                "rootNodeName": "x_button",
-                "visualResponses": {
-                }
+                rootNodeName: "x_button",
+                visualResponses: {},
             },
             "y-button": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 5
+                type: "button",
+                gamepadIndices: {
+                    button: 5,
                 },
-                "rootNodeName": "y_button",
-                "visualResponses": {
-                }
+                rootNodeName: "y_button",
+                visualResponses: {},
             },
-            "thumbrest": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 6
+            thumbrest: {
+                type: "button",
+                gamepadIndices: {
+                    button: 6,
                 },
-                "rootNodeName": "thumbrest",
-                "visualResponses": {
-                }
-            }
+                rootNodeName: "thumbrest",
+                visualResponses: {},
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "oculus-touch-v2-left",
-        "assetPath": "left.glb"
+        gamepadMapping: "xr-standard",
+        rootNodeName: "oculus-touch-v2-left",
+        assetPath: "left.glb",
     },
-    "right": {
-        "selectComponentId": "xr-standard-trigger",
-        "components": {
+    right: {
+        selectComponentId: "xr-standard-trigger",
+        components: {
             "xr-standard-trigger": {
-                "type": "trigger",
-                "gamepadIndices": {
-                    "button": 0
+                type: "trigger",
+                gamepadIndices: {
+                    button: 0,
                 },
-                "rootNodeName": "xr_standard_trigger",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_trigger",
+                visualResponses: {},
             },
             "xr-standard-squeeze": {
-                "type": "squeeze",
-                "gamepadIndices": {
-                    "button": 1
+                type: "squeeze",
+                gamepadIndices: {
+                    button: 1,
                 },
-                "rootNodeName": "xr_standard_squeeze",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_squeeze",
+                visualResponses: {},
             },
             "xr-standard-thumbstick": {
-                "type": "thumbstick",
-                "gamepadIndices": {
-                    "button": 3,
-                    "xAxis": 2,
-                    "yAxis": 3
+                type: "thumbstick",
+                gamepadIndices: {
+                    button: 3,
+                    xAxis: 2,
+                    yAxis: 3,
                 },
-                "rootNodeName": "xr_standard_thumbstick",
-                "visualResponses": {
-                }
+                rootNodeName: "xr_standard_thumbstick",
+                visualResponses: {},
             },
             "a-button": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 4
+                type: "button",
+                gamepadIndices: {
+                    button: 4,
                 },
-                "rootNodeName": "a_button",
-                "visualResponses": {
-                }
+                rootNodeName: "a_button",
+                visualResponses: {},
             },
             "b-button": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 5
+                type: "button",
+                gamepadIndices: {
+                    button: 5,
                 },
-                "rootNodeName": "b_button",
-                "visualResponses": {
-                }
+                rootNodeName: "b_button",
+                visualResponses: {},
             },
-            "thumbrest": {
-                "type": "button",
-                "gamepadIndices": {
-                    "button": 6
+            thumbrest: {
+                type: "button",
+                gamepadIndices: {
+                    button: 6,
                 },
-                "rootNodeName": "thumbrest",
-                "visualResponses": {
-                }
-            }
+                rootNodeName: "thumbrest",
+                visualResponses: {},
+            },
         },
-        "gamepadMapping": "xr-standard",
-        "rootNodeName": "oculus-touch-v2-right",
-        "assetPath": "right.glb"
-    }
-};
+        gamepadMapping: "xr-standard",
+        rootNodeName: "oculus-touch-v2-right",
+        assetPath: "right.glb",
+    },
+};

+ 34 - 29
src/XR/motionController/webXRProfiledMotionController.ts

@@ -1,14 +1,14 @@
-import { AbstractMesh } from '../../Meshes/abstractMesh';
-import { WebXRAbstractMotionController, IMotionControllerProfile, IMotionControllerMeshMap } from './webXRAbstractMotionController';
-import { Scene } from '../../scene';
-import { SceneLoader } from '../../Loading/sceneLoader';
-import { Mesh } from '../../Meshes/mesh';
-import { Axis, Space } from '../../Maths/math.axis';
-import { Color3 } from '../../Maths/math.color';
-import { WebXRControllerComponent } from './webXRControllerComponent';
-import { SphereBuilder } from '../../Meshes/Builders/sphereBuilder';
-import { StandardMaterial } from '../../Materials/standardMaterial';
-import { Logger } from '../../Misc/logger';
+import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { WebXRAbstractMotionController, IMotionControllerProfile, IMotionControllerMeshMap } from "./webXRAbstractMotionController";
+import { Scene } from "../../scene";
+import { SceneLoader } from "../../Loading/sceneLoader";
+import { Mesh } from "../../Meshes/mesh";
+import { Axis, Space } from "../../Maths/math.axis";
+import { Color3 } from "../../Maths/math.color";
+import { WebXRControllerComponent } from "./webXRControllerComponent";
+import { SphereBuilder } from "../../Meshes/Builders/sphereBuilder";
+import { StandardMaterial } from "../../Materials/standardMaterial";
+import { Logger } from "../../Misc/logger";
 
 /**
  * A profiled motion controller has its profile loaded from an online repository.
@@ -19,9 +19,9 @@ export class WebXRProfiledMotionController extends WebXRAbstractMotionController
         [buttonName: string]: {
             mainMesh: AbstractMesh;
             states: {
-                [state: string]: IMotionControllerMeshMap
-            }
-        }
+                [state: string]: IMotionControllerMeshMap;
+            };
+        };
     } = {};
     private _touchDots: { [visKey: string]: AbstractMesh } = {};
 
@@ -42,17 +42,17 @@ export class WebXRProfiledMotionController extends WebXRAbstractMotionController
         });
     }
 
-    protected _getFilenameAndPath(): { filename: string; path: string; } {
+    protected _getFilenameAndPath(): { filename: string; path: string } {
         return {
             filename: this.layout.assetPath,
-            path: `${this._repositoryUrl}/profiles/${this.profileId}/`
+            path: `${this._repositoryUrl}/profiles/${this.profileId}/`,
         };
     }
 
     protected _getModelLoadingConstraints(): boolean {
         const glbLoaded = SceneLoader.IsPluginForExtensionAvailable(".glb");
         if (!glbLoaded) {
-            Logger.Warn('glTF / glb loaded was not registered, using generic controller instead');
+            Logger.Warn("glTF / glb loaded was not registered, using generic controller instead");
         }
         return glbLoaded;
     }
@@ -62,7 +62,7 @@ export class WebXRProfiledMotionController extends WebXRAbstractMotionController
             const componentInLayout = this.layout.components[type];
             this._buttonMeshMapping[type] = {
                 mainMesh: this._getChildByName(this.rootMesh!, componentInLayout.rootNodeName),
-                states: {}
+                states: {},
             };
             Object.keys(componentInLayout.visualResponses).forEach((visualResponseKey) => {
                 const visResponse = componentInLayout.visualResponses[visualResponseKey];
@@ -70,21 +70,24 @@ export class WebXRProfiledMotionController extends WebXRAbstractMotionController
                     this._buttonMeshMapping[type].states[visualResponseKey] = {
                         valueMesh: this._getChildByName(this.rootMesh!, visResponse.valueNodeName!),
                         minMesh: this._getChildByName(this.rootMesh!, visResponse.minNodeName!),
-                        maxMesh: this._getChildByName(this.rootMesh!, visResponse.maxNodeName!)
+                        maxMesh: this._getChildByName(this.rootMesh!, visResponse.maxNodeName!),
                     };
                 } else {
                     // visibility, usually for touchpads
-                    const nameOfMesh = (componentInLayout.type === WebXRControllerComponent.TOUCHPAD_TYPE && componentInLayout.touchPointNodeName)
-                        ? componentInLayout.touchPointNodeName : visResponse.valueNodeName!;
+                    const nameOfMesh = componentInLayout.type === WebXRControllerComponent.TOUCHPAD_TYPE && componentInLayout.touchPointNodeName ? componentInLayout.touchPointNodeName : visResponse.valueNodeName!;
                     this._buttonMeshMapping[type].states[visualResponseKey] = {
-                        valueMesh: this._getChildByName(this.rootMesh!, nameOfMesh)
+                        valueMesh: this._getChildByName(this.rootMesh!, nameOfMesh),
                     };
                     if (componentInLayout.type === WebXRControllerComponent.TOUCHPAD_TYPE && !this._touchDots[visualResponseKey]) {
-                        const dot = SphereBuilder.CreateSphere(visualResponseKey + 'dot', {
-                            diameter: 0.0015,
-                            segments: 8
-                        }, this.scene);
-                        dot.material = new StandardMaterial(visualResponseKey + 'mat', this.scene);
+                        const dot = SphereBuilder.CreateSphere(
+                            visualResponseKey + "dot",
+                            {
+                                diameter: 0.0015,
+                                segments: 8,
+                            },
+                            this.scene
+                        );
+                        dot.material = new StandardMaterial(visualResponseKey + "mat", this.scene);
                         (<StandardMaterial>dot.material).diffuseColor = Color3.Red();
                         dot.parent = this._buttonMeshMapping[type].states[visualResponseKey].valueMesh;
                         dot.isVisible = false;
@@ -125,7 +128,9 @@ export class WebXRProfiledMotionController extends WebXRAbstractMotionController
         }
         this.getComponentIds().forEach((id) => {
             const component = this.getComponent(id);
-            if (!component.hasChanges) { return; }
+            if (!component.hasChanges) {
+                return;
+            }
             const meshes = this._buttonMeshMapping[id];
             const componentInLayout = this.layout.components[id];
             Object.keys(componentInLayout.visualResponses).forEach((visualResponseKey) => {
@@ -148,4 +153,4 @@ export class WebXRProfiledMotionController extends WebXRAbstractMotionController
             });
         });
     }
-}
+}

+ 16 - 17
src/XR/webXRCamera.ts

@@ -4,7 +4,7 @@ import { Camera } from "../Cameras/camera";
 import { FreeCamera } from "../Cameras/freeCamera";
 import { TargetCamera } from "../Cameras/targetCamera";
 import { WebXRSessionManager } from "./webXRSessionManager";
-import { Viewport } from '../Maths/math.viewport';
+import { Viewport } from "../Maths/math.viewport";
 
 /**
  * WebXR Camera which holds the views for the xrSession
@@ -44,18 +44,21 @@ export class WebXRCamera extends FreeCamera {
             this._referenceQuaternion.copyFromFloats(0, 0, 0, 1);
             // first frame - camera's y position should be 0 for the correct offset
             this._firstFrame = this.compensateOnFirstFrame;
-
         });
 
         // Check transformation changes on each frame. Callback is added to be first so that the transformation will be
         // applied to the rest of the elements using the referenceSpace object
-        this._xrSessionManager.onXRFrameObservable.add((frame) => {
-            if (this._firstFrame) {
+        this._xrSessionManager.onXRFrameObservable.add(
+            (frame) => {
+                if (this._firstFrame) {
+                    this._updateFromXRSession();
+                }
+                this._updateReferenceSpace();
                 this._updateFromXRSession();
-            }
-            this._updateReferenceSpace();
-            this._updateFromXRSession();
-        }, undefined, true);
+            },
+            undefined,
+            true
+        );
     }
 
     /**
@@ -141,8 +144,7 @@ export class WebXRCamera extends FreeCamera {
                 this.position.y += this._referencedPosition.y;
                 // avoid using the head rotation on the first frame.
                 this._referenceQuaternion.copyFromFloats(0, 0, 0, 1);
-            }
-            else {
+            } else {
                 // update position and rotation as reference
                 this.rotationQuaternion.copyFrom(this._referenceQuaternion);
                 this.position.copyFrom(this._referencedPosition);
@@ -158,9 +160,9 @@ export class WebXRCamera extends FreeCamera {
             const currentRig = <TargetCamera>this.rigCameras[i];
             // update right and left, where applicable
             if (!currentRig.isLeftCamera && !currentRig.isRightCamera) {
-                if (view.eye === 'right') {
+                if (view.eye === "right") {
                     currentRig._isRightCamera = true;
-                } else if (view.eye === 'left') {
+                } else if (view.eye === "left") {
                     currentRig._isLeftCamera = true;
                 }
             }
@@ -255,9 +257,7 @@ export class WebXRCamera extends FreeCamera {
         if (ignoreHeight) {
             this._xrInvPositionCache.y = 0;
         }
-        const transform = new XRRigidTransform(
-            { x: this._xrInvPositionCache.x, y: this._xrInvPositionCache.y, z: this._xrInvPositionCache.z },
-            { x: this._xrInvQuaternionCache.x, y: this._xrInvQuaternionCache.y, z: this._xrInvQuaternionCache.z, w: this._xrInvQuaternionCache.w });
+        const transform = new XRRigidTransform({ x: this._xrInvPositionCache.x, y: this._xrInvPositionCache.y, z: this._xrInvPositionCache.z }, { x: this._xrInvQuaternionCache.x, y: this._xrInvQuaternionCache.y, z: this._xrInvQuaternionCache.z, w: this._xrInvQuaternionCache.w });
         // Update offset reference to use a new originOffset with the teleported
         // player position and orientation.
         // This new offset needs to be applied to the base ref space.
@@ -276,8 +276,7 @@ export class WebXRCamera extends FreeCamera {
             }
             pos.negateInPlace();
 
-            const transform2 = new XRRigidTransform(
-                {  x: pos.x, y: pos.y, z: pos.z  });
+            const transform2 = new XRRigidTransform({ x: pos.x, y: pos.y, z: pos.z });
             // Update offset reference to use a new originOffset with the teleported
             // player position and orientation.
             // This new offset needs to be applied to the base ref space.

+ 63 - 64
src/XR/webXRDefaultExperience.ts

@@ -1,13 +1,13 @@
 import { WebXRExperienceHelper } from "./webXRExperienceHelper";
-import { Scene } from '../scene';
-import { WebXRInput, IWebXRInputOptions } from './webXRInput';
-import { WebXRControllerPointerSelection, IWebXRControllerPointerSelectionOptions } from './features/WebXRControllerPointerSelection';
-import { WebXRRenderTarget } from './webXRTypes';
-import { WebXREnterExitUI, WebXREnterExitUIOptions } from './webXREnterExitUI';
-import { AbstractMesh } from '../Meshes/abstractMesh';
-import { WebXRManagedOutputCanvasOptions } from './webXRManagedOutputCanvas';
-import { WebXRMotionControllerTeleportation, IWebXRTeleportationOptions } from './features/WebXRControllerTeleportation';
-import { Logger } from '../Misc/logger';
+import { Scene } from "../scene";
+import { WebXRInput, IWebXRInputOptions } from "./webXRInput";
+import { WebXRControllerPointerSelection, IWebXRControllerPointerSelectionOptions } from "./features/WebXRControllerPointerSelection";
+import { WebXRRenderTarget } from "./webXRTypes";
+import { WebXREnterExitUI, WebXREnterExitUIOptions } from "./webXREnterExitUI";
+import { AbstractMesh } from "../Meshes/abstractMesh";
+import { WebXRManagedOutputCanvasOptions } from "./webXRManagedOutputCanvas";
+import { WebXRMotionControllerTeleportation, IWebXRTeleportationOptions } from "./features/WebXRControllerTeleportation";
+import { Logger } from "../Misc/logger";
 
 /**
  * Options for the default xr helper
@@ -89,8 +89,7 @@ export class WebXRDefaultExperience {
      */
     public teleportation: WebXRMotionControllerTeleportation;
 
-    private constructor() {
-    }
+    private constructor() {}
 
     /**
      * Creates the default xr experience
@@ -102,67 +101,67 @@ export class WebXRDefaultExperience {
         var result = new WebXRDefaultExperience();
 
         // Create base experience
-        return WebXRExperienceHelper.CreateAsync(scene).then((xrHelper) => {
-            result.baseExperience = xrHelper;
-
-            if (options.ignoreNativeCameraTransformation) {
-                result.baseExperience.camera.compensateOnFirstFrame = false;
-            }
+        return WebXRExperienceHelper.CreateAsync(scene)
+            .then((xrHelper) => {
+                result.baseExperience = xrHelper;
 
-            // Add controller support
-            result.input = new WebXRInput(xrHelper.sessionManager, xrHelper.camera, {
-                controllerOptions: {
-                    renderingGroupId: options.renderingGroupId
-                },
-                ...(options.inputOptions || {})
-            });
-            result.pointerSelection = <WebXRControllerPointerSelection>result.baseExperience.featuresManager.enableFeature(WebXRControllerPointerSelection.Name, options.useStablePlugins ? "stable" : "latest",
-            <IWebXRControllerPointerSelectionOptions>{
-                xrInput: result.input,
-                renderingGroupId: options.renderingGroupId
-            });
+                if (options.ignoreNativeCameraTransformation) {
+                    result.baseExperience.camera.compensateOnFirstFrame = false;
+                }
 
-            // Add default teleportation, including rotation
-            if (!options.disableTeleportation) {
-                result.teleportation = <WebXRMotionControllerTeleportation>result.baseExperience.featuresManager.enableFeature(WebXRMotionControllerTeleportation.Name, options.useStablePlugins ? "stable" : "latest",
-                <IWebXRTeleportationOptions>{
-                    floorMeshes: options.floorMeshes,
+                // Add controller support
+                result.input = new WebXRInput(xrHelper.sessionManager, xrHelper.camera, {
+                    controllerOptions: {
+                        renderingGroupId: options.renderingGroupId,
+                    },
+                    ...(options.inputOptions || {}),
+                });
+                result.pointerSelection = <WebXRControllerPointerSelection>result.baseExperience.featuresManager.enableFeature(WebXRControllerPointerSelection.Name, options.useStablePlugins ? "stable" : "latest", <IWebXRControllerPointerSelectionOptions>{
                     xrInput: result.input,
-                    renderingGroupId: options.renderingGroupId
+                    renderingGroupId: options.renderingGroupId,
                 });
-                result.teleportation.setSelectionFeature(result.pointerSelection);
-            }
 
-            // Create the WebXR output target
-            result.renderTarget = result.baseExperience.sessionManager.getWebXRRenderTarget(options.outputCanvasOptions);
+                // Add default teleportation, including rotation
+                if (!options.disableTeleportation) {
+                    result.teleportation = <WebXRMotionControllerTeleportation>result.baseExperience.featuresManager.enableFeature(WebXRMotionControllerTeleportation.Name, options.useStablePlugins ? "stable" : "latest", <IWebXRTeleportationOptions>{
+                        floorMeshes: options.floorMeshes,
+                        xrInput: result.input,
+                        renderingGroupId: options.renderingGroupId,
+                    });
+                    result.teleportation.setSelectionFeature(result.pointerSelection);
+                }
 
-            if (!options.disableDefaultUI) {
+                // Create the WebXR output target
+                result.renderTarget = result.baseExperience.sessionManager.getWebXRRenderTarget(options.outputCanvasOptions);
 
-                const uiOptions: WebXREnterExitUIOptions = {
-                    renderTarget: result.renderTarget,
-                    ...(options.uiOptions || {})
-                };
-                if (options.optionalFeatures) {
-                    if (typeof options.optionalFeatures === 'boolean') {
-                        uiOptions.optionalFeatures = ['hit-test', 'anchors', 'planes', 'hand-tracking'];
-                    } else {
-                        uiOptions.optionalFeatures = options.optionalFeatures;
+                if (!options.disableDefaultUI) {
+                    const uiOptions: WebXREnterExitUIOptions = {
+                        renderTarget: result.renderTarget,
+                        ...(options.uiOptions || {}),
+                    };
+                    if (options.optionalFeatures) {
+                        if (typeof options.optionalFeatures === "boolean") {
+                            uiOptions.optionalFeatures = ["hit-test", "anchors", "planes", "hand-tracking"];
+                        } else {
+                            uiOptions.optionalFeatures = options.optionalFeatures;
+                        }
                     }
+                    // Create ui for entering/exiting xr
+                    return WebXREnterExitUI.CreateAsync(scene, result.baseExperience, uiOptions).then((ui) => {
+                        result.enterExitUI = ui;
+                    });
+                } else {
+                    return;
                 }
-                // Create ui for entering/exiting xr
-                return WebXREnterExitUI.CreateAsync(scene, result.baseExperience, uiOptions).then((ui) => {
-                    result.enterExitUI = ui;
-                });
-            } else {
-                return;
-            }
-        }).then(() => {
-            return result;
-        }).catch((error) => {
-            Logger.Error("Error initializing XR");
-            Logger.Error(error);
-            return result;
-        });
+            })
+            .then(() => {
+                return result;
+            })
+            .catch((error) => {
+                Logger.Error("Error initializing XR");
+                Logger.Error(error);
+                return result;
+            });
     }
 
     /**
@@ -182,4 +181,4 @@ export class WebXRDefaultExperience {
             this.renderTarget.dispose();
         }
     }
-}
+}

File diff suppressed because it is too large
+ 22 - 18
src/XR/webXREnterExitUI.ts


+ 73 - 60
src/XR/webXRExperienceHelper.ts

@@ -4,9 +4,9 @@ import { IDisposable, Scene } from "../scene";
 import { Camera } from "../Cameras/camera";
 import { WebXRSessionManager } from "./webXRSessionManager";
 import { WebXRCamera } from "./webXRCamera";
-import { WebXRState, WebXRRenderTarget } from './webXRTypes';
-import { WebXRFeaturesManager } from './webXRFeaturesManager';
-import { Logger } from '../Misc/logger';
+import { WebXRState, WebXRRenderTarget } from "./webXRTypes";
+import { WebXRFeaturesManager } from "./webXRFeaturesManager";
+import { Logger } from "../Misc/logger";
 
 /**
  * Base set of functionality needed to create an XR experience (WebXRSessionManager, Camera, StateManagement, etc.)
@@ -63,14 +63,17 @@ export class WebXRExperienceHelper implements IDisposable {
      */
     public static CreateAsync(scene: Scene): Promise<WebXRExperienceHelper> {
         var helper = new WebXRExperienceHelper(scene);
-        return helper.sessionManager.initializeAsync().then(() => {
-            helper._supported = true;
-            return helper;
-        }).catch((e) => {
-            helper._setState(WebXRState.NOT_IN_XR);
-            helper.dispose();
-            throw e;
-        });
+        return helper.sessionManager
+            .initializeAsync()
+            .then(() => {
+                helper._supported = true;
+                return helper;
+            })
+            .catch((e) => {
+                helper._setState(WebXRState.NOT_IN_XR);
+                helper.dispose();
+                throw e;
+            });
     }
 
     /**
@@ -108,61 +111,71 @@ export class WebXRExperienceHelper implements IDisposable {
             Logger.Warn("We recommend using 'unbounded' reference space type when using 'immersive-ar' session mode");
         }
         // make sure that the session mode is supported
-        return this.sessionManager.initializeSessionAsync(sessionMode, sessionCreationOptions).then(() => {
-            return this.sessionManager.setReferenceSpaceTypeAsync(referenceSpaceType);
-        }).then(() => {
-            return renderTarget.initializeXRLayerAsync(this.sessionManager.session);
-        }).then(() => {
-            return this.sessionManager.updateRenderStateAsync({ depthFar: this.camera.maxZ, depthNear: this.camera.minZ, baseLayer: renderTarget.xrLayer! });
-        }).then(() => {
-            // run the render loop
-            this.sessionManager.runXRRenderLoop();
-            // Cache pre xr scene settings
-            this._originalSceneAutoClear = this.scene.autoClear;
-            this._nonVRCamera = this.scene.activeCamera;
-
-            this.scene.activeCamera = this.camera;
-            // do not compensate when AR session is used
-            if (sessionMode !== 'immersive-ar') {
-                this._nonXRToXRCamera();
-            } else {
-                // Kept here, TODO - check if needed
-                this.scene.autoClear = false;
-                this.camera.compensateOnFirstFrame = false;
-            }
-
-            this.sessionManager.onXRSessionEnded.addOnce(() => {
-                // Reset camera rigs output render target to ensure sessions render target is not drawn after it ends
-                this.camera.rigCameras.forEach((c) => {
-                    c.outputRenderTarget = null;
+        return this.sessionManager
+            .initializeSessionAsync(sessionMode, sessionCreationOptions)
+            .then(() => {
+                return this.sessionManager.setReferenceSpaceTypeAsync(referenceSpaceType);
+            })
+            .then(() => {
+                return renderTarget.initializeXRLayerAsync(this.sessionManager.session);
+            })
+            .then(() => {
+                return this.sessionManager.updateRenderStateAsync({
+                    depthFar: this.camera.maxZ,
+                    depthNear: this.camera.minZ,
+                    baseLayer: renderTarget.xrLayer!,
                 });
+            })
+            .then(() => {
+                // run the render loop
+                this.sessionManager.runXRRenderLoop();
+                // Cache pre xr scene settings
+                this._originalSceneAutoClear = this.scene.autoClear;
+                this._nonVRCamera = this.scene.activeCamera;
+
+                this.scene.activeCamera = this.camera;
+                // do not compensate when AR session is used
+                if (sessionMode !== "immersive-ar") {
+                    this._nonXRToXRCamera();
+                } else {
+                    // Kept here, TODO - check if needed
+                    this.scene.autoClear = false;
+                    this.camera.compensateOnFirstFrame = false;
+                }
 
-                // Restore scene settings
-                this.scene.autoClear = this._originalSceneAutoClear;
-                this.scene.activeCamera = this._nonVRCamera;
-                if (sessionMode !== 'immersive-ar' && this.camera.compensateOnFirstFrame) {
-                    if ((<any>this._nonVRCamera).setPosition) {
-                        (<any>this._nonVRCamera).setPosition(this.camera.position);
-                    } else {
-                        this._nonVRCamera!.position.copyFrom(this.camera.position);
+                this.sessionManager.onXRSessionEnded.addOnce(() => {
+                    // Reset camera rigs output render target to ensure sessions render target is not drawn after it ends
+                    this.camera.rigCameras.forEach((c) => {
+                        c.outputRenderTarget = null;
+                    });
+
+                    // Restore scene settings
+                    this.scene.autoClear = this._originalSceneAutoClear;
+                    this.scene.activeCamera = this._nonVRCamera;
+                    if (sessionMode !== "immersive-ar" && this.camera.compensateOnFirstFrame) {
+                        if ((<any>this._nonVRCamera).setPosition) {
+                            (<any>this._nonVRCamera).setPosition(this.camera.position);
+                        } else {
+                            this._nonVRCamera!.position.copyFrom(this.camera.position);
+                        }
                     }
-                }
 
-                this._setState(WebXRState.NOT_IN_XR);
-            });
+                    this._setState(WebXRState.NOT_IN_XR);
+                });
 
-            // Wait until the first frame arrives before setting state to in xr
-            this.sessionManager.onXRFrameObservable.addOnce(() => {
-                this._setState(WebXRState.IN_XR);
-            });
+                // Wait until the first frame arrives before setting state to in xr
+                this.sessionManager.onXRFrameObservable.addOnce(() => {
+                    this._setState(WebXRState.IN_XR);
+                });
 
-            return this.sessionManager;
-        }).catch((e: any) => {
-            console.log(e);
-            console.log(e.message);
-            this._setState(WebXRState.NOT_IN_XR);
-            throw (e);
-        });
+                return this.sessionManager;
+            })
+            .catch((e: any) => {
+                console.log(e);
+                console.log(e.message);
+                this._setState(WebXRState.NOT_IN_XR);
+                throw e;
+            });
     }
 
     /**

+ 18 - 18
src/XR/webXRFeaturesManager.ts

@@ -1,5 +1,5 @@
-import { WebXRSessionManager } from './webXRSessionManager';
-import { IDisposable } from '../scene';
+import { WebXRSessionManager } from "./webXRSessionManager";
+import { IDisposable } from "../scene";
 
 /**
  * Defining the interface required for a (webxr) feature
@@ -68,7 +68,7 @@ export class WebXRFeatureName {
 /**
  * Defining the constructor of a feature. Used to register the modules.
  */
-export type WebXRFeatureConstructor = (xrSessionManager: WebXRSessionManager, options?: any) => (() => IWebXRFeature);
+export type WebXRFeatureConstructor = (xrSessionManager: WebXRSessionManager, options?: any) => () => IWebXRFeature;
 
 /**
  * The WebXR features manager is responsible of enabling or disabling features required for the current XR session.
@@ -82,15 +82,15 @@ export class WebXRFeaturesManager implements IDisposable {
             stable: number;
             latest: number;
             [version: number]: WebXRFeatureConstructor;
-        }
+        };
     } = {};
 
     private _features: {
         [name: string]: {
-            featureImplementation: IWebXRFeature,
-            version: number,
-            enabled: boolean
-        }
+            featureImplementation: IWebXRFeature;
+            version: number;
+            enabled: boolean;
+        };
     } = {};
 
     /**
@@ -150,11 +150,11 @@ export class WebXRFeaturesManager implements IDisposable {
      * @param options optional options provided to the module.
      * @returns a function that, when called, will return a new instance of this feature
      */
-    public static ConstructFeature(featureName: string, version: number = 1, xrSessionManager: WebXRSessionManager, options?: any): (() => IWebXRFeature) {
+    public static ConstructFeature(featureName: string, version: number = 1, xrSessionManager: WebXRSessionManager, options?: any): () => IWebXRFeature {
         const constructorFunction = this._AvailableFeatures[featureName][version];
         if (!constructorFunction) {
             // throw an error? return nothing?
-            throw new Error('feature not found');
+            throw new Error("feature not found");
         }
 
         return constructorFunction(xrSessionManager, options);
@@ -226,7 +226,7 @@ export class WebXRFeaturesManager implements IDisposable {
      * @returns true if disable was successful
      */
     public disableFeature(featureName: string | { Name: string }): boolean {
-        const name = typeof featureName === 'string' ? featureName : featureName.Name;
+        const name = typeof featureName === "string" ? featureName : featureName.Name;
         const feature = this._features[name];
         if (feature && feature.enabled) {
             feature.enabled = false;
@@ -257,16 +257,16 @@ export class WebXRFeaturesManager implements IDisposable {
      * @param attachIfPossible if set to true (default) the feature will be automatically attached, if it is currently possible
      * @returns a new constructed feature or throws an error if feature not found.
      */
-    public enableFeature(featureName: string | { Name: string }, version: number | string = 'latest', moduleOptions: any = {}, attachIfPossible: boolean = true): IWebXRFeature {
-        const name = typeof featureName === 'string' ? featureName : featureName.Name;
+    public enableFeature(featureName: string | { Name: string }, version: number | string = "latest", moduleOptions: any = {}, attachIfPossible: boolean = true): IWebXRFeature {
+        const name = typeof featureName === "string" ? featureName : featureName.Name;
         let versionToLoad = 0;
-        if (typeof version === 'string') {
+        if (typeof version === "string") {
             if (!version) {
                 throw new Error(`Error in provided version - ${name} (${version})`);
             }
-            if (version === 'stable') {
+            if (version === "stable") {
                 versionToLoad = WebXRFeaturesManager.GetStableVersionOfFeature(name);
-            } else if (version === 'latest') {
+            } else if (version === "latest") {
                 versionToLoad = WebXRFeaturesManager.GetLatestVersionOfFeature(name);
             } else {
                 // try loading the number the string represents
@@ -294,7 +294,7 @@ export class WebXRFeaturesManager implements IDisposable {
         this._features[name] = {
             featureImplementation: constructFunction(),
             enabled: true,
-            version: versionToLoad
+            version: versionToLoad,
         };
 
         if (attachIfPossible) {
@@ -327,4 +327,4 @@ export class WebXRFeaturesManager implements IDisposable {
     public getEnabledFeatures() {
         return Object.keys(this._features);
     }
-}
+}

+ 15 - 9
src/XR/webXRInput.ts

@@ -1,10 +1,10 @@
 import { Nullable } from "../types";
 import { Observer, Observable } from "../Misc/observable";
 import { IDisposable } from "../scene";
-import { WebXRInputSource, IWebXRControllerOptions } from './webXRInputSource';
-import { WebXRSessionManager } from './webXRSessionManager';
-import { WebXRCamera } from './webXRCamera';
-import { WebXRMotionControllerManager } from './motionController/webXRMotionControllerManager';
+import { WebXRInputSource, IWebXRControllerOptions } from "./webXRInputSource";
+import { WebXRSessionManager } from "./webXRSessionManager";
+import { WebXRCamera } from "./webXRCamera";
+import { WebXRMotionControllerManager } from "./motionController/webXRMotionControllerManager";
 
 /**
  * The schema for initialization options of the XR Input class
@@ -83,7 +83,12 @@ export class WebXRInput implements IDisposable {
     ) {
         // Remove controllers when exiting XR
         this._sessionEndedObserver = this.xrSessionManager.onXRSessionEnded.add(() => {
-            this._addAndRemoveControllers([], this.controllers.map((c) => { return c.inputSource; }));
+            this._addAndRemoveControllers(
+                [],
+                this.controllers.map((c) => {
+                    return c.inputSource;
+                })
+            );
         });
 
         this._sessionInitObserver = this.xrSessionManager.onXRSessionInit.add((session) => {
@@ -112,18 +117,20 @@ export class WebXRInput implements IDisposable {
 
     private _onInputSourcesChange = (event: XRInputSourceChangeEvent) => {
         this._addAndRemoveControllers(event.added, event.removed);
-    }
+    };
 
     private _addAndRemoveControllers(addInputs: Array<XRInputSource>, removeInputs: Array<XRInputSource>) {
         // Add controllers if they don't already exist
-        let sources = this.controllers.map((c) => { return c.inputSource; });
+        let sources = this.controllers.map((c) => {
+            return c.inputSource;
+        });
         for (let input of addInputs) {
             if (sources.indexOf(input) === -1) {
                 let controller = new WebXRInputSource(this.xrSessionManager.scene, input, {
                     ...(this.options.controllerOptions || {}),
                     forceControllerProfile: this.options.forceInputProfile,
                     doNotLoadControllerMesh: this.options.doNotLoadControllerMeshes,
-                    disableMotionControllerAnimation: this.options.disableControllerAnimation
+                    disableMotionControllerAnimation: this.options.disableControllerAnimation,
                 });
                 this.controllers.push(controller);
                 this.onControllerAddedObservable.notifyObservers(controller);
@@ -145,7 +152,6 @@ export class WebXRInput implements IDisposable {
             this.onControllerRemovedObservable.notifyObservers(c);
             c.dispose();
         });
-
     }
 
     /**

+ 33 - 33
src/XR/webXRInputSource.ts

@@ -1,11 +1,11 @@
 import { Observable } from "../Misc/observable";
 import { AbstractMesh } from "../Meshes/abstractMesh";
-import { Quaternion, Vector3 } from '../Maths/math.vector';
-import { Ray } from '../Culling/ray';
-import { Scene } from '../scene';
-import { WebXRAbstractMotionController } from './motionController/webXRAbstractMotionController';
-import { WebXRMotionControllerManager } from './motionController/webXRMotionControllerManager';
-import { Tools } from '../Misc/tools';
+import { Quaternion, Vector3 } from "../Maths/math.vector";
+import { Ray } from "../Culling/ray";
+import { Scene } from "../scene";
+import { WebXRAbstractMotionController } from "./motionController/webXRAbstractMotionController";
+import { WebXRMotionControllerManager } from "./motionController/webXRMotionControllerManager";
+import { Tools } from "../Misc/tools";
 
 let idCount = 0;
 
@@ -83,7 +83,8 @@ export class WebXRInputSource {
         private _scene: Scene,
         /** The underlying input source for the controller  */
         public inputSource: XRInputSource,
-        private _options: IWebXRControllerOptions = {}) {
+        private _options: IWebXRControllerOptions = {}
+    ) {
         this._uniqueId = `controller-${idCount++}-${inputSource.targetRayMode}-${inputSource.handedness}`;
 
         this.pointer = new AbstractMesh(`${this._uniqueId}-pointer`, _scene);
@@ -94,31 +95,34 @@ export class WebXRInputSource {
             this.grip.rotationQuaternion = new Quaternion();
         }
 
-        this._tmpVector.set(0, 0, (this._scene.useRightHandedSystem ? -1.0 : 1.0));
+        this._tmpVector.set(0, 0, this._scene.useRightHandedSystem ? -1.0 : 1.0);
 
         // for now only load motion controllers if gamepad object available
         if (this.inputSource.gamepad) {
-            WebXRMotionControllerManager.GetMotionControllerWithXRInput(inputSource, _scene, this._options.forceControllerProfile).then((motionController) => {
-                this.motionController = motionController;
-                this.onMotionControllerInitObservable.notifyObservers(motionController);
-                // should the model be loaded?
-                if (!this._options.doNotLoadControllerMesh) {
-                    this.motionController.loadModel().then((success) => {
-                        if (success && this.motionController && this.motionController.rootMesh) {
-                            if (this._options.renderingGroupId) {
-                                // anything other than 0?
-                                this.motionController.rootMesh.renderingGroupId = this._options.renderingGroupId;
-                                this.motionController.rootMesh.getChildMeshes(false).forEach((mesh) => mesh.renderingGroupId = this._options.renderingGroupId!);
+            WebXRMotionControllerManager.GetMotionControllerWithXRInput(inputSource, _scene, this._options.forceControllerProfile).then(
+                (motionController) => {
+                    this.motionController = motionController;
+                    this.onMotionControllerInitObservable.notifyObservers(motionController);
+                    // should the model be loaded?
+                    if (!this._options.doNotLoadControllerMesh) {
+                        this.motionController.loadModel().then((success) => {
+                            if (success && this.motionController && this.motionController.rootMesh) {
+                                if (this._options.renderingGroupId) {
+                                    // anything other than 0?
+                                    this.motionController.rootMesh.renderingGroupId = this._options.renderingGroupId;
+                                    this.motionController.rootMesh.getChildMeshes(false).forEach((mesh) => (mesh.renderingGroupId = this._options.renderingGroupId!));
+                                }
+                                this.onMeshLoadedObservable.notifyObservers(this.motionController.rootMesh);
+                                this.motionController.rootMesh.parent = this.grip || this.pointer;
+                                this.motionController.disableAnimation = !!this._options.disableMotionControllerAnimation;
                             }
-                            this.onMeshLoadedObservable.notifyObservers(this.motionController.rootMesh);
-                            this.motionController.rootMesh.parent = this.grip || this.pointer;
-                            this.motionController.disableAnimation = !!this._options.disableMotionControllerAnimation;
-                        }
-                    });
+                        });
+                    }
+                },
+                () => {
+                    Tools.Warn(`Could not find a matching motion controller for the registered input source`);
                 }
-            }, () => {
-                Tools.Warn(`Could not find a matching motion controller for the registered input source`);
-            });
+            );
         }
     }
 
@@ -153,11 +157,7 @@ export class WebXRInputSource {
      */
     public getWorldPointerRayToRef(result: Ray, gripIfAvailable: boolean = false) {
         const object = gripIfAvailable && this.grip ? this.grip : this.pointer;
-        Vector3.TransformNormalToRef(
-            this._tmpVector,
-            object.getWorldMatrix(),
-            result.direction
-        );
+        Vector3.TransformNormalToRef(this._tmpVector, object.getWorldMatrix(), result.direction);
         result.direction.normalize();
         result.origin.copyFrom(object.absolutePosition);
         result.length = 1000;
@@ -204,4 +204,4 @@ export class WebXRInputSource {
             this.motionController.updateFromXRFrame(xrFrame);
         }
     }
-}
+}

+ 15 - 16
src/XR/webXRManagedOutputCanvas.ts

@@ -1,8 +1,8 @@
 import { Nullable } from "../types";
-import { ThinEngine } from '../Engines/thinEngine';
+import { ThinEngine } from "../Engines/thinEngine";
 import { WebXRRenderTarget } from "./webXRTypes";
-import { WebXRSessionManager } from './webXRSessionManager';
-import { Observable } from '../Misc/observable';
+import { WebXRSessionManager } from "./webXRSessionManager";
+import { Observable } from "../Misc/observable";
 
 /**
  * COnfiguration object for WebXR output canvas
@@ -34,7 +34,7 @@ export class WebXRManagedOutputCanvasOptions {
             stencil: false,
             alpha: true,
             multiview: false,
-            framebufferScaleFactor: 1
+            framebufferScaleFactor: 1,
         };
 
         defaults.newCanvasCssStyle = "position:absolute; bottom:0px;right:0px;z-index:10;width:90%;height:100%;background-color: #000000;";
@@ -49,8 +49,8 @@ export class WebXRManagedOutputCanvas implements WebXRRenderTarget {
     private _canvas: Nullable<HTMLCanvasElement> = null;
     private _engine: ThinEngine;
     private _originalCanvasSize: {
-        width: number,
-        height: number
+        width: number;
+        height: number;
     };
 
     /**
@@ -75,7 +75,7 @@ export class WebXRManagedOutputCanvas implements WebXRRenderTarget {
     constructor(_xrSessionManager: WebXRSessionManager, private _options: WebXRManagedOutputCanvasOptions = WebXRManagedOutputCanvasOptions.GetDefaults()) {
         this._engine = _xrSessionManager.scene.getEngine();
         if (!_options.canvasElement) {
-            const canvas = document.createElement('canvas');
+            const canvas = document.createElement("canvas");
             canvas.style.cssText = this._options.newCanvasCssStyle || "position:absolute; bottom:0px;right:0px;";
             this._setManagedOutputCanvas(canvas);
         } else {
@@ -134,7 +134,6 @@ export class WebXRManagedOutputCanvas implements WebXRRenderTarget {
                 this._setCanvasSize(true, layer);
             });
         }
-
     }
 
     private _removeCanvas() {
@@ -151,8 +150,8 @@ export class WebXRManagedOutputCanvas implements WebXRRenderTarget {
         if (init) {
             if (xrLayer) {
                 if (this._canvas !== this._engine.getRenderingCanvas()) {
-                    this._canvas.style.width = xrLayer.framebufferWidth + 'px';
-                    this._canvas.style.height = xrLayer.framebufferHeight + 'px';
+                    this._canvas.style.width = xrLayer.framebufferWidth + "px";
+                    this._canvas.style.height = xrLayer.framebufferHeight + "px";
                 } else {
                     this._engine.setSize(xrLayer.framebufferWidth, xrLayer.framebufferHeight);
                 }
@@ -160,8 +159,8 @@ export class WebXRManagedOutputCanvas implements WebXRRenderTarget {
         } else {
             if (this._originalCanvasSize) {
                 if (this._canvas !== this._engine.getRenderingCanvas()) {
-                    this._canvas.style.width = this._originalCanvasSize.width + 'px';
-                    this._canvas.style.height = this._originalCanvasSize.height + 'px';
+                    this._canvas.style.width = this._originalCanvasSize.width + "px";
+                    this._canvas.style.height = this._originalCanvasSize.height + "px";
                 } else {
                     this._engine.setSize(this._originalCanvasSize.width, this._originalCanvasSize.height);
                 }
@@ -177,13 +176,13 @@ export class WebXRManagedOutputCanvas implements WebXRRenderTarget {
         } else {
             this._originalCanvasSize = {
                 width: canvas.offsetWidth,
-                height: canvas.offsetHeight
+                height: canvas.offsetHeight,
             };
             this._canvas = canvas;
-            this.canvasContext = <any>this._canvas.getContext('webgl2');
+            this.canvasContext = <any>this._canvas.getContext("webgl2");
             if (!this.canvasContext) {
-                this.canvasContext = <any>this._canvas.getContext('webgl');
+                this.canvasContext = <any>this._canvas.getContext("webgl");
             }
         }
     }
-}
+}

+ 72 - 56
src/XR/webXRSessionManager.ts

@@ -4,8 +4,8 @@ import { Nullable } from "../types";
 import { IDisposable, Scene } from "../scene";
 import { InternalTexture, InternalTextureSource } from "../Materials/Textures/internalTexture";
 import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
-import { WebXRRenderTarget } from './webXRTypes';
-import { WebXRManagedOutputCanvas, WebXRManagedOutputCanvasOptions } from './webXRManagedOutputCanvas';
+import { WebXRRenderTarget } from "./webXRTypes";
+import { WebXRManagedOutputCanvas, WebXRManagedOutputCanvasOptions } from "./webXRManagedOutputCanvas";
 
 interface IRenderTargetProvider {
     getRenderTargetForEye(eye: XREye): RenderTargetTexture;
@@ -71,8 +71,7 @@ export class WebXRSessionManager implements IDisposable {
     constructor(
         /** The scene which the session should be created for */
         public scene: Scene
-    ) {
-    }
+    ) {}
 
     /**
      * The current reference space used in this session. This reference space can constantly change!
@@ -136,8 +135,7 @@ export class WebXRSessionManager implements IDisposable {
         const engine = this.scene.getEngine();
         if (this._xrNavigator.xr.native) {
             return this._xrNavigator.xr.getWebXRRenderTarget(engine);
-        }
-        else {
+        } else {
             options = options || {};
             options.canvasElement = engine.getRenderingCanvas() || undefined;
             return new WebXRManagedOutputCanvas(this, options);
@@ -164,29 +162,33 @@ export class WebXRSessionManager implements IDisposable {
      * @param xrSessionInit defines optional and required values to pass to the session builder
      * @returns a promise which will resolve once the session has been initialized
      */
-    public initializeSessionAsync(xrSessionMode: XRSessionMode = 'immersive-vr', xrSessionInit: XRSessionInit = {}): Promise<XRSession> {
+    public initializeSessionAsync(xrSessionMode: XRSessionMode = "immersive-vr", xrSessionInit: XRSessionInit = {}): Promise<XRSession> {
         return this._xrNavigator.xr.requestSession(xrSessionMode, xrSessionInit).then((session: XRSession) => {
             this.session = session;
             this.onXRSessionInit.notifyObservers(session);
             this._sessionEnded = false;
 
             // handle when the session is ended (By calling session.end or device ends its own session eg. pressing home button on phone)
-            this.session.addEventListener("end", () => {
-                const engine = this.scene.getEngine();
-                this._sessionEnded = true;
-                // Remove render target texture and notify frame observers
-                this._rttProvider = null;
-                // make sure dimensions object is restored
-                engine.framebufferDimensionsObject = null;
+            this.session.addEventListener(
+                "end",
+                () => {
+                    const engine = this.scene.getEngine();
+                    this._sessionEnded = true;
+                    // Remove render target texture and notify frame observers
+                    this._rttProvider = null;
+                    // make sure dimensions object is restored
+                    engine.framebufferDimensionsObject = null;
 
-                // Restore frame buffer to avoid clear on xr framebuffer after session end
-                engine.restoreDefaultFramebuffer();
+                    // Restore frame buffer to avoid clear on xr framebuffer after session end
+                    engine.restoreDefaultFramebuffer();
 
-                // Need to restart render loop as after the session is ended the last request for new frame will never call callback
-                engine.customAnimationFrameRequester = null;
-                this.onXRSessionEnded.notifyObservers(null);
-                engine._renderLoop();
-            }, { once: true });
+                    // Need to restart render loop as after the session is ended the last request for new frame will never call callback
+                    engine.customAnimationFrameRequester = null;
+                    this.onXRSessionEnded.notifyObservers(null);
+                    engine._renderLoop();
+                },
+                { once: true }
+            );
             return this.session;
         });
     }
@@ -228,7 +230,7 @@ export class WebXRSessionManager implements IDisposable {
                     engine._renderLoop();
                     engine.framebufferDimensionsObject = null;
                 }
-            }
+            },
         };
 
         if (this._xrNavigator.xr.native) {
@@ -241,7 +243,9 @@ export class WebXRSessionManager implements IDisposable {
         }
 
         // Stop window's animation frame and trigger sessions animation frame
-        if (window.cancelAnimationFrame) { window.cancelAnimationFrame(engine._frameHandler); }
+        if (window.cancelAnimationFrame) {
+            window.cancelAnimationFrame(engine._frameHandler);
+        }
         engine._renderLoop();
     }
 
@@ -251,31 +255,41 @@ export class WebXRSessionManager implements IDisposable {
      * @returns a promise that will resolve once the reference space has been set
      */
     public setReferenceSpaceTypeAsync(referenceSpaceType: XRReferenceSpaceType = "local-floor"): Promise<XRReferenceSpace> {
-        return this.session.requestReferenceSpace(referenceSpaceType).then((referenceSpace: XRReferenceSpace) => {
-            return referenceSpace;
-        }, (rejectionReason) => {
-            Logger.Error("XR.requestReferenceSpace failed for the following reason: ");
-            Logger.Error(rejectionReason);
-            Logger.Log("Defaulting to universally-supported \"viewer\" reference space type.");
+        return this.session
+            .requestReferenceSpace(referenceSpaceType)
+            .then(
+                (referenceSpace: XRReferenceSpace) => {
+                    return referenceSpace;
+                },
+                (rejectionReason) => {
+                    Logger.Error("XR.requestReferenceSpace failed for the following reason: ");
+                    Logger.Error(rejectionReason);
+                    Logger.Log('Defaulting to universally-supported "viewer" reference space type.');
 
-            return this.session.requestReferenceSpace("viewer").then((referenceSpace: XRReferenceSpace) => {
-                const heightCompensation = new XRRigidTransform({ x: 0, y: -this.defaultHeightCompensation, z: 0 });
-                return referenceSpace.getOffsetReferenceSpace(heightCompensation);
-            }, (rejectionReason) => {
-                Logger.Error(rejectionReason);
-                throw "XR initialization failed: required \"viewer\" reference space type not supported.";
-            });
-        }).then((referenceSpace) => {
-            // create viewer reference space before setting the first reference space
-            return this.session.requestReferenceSpace("viewer").then((viewerReferenceSpace: XRReferenceSpace) => {
-                this.viewerReferenceSpace = viewerReferenceSpace;
-                return referenceSpace;
+                    return this.session.requestReferenceSpace("viewer").then(
+                        (referenceSpace: XRReferenceSpace) => {
+                            const heightCompensation = new XRRigidTransform({ x: 0, y: -this.defaultHeightCompensation, z: 0 });
+                            return referenceSpace.getOffsetReferenceSpace(heightCompensation);
+                        },
+                        (rejectionReason) => {
+                            Logger.Error(rejectionReason);
+                            throw "XR initialization failed: required \"viewer\" reference space type not supported.";
+                        }
+                    );
+                }
+            )
+            .then((referenceSpace) => {
+                // create viewer reference space before setting the first reference space
+                return this.session.requestReferenceSpace("viewer").then((viewerReferenceSpace: XRReferenceSpace) => {
+                    this.viewerReferenceSpace = viewerReferenceSpace;
+                    return referenceSpace;
+                });
+            })
+            .then((referenceSpace) => {
+                // initialize the base and offset (currently the same)
+                this.referenceSpace = this.baseReferenceSpace = referenceSpace;
+                return this.referenceSpace;
             });
-        }).then((referenceSpace) => {
-            // initialize the base and offset (currently the same)
-            this.referenceSpace = this.baseReferenceSpace = referenceSpace;
-            return this.referenceSpace;
-        });
     }
 
     /**
@@ -304,13 +318,16 @@ export class WebXRSessionManager implements IDisposable {
         if (!functionToUse) {
             return Promise.resolve(false);
         } else {
-            return functionToUse.call((navigator as any).xr, sessionMode).then((result: boolean) => {
-                const returnValue = (typeof result === "undefined") ? true : result;
-                return Promise.resolve(returnValue);
-            }).catch((e: any) => {
-                Logger.Warn(e);
-                return Promise.resolve(false);
-            });
+            return functionToUse
+                .call((navigator as any).xr, sessionMode)
+                .then((result: boolean) => {
+                    const returnValue = typeof result === "undefined" ? true : result;
+                    return Promise.resolve(returnValue);
+                })
+                .catch((e: any) => {
+                    Logger.Warn(e);
+                    return Promise.resolve(false);
+                });
         }
     }
 
@@ -322,10 +339,9 @@ export class WebXRSessionManager implements IDisposable {
         internalTexture._framebuffer = framebuffer;
 
         // Create render target texture from the internal texture
-        var renderTargetTexture = new RenderTargetTexture("XR renderTargetTexture", { width: width, height: height }, this.scene,
-            undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
+        var renderTargetTexture = new RenderTargetTexture("XR renderTargetTexture", { width: width, height: height }, this.scene, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
         renderTargetTexture._texture = internalTexture;
 
         return renderTargetTexture;
     }
-}
+}

+ 3 - 3
src/XR/webXRTypes.ts

@@ -20,7 +20,7 @@ export enum WebXRState {
     /**
      * Not entered XR mode
      */
-    NOT_IN_XR
+    NOT_IN_XR,
 }
 
 /**
@@ -42,5 +42,5 @@ export interface WebXRRenderTarget extends IDisposable {
      * @param xrSession xr session
      * @returns a promise that will resolve once the XR Layer has been created
      */
-    initializeXRLayerAsync(xrSession: XRSession) : Promise<XRWebGLLayer>;
-}
+    initializeXRLayerAsync(xrSession: XRSession): Promise<XRWebGLLayer>;
+}

+ 2 - 2
tslint.json

@@ -8,8 +8,8 @@
         "new-parens": true,
         "no-consecutive-blank-lines": true,
         "no-irregular-whitespace": true,
-        "semicolon": [true, "always"],
-        "space-before-function-paren": [true, "never"],
+        "semicolon": [true, "always", "ignore-bound-class-methods"],
+        "space-before-function-paren": [false, "never"],
         "space-within-parens": true,
         "curly": true,
         "whitespace": [true,