123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- 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
- */
- export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionController {
- // 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"
- },
- defaultAxis: {
- "valueNodeName": "VALUE",
- "minNodeName": "MIN",
- "maxNodeName": "MAX"
- },
- buttons: {
- "xr-standard-trigger": {
- "rootNodeName": "SELECT",
- "componentProperty": "button",
- "states": ["default", "touched", "pressed"]
- },
- "xr-standard-squeeze": {
- "rootNodeName": "GRASP",
- "componentProperty": "state",
- "states": ["pressed"]
- },
- "xr-standard-touchpad": {
- "rootNodeName": "TOUCHPAD_PRESS",
- "labelAnchorNodeName": "squeeze-label",
- "touchPointNodeName": "TOUCH" // TODO - use this for visual feedback
- },
- "xr-standard-thumbstick": {
- "rootNodeName": "THUMBSTICK_PRESS",
- "componentProperty": "state",
- "states": ["pressed"],
- }
- },
- axes: {
- "xr-standard-touchpad": {
- "x-axis": {
- "rootNodeName": "TOUCHPAD_TOUCH_X"
- },
- "y-axis": {
- "rootNodeName": "TOUCHPAD_TOUCH_Y"
- }
- },
- "xr-standard-thumbstick": {
- "x-axis": {
- "rootNodeName": "THUMBSTICK_X"
- },
- "y-axis": {
- "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/';
- /**
- * The name of the left controller model file
- */
- 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 profileId = "microsoft-mixed-reality";
- constructor(scene: Scene, gamepadObject: IMinimalMotionControllerObject, handedness: MotionControllerHandedness) {
- super(scene, MixedRealityProfile["left-right"], gamepadObject, handedness);
- }
- protected _getFilenameAndPath(): { filename: string; path: string; } {
- let filename = "";
- if (this.handedness === 'left') {
- filename = WebXRMicrosoftMixedRealityController.MODEL_LEFT_FILENAME;
- }
- 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 + '/';
- return {
- filename,
- path
- };
- }
- protected _getModelLoadingConstraints(): boolean {
- const glbLoaded = SceneLoader.IsPluginForExtensionAvailable(".glb");
- if (!glbLoaded) {
- Logger.Warn('glTF / glb loaded was not registered, using generic controller instead');
- }
- return glbLoaded;
- }
- protected _processLoadedModel(_meshes: AbstractMesh[]): void {
- if (!this.rootMesh) { return; }
- // Button Meshes
- this.getComponentIds().forEach((id, i) => {
- if (this.disableAnimation) {
- return;
- }
- if (id && this.rootMesh) {
- 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);
- return;
- }
- var buttonMesh = this._getChildByName(this.rootMesh, buttonMeshName);
- if (!buttonMesh) {
- Logger.Warn('Missing button mesh with name: ' + buttonMeshName);
- return;
- }
- buttonMap.valueMesh = this._getImmediateChildByName(buttonMesh, this._mapping.defaultButton.valueNodeName);
- buttonMap.pressedMesh = this._getImmediateChildByName(buttonMesh, this._mapping.defaultButton.pressedNodeName);
- buttonMap.unpressedMesh = this._getImmediateChildByName(buttonMesh, this._mapping.defaultButton.unpressedNodeName);
- 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);
- }
- } 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);
- }
- }
- });
- // Axis Meshes
- this.getComponentIds().forEach((id, i) => {
- const comp = this.getComponent(id);
- if (!comp.isAxes()) {
- return;
- }
- ["x-axis", "y-axis"].forEach((axis) => {
- 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);
- return;
- }
- axisMap.valueMesh = this._getImmediateChildByName(axisMesh, this._mapping.defaultAxis.valueNodeName);
- axisMap.minMesh = this._getImmediateChildByName(axisMesh, this._mapping.defaultAxis.minNodeName);
- axisMap.maxMesh = this._getImmediateChildByName(axisMesh, this._mapping.defaultAxis.maxNodeName);
- 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);
- }
- } 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);
- }
- });
- });
- }
- protected _setRootMesh(meshes: AbstractMesh[]): void {
- this.rootMesh = new Mesh(this.profileId + " " + this.handedness, this.scene);
- this.rootMesh.isPickable = false;
- let rootMesh;
- // Find the root node in the loaded glTF scene, and attach it as a child of 'parentMesh'
- for (let i = 0; i < meshes.length; i++) {
- let mesh = meshes[i];
- mesh.isPickable = false;
- if (!mesh.parent) {
- // Handle root node, attach to the new parentMesh
- rootMesh = mesh;
- }
- }
- if (rootMesh) {
- rootMesh.setParent(this.rootMesh);
- }
- if (!this.scene.useRightHandedSystem) {
- this.rootMesh.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);
- }
- }
- protected _updateModel(): void {
- // no-op. model is updated using observables.
- }
- }
- // register the profile
- WebXRMotionControllerManager.RegisterController("windows-mixed-reality", (xrInput: XRInputSource, scene: Scene) => {
- 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": {
- "xr-standard-trigger": {
- "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"
- }
- }
- },
- "xr-standard-squeeze": {
- "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"
- }
- }
- },
- "xr-standard-touchpad": {
- "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"
- },
- "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_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_axes_touched": {
- "componentProperty": "state",
- "states": [
- "touched",
- "pressed"
- ],
- "valueNodeProperty": "visibility",
- "valueNodeName": "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
- },
- "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_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"
- },
- "right": {
- "selectComponentId": "xr-standard-trigger",
- "components": {
- "xr-standard-trigger": {
- "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"
- }
- }
- },
- "xr-standard-squeeze": {
- "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"
- }
- }
- },
- "xr-standard-touchpad": {
- "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"
- },
- "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_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_axes_touched": {
- "componentProperty": "state",
- "states": [
- "touched",
- "pressed"
- ],
- "valueNodeProperty": "visibility",
- "valueNodeName": "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
- },
- "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_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"
- }
- };
|