mixedreality/com.microsoft.mixedreality..../Providers/OpenVR/GenericOpenVRController.cs

319 lines
17 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Input.UnityInput;
using Microsoft.MixedReality.Toolkit.Utilities;
using System;
using System.Collections.Generic;
using Unity.Profiling;
using UnityEngine;
using UnityEngine.XR;
namespace Microsoft.MixedReality.Toolkit.OpenVR.Input
{
[MixedRealityController(
SupportedControllerType.GenericOpenVR,
new[] { Handedness.Left, Handedness.Right },
flags: MixedRealityControllerConfigurationFlags.UseCustomInteractionMappings,
supportedUnityXRPipelines: SupportedUnityXRPipelines.LegacyXR)]
public class GenericOpenVRController : GenericJoystickController
{
public GenericOpenVRController(
TrackingState trackingState,
Handedness controllerHandedness,
IMixedRealityInputSource inputSource = null,
MixedRealityInteractionMapping[] interactions = null)
: this(trackingState, controllerHandedness, new GenericOpenVRControllerDefinition(controllerHandedness), inputSource, interactions)
{ }
public GenericOpenVRController(
TrackingState trackingState,
Handedness controllerHandedness,
IMixedRealityInputSourceDefinition definition,
IMixedRealityInputSource inputSource = null,
MixedRealityInteractionMapping[] interactions = null)
: base(trackingState, controllerHandedness, definition, inputSource, interactions)
{
nodeType = controllerHandedness == Handedness.Left ? XRNode.LeftHand : XRNode.RightHand;
}
private readonly XRNode nodeType;
/// <summary>
/// The current source state reading for this OpenVR Controller.
/// </summary>
public XRNodeState LastXrNodeStateReading { get; protected set; }
/// <summary>
/// Tracking states returned from the InputTracking state tracking manager.
/// </summary>
private readonly List<XRNodeState> nodeStates = new List<XRNodeState>();
/// <summary>
/// A private static list of previously loaded controller models.
/// </summary>
private static readonly Dictionary<Handedness, GameObject> controllerDictionary = new Dictionary<Handedness, GameObject>(0);
protected override MixedRealityInteractionMappingLegacyInput[] LeftHandedLegacyInputSupport => new[]
{
// Controller Pose
new MixedRealityInteractionMappingLegacyInput(),
// HTC Vive Controller - Left Controller Trigger (7) Squeeze
// Oculus Touch Controller - Axis1D.PrimaryIndexTrigger Squeeze
// Valve Knuckles Controller - Left Controller Trigger Squeeze
// Windows Mixed Reality Controller - Left Trigger Squeeze
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_9),
// HTC Vive Controller - Left Controller Trigger (7)
// Oculus Touch Controller - Axis1D.PrimaryIndexTrigger
// Valve Knuckles Controller - Left Controller Trigger
// Windows Mixed Reality Controller - Left Trigger Press (Select)
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton14),
// HTC Vive Controller - Left Controller Trigger (7)
// Oculus Touch Controller - Axis1D.PrimaryIndexTrigger
// Valve Knuckles Controller - Left Controller Trigger
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_9),
// HTC Vive Controller - Left Controller Grip Button (8)
// Oculus Touch Controller - Axis1D.PrimaryHandTrigger
// Valve Knuckles Controller - Left Controller Grip Average
// Windows Mixed Reality Controller - Left Grip Button Press
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_11),
// HTC Vive Controller - Left Controller Trackpad (2)
// Oculus Touch Controller - Axis2D.PrimaryThumbstick
// Valve Knuckles Controller - Left Controller Trackpad
// Windows Mixed Reality Controller - Left Thumbstick Position
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_1, axisCodeY: ControllerMappingLibrary.AXIS_2, invertYAxis: true),
// HTC Vive Controller - Left Controller Trackpad (2)
// Oculus Touch Controller - Button.PrimaryThumbstick
// Valve Knuckles Controller - Left Controller Trackpad
// Windows Mixed Reality Controller - Left Touchpad Touch
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton16),
// HTC Vive Controller - Left Controller Trackpad (2)
// Oculus Touch Controller - Button.PrimaryThumbstick
// Valve Knuckles Controller - Left Controller Trackpad
// Windows Mixed Reality Controller - Left Thumbstick Press
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton8),
// HTC Vive Controller - Left Controller Menu Button (1)
// Oculus Touch Controller - Button.Three Press
// Valve Knuckles Controller - Left Controller Inner Face Button
// Windows Mixed Reality Controller - Left Menu Button
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton2),
// Oculus Touch Controller - Button.Four Press
// Valve Knuckles Controller - Left Controller Outer Face Button
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton3),
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton18),
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_17, axisCodeY: ControllerMappingLibrary.AXIS_18),
new MixedRealityInteractionMappingLegacyInput(),
};
protected override MixedRealityInteractionMappingLegacyInput[] RightHandedLegacyInputSupport => new[]
{
// Controller Pose
new MixedRealityInteractionMappingLegacyInput(),
// HTC Vive Controller - Right Controller Trigger (7) Squeeze
// Oculus Touch Controller - Axis1D.SecondaryIndexTrigger Squeeze
// Valve Knuckles Controller - Right Controller Trigger Squeeze
// Windows Mixed Reality Controller - Right Trigger Squeeze
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_10),
// HTC Vive Controller - Right Controller Trigger (7)
// Oculus Touch Controller - Axis1D.SecondaryIndexTrigger
// Valve Knuckles Controller - Right Controller Trigger
// Windows Mixed Reality Controller - Right Trigger Press (Select)
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton15),
// HTC Vive Controller - Right Controller Trigger (7)
// Oculus Touch Controller - Axis1D.SecondaryIndexTrigger
// Valve Knuckles Controller - Right Controller Trigger
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_10),
// HTC Vive Controller - Right Controller Grip Button (8)
// Oculus Touch Controller - Axis1D.SecondaryHandTrigger
// Valve Knuckles Controller - Right Controller Grip Average
// Windows Mixed Reality Controller - Right Grip Button Press
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_12),
// HTC Vive Controller - Right Controller Trackpad (2)
// Oculus Touch Controller - Axis2D.PrimaryThumbstick
// Valve Knuckles Controller - Right Controller Trackpad
// Windows Mixed Reality Controller - Right Thumbstick Position
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_4, axisCodeY: ControllerMappingLibrary.AXIS_5, invertYAxis: true),
// HTC Vive Controller - Right Controller Trackpad (2)
// Oculus Touch Controller - Button.SecondaryThumbstick
// Valve Knuckles Controller - Right Controller Trackpad
// Windows Mixed Reality Controller - Right Touchpad Touch
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton17),
// HTC Vive Controller - Right Controller Trackpad (2)
// Oculus Touch Controller - Button.SecondaryThumbstick
// Valve Knuckles Controller - Right Controller Trackpad
// Windows Mixed Reality Controller - Right Thumbstick Press
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton9),
// HTC Vive Controller - Right Controller Menu Button (1)
// Oculus Remote - Button.One Press
// Oculus Touch Controller - Button.One Press
// Valve Knuckles Controller - Right Controller Inner Face Button
// Windows Mixed Reality Controller - Right Menu Button
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton0),
// Oculus Remote - Button.Two Press
// Oculus Touch Controller - Button.Two Press
// Valve Knuckles Controller - Right Controller Outer Face Button
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton1),
new MixedRealityInteractionMappingLegacyInput(keyCode: KeyCode.JoystickButton19),
new MixedRealityInteractionMappingLegacyInput(axisCodeX: ControllerMappingLibrary.AXIS_19, axisCodeY: ControllerMappingLibrary.AXIS_20),
new MixedRealityInteractionMappingLegacyInput(),
};
private static readonly ProfilerMarker UpdateControllerPerfMarker = new ProfilerMarker("[MRTK] GenericOpenVRController.UpdateController");
/// <inheritdoc />
public override void UpdateController()
{
using (UpdateControllerPerfMarker.Auto())
{
if (!Enabled) { return; }
InputTracking.GetNodeStates(nodeStates);
for (int i = 0; i < nodeStates.Count; i++)
{
if (nodeStates[i].nodeType == nodeType)
{
var xrNodeState = nodeStates[i];
UpdateControllerData(xrNodeState);
LastXrNodeStateReading = xrNodeState;
break;
}
}
base.UpdateController();
}
}
private static readonly ProfilerMarker UpdateControllerDataPerfMarker = new ProfilerMarker("[MRTK] GenericOpenVRController.UpdateControllerData");
/// <summary>
/// Update the "Controller" input from the device
/// </summary>
protected void UpdateControllerData(XRNodeState state)
{
using (UpdateControllerDataPerfMarker.Auto())
{
var lastState = TrackingState;
LastControllerPose = CurrentControllerPose;
if (nodeType == XRNode.LeftHand || nodeType == XRNode.RightHand)
{
// The source is either a hand or a controller that supports pointing.
// We can now check for position and rotation.
IsPositionAvailable = state.TryGetPosition(out CurrentControllerPosition);
IsPositionApproximate = false;
IsRotationAvailable = state.TryGetRotation(out CurrentControllerRotation);
// Devices are considered tracked if we receive position OR rotation data from the sensors.
TrackingState = (IsPositionAvailable || IsRotationAvailable) ? TrackingState.Tracked : TrackingState.NotTracked;
CurrentControllerPosition = MixedRealityPlayspace.TransformPoint(CurrentControllerPosition);
CurrentControllerRotation = MixedRealityPlayspace.Rotation * CurrentControllerRotation;
}
else
{
// The input source does not support tracking.
TrackingState = TrackingState.NotApplicable;
}
CurrentControllerPose.Position = CurrentControllerPosition;
CurrentControllerPose.Rotation = CurrentControllerRotation;
// Raise input system events if it is enabled.
if (lastState != TrackingState)
{
CoreServices.InputSystem?.RaiseSourceTrackingStateChanged(InputSource, this, TrackingState);
}
if (TrackingState == TrackingState.Tracked && LastControllerPose != CurrentControllerPose)
{
if (IsPositionAvailable && IsRotationAvailable)
{
CoreServices.InputSystem?.RaiseSourcePoseChanged(InputSource, this, CurrentControllerPose);
}
else if (IsPositionAvailable && !IsRotationAvailable)
{
CoreServices.InputSystem?.RaiseSourcePositionChanged(InputSource, this, CurrentControllerPosition);
}
else if (!IsPositionAvailable && IsRotationAvailable)
{
CoreServices.InputSystem?.RaiseSourceRotationChanged(InputSource, this, CurrentControllerRotation);
}
}
}
}
#region Controller model functions
/// <inheritdoc />
protected override bool TryRenderControllerModel(Type controllerType, InputSourceType inputSourceType)
{
MixedRealityControllerVisualizationProfile visualizationProfile = GetControllerVisualizationProfile();
// Intercept this call if we are using the default driver provided models.
if (visualizationProfile == null ||
!visualizationProfile.GetUsePlatformModelsOverride(GetType(), ControllerHandedness))
{
return base.TryRenderControllerModel(controllerType, inputSourceType);
}
else if (controllerDictionary.TryGetValue(ControllerHandedness, out GameObject controllerModel))
{
TryAddControllerModelToSceneHierarchy(controllerModel);
controllerModel.SetActive(true);
return true;
}
Debug.Log("Trying to load controller model from platform SDK");
GameObject controllerModelGameObject = new GameObject($"{ControllerHandedness} OpenVR Controller");
bool failedToObtainControllerModel;
var visualizationType = visualizationProfile.GetControllerVisualizationTypeOverride(GetType(), ControllerHandedness);
if (visualizationType != null)
{
// Set the platform controller model to not be destroyed when the source is lost. It'll be disabled instead,
// and re-enabled when the same controller is re-detected.
if (controllerModelGameObject.AddComponent(visualizationType.Type) is IMixedRealityControllerPoseSynchronizer visualizer)
{
visualizer.DestroyOnSourceLost = false;
}
OpenVRRenderModel openVRRenderModel = controllerModelGameObject.AddComponent<OpenVRRenderModel>();
Material overrideMaterial = visualizationProfile.GetPlatformModelMaterialOverride(GetType(), ControllerHandedness);
if (overrideMaterial != null)
{
openVRRenderModel.shader = overrideMaterial.shader;
}
failedToObtainControllerModel = !openVRRenderModel.LoadModel(ControllerHandedness);
if (!failedToObtainControllerModel)
{
TryAddControllerModelToSceneHierarchy(controllerModelGameObject);
controllerDictionary.Add(ControllerHandedness, controllerModelGameObject);
}
}
else
{
Debug.LogError("Controller visualization type not defined for controller visualization profile");
failedToObtainControllerModel = true;
}
if (failedToObtainControllerModel)
{
Debug.LogWarning("Failed to create controller model from driver, defaulting to BaseController behavior");
UnityEngine.Object.Destroy(controllerModelGameObject);
return base.TryRenderControllerModel(GetType(), InputSourceType.Controller);
}
return true;
}
#endregion Controller model functions
}
}