Trevor Baron %!s(int64=6) %!d(string=hai) anos
pai
achega
2dc35399c0
Modificáronse 2 ficheiros con 107 adicións e 52 borrados
  1. 90 3
      src/Cameras/XR/webXRInput.ts
  2. 17 49
      src/LibDeclarations/webxr.d.ts

+ 90 - 3
src/Cameras/XR/webXRInput.ts

@@ -1,8 +1,9 @@
 import { Nullable } from "../../types";
 import { Nullable } from "../../types";
-import { Observer } from "../../Misc/observable";
+import { Observer, Observable } from "../../Misc/observable";
 import { IDisposable, Scene } from "../../scene";
 import { IDisposable, Scene } from "../../scene";
 import { AbstractMesh } from "../../Meshes/abstractMesh";
 import { AbstractMesh } from "../../Meshes/abstractMesh";
 import { WebXRExperienceHelper } from "./webXRExperienceHelper";
 import { WebXRExperienceHelper } from "./webXRExperienceHelper";
+import { Matrix, Quaternion } from '../../Maths/math';
 /**
 /**
  * Represents an XR input
  * Represents an XR input
  */
  */
@@ -10,20 +11,54 @@ export class WebXRController {
     /**
     /**
      * Represents the part of the controller that is held. This may not exist if the controller is the head mounted display itself, if thats the case only the pointer from the head will be availible
      * Represents the part of the controller that is held. This may not exist if the controller is the head mounted display itself, if thats the case only the pointer from the head will be availible
      */
      */
-    public grip?: AbstractMesh;
+    public grip: AbstractMesh;
     /**
     /**
      * Pointer which can be used to select objects or attach a visible laser to
      * Pointer which can be used to select objects or attach a visible laser to
      */
      */
     public pointer: AbstractMesh;
     public pointer: AbstractMesh;
 
 
+    private _tmpMatrix = new Matrix();
+
     /**
     /**
      * Creates the controller
      * Creates the controller
      * @see https://doc.babylonjs.com/how_to/webxr
      * @see https://doc.babylonjs.com/how_to/webxr
      * @param scene the scene which the controller should be associated to
      * @param scene the scene which the controller should be associated to
      */
      */
-    constructor(scene: Scene) {
+    constructor(scene: Scene, public inputSource:XRInputSource, parentContainer:Nullable<AbstractMesh> = null) {
         this.pointer = new AbstractMesh("controllerPointer", scene);
         this.pointer = new AbstractMesh("controllerPointer", scene);
+        this.grip = new AbstractMesh("controllerGrip", scene);
+        if(parentContainer){
+            parentContainer.addChild(this.pointer)
+            parentContainer.addChild(this.grip)
+        }
+    }
+
+    updateFromXRFrame(xrFrame:XRFrame, xrFrameOfReference:XRReferenceSpaceType){
+        var pose = xrFrame.getPose(this.inputSource.targetRaySpace, xrFrameOfReference)
+        if(pose){
+            Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
+            if (!this.pointer.getScene().useRightHandedSystem) {
+                this._tmpMatrix.toggleModelMatrixHandInPlace();
+            }
+            if (!this.pointer.rotationQuaternion) {
+                this.pointer.rotationQuaternion = new Quaternion();
+            }
+            this._tmpMatrix.decompose(this.pointer.scaling, this.pointer.rotationQuaternion!, this.pointer.position);
+        }
+
+        var pose = xrFrame.getPose(this.inputSource.gripSpace, xrFrameOfReference)
+        if(pose){
+            Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
+            if (!this.pointer.getScene().useRightHandedSystem) {
+                this._tmpMatrix.toggleModelMatrixHandInPlace();
+            }
+            if (!this.grip.rotationQuaternion) {
+                this.grip.rotationQuaternion = new Quaternion();
+            }
+            this._tmpMatrix.decompose(this.grip.scaling, this.grip.rotationQuaternion!, this.grip.position);
+        }
     }
     }
+    
     /**
     /**
      * Disposes of the object
      * Disposes of the object
      */
      */
@@ -44,14 +79,66 @@ export class WebXRInput implements IDisposable {
      */
      */
     public controllers: Array<WebXRController> = [];
     public controllers: Array<WebXRController> = [];
     private _frameObserver: Nullable<Observer<any>>;
     private _frameObserver: Nullable<Observer<any>>;
+    public onControllerAddedObservable = new Observable<WebXRController>();
+    public onControllerRemovedObservable = new Observable<WebXRController>();
 
 
     /**
     /**
      * Initializes the WebXRInput
      * Initializes the WebXRInput
      * @param helper experience helper which the input should be created for
      * @param helper experience helper which the input should be created for
      */
      */
     public constructor(private helper: WebXRExperienceHelper) {
     public constructor(private helper: WebXRExperienceHelper) {
+        this._frameObserver = helper.sessionManager.onXRFrameObservable.add(() => {
+            if (!helper.sessionManager._currentXRFrame) {
+                return;
+            }
+
+            // Start listing to input add/remove event
+            if(this.controllers.length == 0 && helper.sessionManager._xrSession.inputSources){
+                this._addAndRemoveControllers(helper.sessionManager._xrSession.inputSources, []);
+                helper.sessionManager._xrSession.addEventListener("inputsourceschange", this._onInputSourcesChange)
+            }
+
+            // Update controller pose info
+            this.controllers.forEach((controller)=>{
+                controller.updateFromXRFrame(helper.sessionManager._currentXRFrame!, helper.sessionManager._frameOfReference)
+            })
+
+        })
+    }
+
+    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
+        var sources = this.controllers.map((c)=>{return c.inputSource});
+        addInputs.forEach((input)=>{
+            if(sources.indexOf(input) === -1){
+                var controller = new WebXRController(this.helper.camera._scene, input);
+                this.controllers.push(controller)
+                this.onControllerAddedObservable.notifyObservers(controller)
+            }
+        })
+        
+        // Remove and dispose of controllers to be disposed
+        var keepControllers: Array<WebXRController> = []
+        var removedControllers: Array<WebXRController> = []
+        this.controllers.forEach((c)=>{
+            if(removeInputs.indexOf(c.inputSource) === -1){
+                keepControllers.push(c)
+            }else{
+                removedControllers.push(c);
+            }
+        })
+        this.controllers = keepControllers;
+        removedControllers.forEach((c)=>{
+            this.onControllerRemovedObservable.notifyObservers(c);
+            c.dispose()
+        })
         
         
     }
     }
+
     /**
     /**
      * Disposes of the object
      * Disposes of the object
      */
      */

+ 17 - 49
src/LibDeclarations/webxr.d.ts

@@ -24,6 +24,15 @@ enum XRVisibilityState {
     "hidden",
     "hidden",
 };
 };
 
 
+interface XRInputSource {
+    handedness:XRHandedness;
+    targetRayMode:XRTargetRayMode;
+    targetRaySpace:XRSpace;
+    gripSpace:XRSpace?;
+    gamepad:Gamepad?;
+    profiles:FrozenArray<DOMString>;
+};
+
 interface XRSession {
 interface XRSession {
     addEventListener: Function
     addEventListener: Function
     requestReferenceSpace(type: XRReferenceSpaceType): Promise<void>;
     requestReferenceSpace(type: XRReferenceSpaceType): Promise<void>;
@@ -31,13 +40,15 @@ interface XRSession {
     requestAnimationFrame: Function;
     requestAnimationFrame: Function;
     end():Promise<void>;
     end():Promise<void>;
     renderState:XRRenderState;
     renderState:XRRenderState;
+    inputSources:Array<XRInputSource>
 
 
 
 
 };
 };
 
 
 interface XRFrame {
 interface XRFrame {
     session:XRSession
     session:XRSession
-    getViewerPose(referenceSpace:XRReferenceSpace):XRViewerPose?
+    getViewerPose(referenceSpace:XRReferenceSpace):XRViewerPose?;
+    getPose(space:XRSpace, baseSpace:XRSpace):XRPose?;
 }
 }
 
 
 interface XRViewerPose extends XRPose {
 interface XRViewerPose extends XRPose {
@@ -72,51 +83,8 @@ interface XRView {
     transform:XRRigidTransform;
     transform:XRRigidTransform;
 };
 };
 
 
-// interface XRDevice {
-//     requestSession(options: XRSessionCreationOptions): Promise<XRSession>;
-//     supportsSession(options: XRSessionCreationOptions): Promise<void>;
-// }
-// interface XRSession {
-//     getInputSources(): Array<any>;
-//     renderState: any;
-//     requestReferenceSpace(options: ReferenceSpaceOptions): Promise<void>;
-//     requestHitTest(origin: Float32Array, direction: Float32Array, frameOfReference: any): any;
-//     end(): Promise<void>;
-//     updateRenderState(state:any):Promise<void>;
-//     requestAnimationFrame: Function;
-//     addEventListener: Function;
-// }
-// interface XRSessionCreationOptions {
-//     mode?: string;
-// }
-
-
-
-// interface ReferenceSpaceOptions {
-//     type?: string;
-//     subtype?: string;
-// }
-
-// interface XRLayer {
-//     getViewport: Function;
-//     framebufferWidth: number;
-//     framebufferHeight: number;
-// }
-// interface XRView {
-//     projectionMatrix: Float32Array;
-// }
-// interface XRFrame {
-//     getViewerPose: Function;
-//     getInputPose: Function;
-//     views: Array<XRView>;
-//     baseLayer: XRLayer;
-// }
-// interface XRFrameOfReference {
-// }
-// interface XRWebGLLayer extends XRLayer {
-//     framebuffer: WebGLFramebuffer;
-// }
-// declare var XRWebGLLayer: {
-//     prototype: XRWebGLLayer;
-//     new(session: XRSession, context?: WebGLRenderingContext): XRWebGLLayer;
-// };
+interface XRInputSourceChangeEvent {
+    session:XRSession;
+    removed:Array<XRInputSource>;
+    added:Array<XRInputSource>;
+}