|
@@ -11,7 +11,7 @@ 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
|
|
*/
|
|
*/
|
|
@@ -23,19 +23,30 @@ export class WebXRController {
|
|
* 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
|
|
|
|
+ * @param inputSource the underlying input source for the controller
|
|
|
|
+ * @param parentContainer parent that the controller meshes should be children of
|
|
*/
|
|
*/
|
|
- constructor(scene: Scene, public inputSource:XRInputSource, parentContainer:Nullable<AbstractMesh> = null) {
|
|
|
|
|
|
+ constructor(
|
|
|
|
+ private scene: Scene,
|
|
|
|
+ /** The underlying input source for the controller */
|
|
|
|
+ public inputSource: XRInputSource,
|
|
|
|
+ private 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)
|
|
|
|
|
|
+ if (parentContainer) {
|
|
|
|
+ parentContainer.addChild(this.pointer);
|
|
|
|
+
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- updateFromXRFrame(xrFrame:XRFrame, referenceSpaceType:XRReferenceSpaceType){
|
|
|
|
- var pose = xrFrame.getPose(this.inputSource.targetRaySpace, referenceSpaceType)
|
|
|
|
- if(pose){
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Updates the controller pose based on the given XRFrame
|
|
|
|
+ * @param xrFrame xr frame to update the pose with
|
|
|
|
+ * @param referenceSpace reference space to use
|
|
|
|
+ */
|
|
|
|
+ public updateFromXRFrame(xrFrame: XRFrame, referenceSpace: XRReferenceSpace) {
|
|
|
|
+ var pose = xrFrame.getPose(this.inputSource.targetRaySpace, referenceSpace);
|
|
|
|
+ if (pose) {
|
|
Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
|
|
Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
|
|
if (!this.pointer.getScene().useRightHandedSystem) {
|
|
if (!this.pointer.getScene().useRightHandedSystem) {
|
|
this._tmpMatrix.toggleModelMatrixHandInPlace();
|
|
this._tmpMatrix.toggleModelMatrixHandInPlace();
|
|
@@ -46,19 +57,29 @@ export class WebXRController {
|
|
this._tmpMatrix.decompose(this.pointer.scaling, this.pointer.rotationQuaternion!, this.pointer.position);
|
|
this._tmpMatrix.decompose(this.pointer.scaling, this.pointer.rotationQuaternion!, this.pointer.position);
|
|
}
|
|
}
|
|
|
|
|
|
- var pose = xrFrame.getPose(this.inputSource.gripSpace, referenceSpaceType)
|
|
|
|
- if(pose){
|
|
|
|
- Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
|
|
|
|
- if (!this.pointer.getScene().useRightHandedSystem) {
|
|
|
|
- this._tmpMatrix.toggleModelMatrixHandInPlace();
|
|
|
|
|
|
+ if (this.inputSource.gripSpace) {
|
|
|
|
+ if (!this.grip) {
|
|
|
|
+ this.grip = new AbstractMesh("controllerGrip", this.scene);
|
|
|
|
+ if (this.parentContainer) {
|
|
|
|
+ this.parentContainer.addChild(this.grip);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- if (!this.grip.rotationQuaternion) {
|
|
|
|
- this.grip.rotationQuaternion = new Quaternion();
|
|
|
|
|
|
+
|
|
|
|
+ var pose = xrFrame.getPose(this.inputSource.gripSpace, referenceSpace);
|
|
|
|
+ if (pose) {
|
|
|
|
+ Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
|
|
|
|
+ if (!this.grip.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);
|
|
}
|
|
}
|
|
- this._tmpMatrix.decompose(this.grip.scaling, this.grip.rotationQuaternion!, this.grip.position);
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Disposes of the object
|
|
* Disposes of the object
|
|
*/
|
|
*/
|
|
@@ -79,7 +100,13 @@ export class WebXRInput implements IDisposable {
|
|
*/
|
|
*/
|
|
public controllers: Array<WebXRController> = [];
|
|
public controllers: Array<WebXRController> = [];
|
|
private _frameObserver: Nullable<Observer<any>>;
|
|
private _frameObserver: Nullable<Observer<any>>;
|
|
|
|
+ /**
|
|
|
|
+ * Event when a controller has been connected/added
|
|
|
|
+ */
|
|
public onControllerAddedObservable = new Observable<WebXRController>();
|
|
public onControllerAddedObservable = new Observable<WebXRController>();
|
|
|
|
+ /**
|
|
|
|
+ * Event when a controller has been removed/disconnected
|
|
|
|
+ */
|
|
public onControllerRemovedObservable = new Observable<WebXRController>();
|
|
public onControllerRemovedObservable = new Observable<WebXRController>();
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -93,50 +120,50 @@ export class WebXRInput implements IDisposable {
|
|
}
|
|
}
|
|
|
|
|
|
// Start listing to input add/remove event
|
|
// Start listing to input add/remove event
|
|
- if(this.controllers.length == 0 && helper.sessionManager.session.inputSources){
|
|
|
|
|
|
+ if (this.controllers.length == 0 && helper.sessionManager.session.inputSources) {
|
|
this._addAndRemoveControllers(helper.sessionManager.session.inputSources, []);
|
|
this._addAndRemoveControllers(helper.sessionManager.session.inputSources, []);
|
|
- helper.sessionManager.session.addEventListener("inputsourceschange", this._onInputSourcesChange)
|
|
|
|
|
|
+ helper.sessionManager.session.addEventListener("inputsourceschange", this._onInputSourcesChange);
|
|
}
|
|
}
|
|
|
|
|
|
// Update controller pose info
|
|
// Update controller pose info
|
|
- this.controllers.forEach((controller)=>{
|
|
|
|
- controller.updateFromXRFrame(helper.sessionManager.currentFrame!, helper.sessionManager.referenceSpaceType)
|
|
|
|
- })
|
|
|
|
|
|
+ this.controllers.forEach((controller) => {
|
|
|
|
+ controller.updateFromXRFrame(helper.sessionManager.currentFrame!, helper.sessionManager.referenceSpace);
|
|
|
|
+ });
|
|
|
|
|
|
- })
|
|
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
- private _onInputSourcesChange = (event:XRInputSourceChangeEvent )=>{
|
|
|
|
- this._addAndRemoveControllers(event.added, event.removed)
|
|
|
|
|
|
+ private _onInputSourcesChange = (event: XRInputSourceChangeEvent) => {
|
|
|
|
+ this._addAndRemoveControllers(event.added, event.removed);
|
|
}
|
|
}
|
|
|
|
|
|
- private _addAndRemoveControllers(addInputs:Array<XRInputSource>, removeInputs:Array<XRInputSource>){
|
|
|
|
|
|
+ private _addAndRemoveControllers(addInputs: Array<XRInputSource>, removeInputs: Array<XRInputSource>) {
|
|
// Add controllers if they don't already exist
|
|
// 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 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.helper.container);
|
|
var controller = new WebXRController(this.helper.camera._scene, input, this.helper.container);
|
|
- this.controllers.push(controller)
|
|
|
|
- this.onControllerAddedObservable.notifyObservers(controller)
|
|
|
|
|
|
+ this.controllers.push(controller);
|
|
|
|
+ this.onControllerAddedObservable.notifyObservers(controller);
|
|
}
|
|
}
|
|
- })
|
|
|
|
-
|
|
|
|
|
|
+ });
|
|
|
|
+
|
|
// Remove and dispose of controllers to be disposed
|
|
// 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{
|
|
|
|
|
|
+ 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);
|
|
removedControllers.push(c);
|
|
}
|
|
}
|
|
- })
|
|
|
|
|
|
+ });
|
|
this.controllers = keepControllers;
|
|
this.controllers = keepControllers;
|
|
- removedControllers.forEach((c)=>{
|
|
|
|
|
|
+ removedControllers.forEach((c) => {
|
|
this.onControllerRemovedObservable.notifyObservers(c);
|
|
this.onControllerRemovedObservable.notifyObservers(c);
|
|
- c.dispose()
|
|
|
|
- })
|
|
|
|
-
|
|
|
|
|
|
+ c.dispose();
|
|
|
|
+ });
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|