Add ultimate xr

This commit is contained in:
2024-08-06 21:58:35 +02:00
parent 864033bf10
commit 7165bacd9d
3952 changed files with 2162037 additions and 35 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 32f22795408987f42bb073e358835363
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHpReverbG2Input.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Devices.Integrations.Microsoft;
namespace UltimateXR.Devices.Integrations.HP
{
/// <summary>
/// HP Reverb G2 Input.
/// </summary>
public class UxrHpReverbG2Input : UxrWindowsMixedRealityInput
{
#region Public Overrides UxrWindowsMixedRealityInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "HP Reverb G2 Controller";
yield return "HP Reverb G2 Controller OpenXR";
}
}
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Joystick2 |
UxrControllerElements.Grip |
UxrControllerElements.Trigger |
UxrControllerElements.Button1 |
UxrControllerElements.Button2 |
UxrControllerElements.Menu |
UxrControllerElements.DPad);
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: cd7aa825077847641b535866ae4258b9
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHpReverbG2Tracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Devices.Integrations.Microsoft;
namespace UltimateXR.Devices.Integrations.HP
{
/// <summary>
/// Tracking component for HP Reverb G2.
/// </summary>
public class UxrHpReverbG2Tracking : UxrWindowsMixedRealityTracking
{
#region Public Overrides UxrWindowsMixedRealityTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrHpReverbG2Input);
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 85e5b3a94d5599c4982fe887142e1201
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e7ef432f4a08f6348b5b1e4e3ca778e4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHtcViveCosmosInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.HTC
{
/// <summary>
/// HTC Vive Cosmos controllers input using SteamVR.
/// </summary>
public class UxrHtcViveCosmosInput : UxrSteamVRControllerInput
{
#region Public Overrides UxrSteamVRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get { yield return ControllerNameHtcViveCosmos; }
}
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick | // Joystick
UxrControllerElements.Grip | // Grip
UxrControllerElements.Bumper | // Bumper
UxrControllerElements.Trigger | // Trigger
UxrControllerElements.Button1 | // Button A/X
UxrControllerElements.Button2 | // Button B/Y
UxrControllerElements.DPad); // Joystick
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return UxrControllerInputCapabilities.HapticImpulses;
}
#endregion
#region Private Types & Data
private const string ControllerNameHtcViveCosmos = "vive_cosmos_controller";
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: aeb548548ec3cdb489de559527782aee
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHtcViveCosmosTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.HTC
{
/// <summary>
/// Tracking for HTC Vive Cosmos controllers using SteamVR SDK.
/// </summary>
public class UxrHtcViveCosmosTracking : UxrSteamVRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrHtcViveCosmosInput);
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7aaab42f00bf7ad4bb5388a08c575a4d
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,85 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHtcViveFocus3Input.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.HTC
{
/// <summary>
/// HTC Vive Focus 3 controller input using WaveXR SDK's UnityXR support.
/// </summary>
public class UxrHtcViveFocus3Input : UxrUnityXRControllerInput
{
#region Public Overrides UxrControllerInput
/// <summary>
/// Gets the SDK dependency: Wave XR.
/// </summary>
public override string SDKDependency => UxrConstants.SdkWaveXR;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Grip |
UxrControllerElements.Trigger |
UxrControllerElements.Button1 |
UxrControllerElements.Button2 |
UxrControllerElements.Menu |
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Right)
{
// Remove menu button from right controller, which is reserved.
validElements = validElements & ~(uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
#region Public Overrides UxrUnityXRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "WVR_CR_Left_001";
yield return "WVR_CR_Right_001";
}
}
#endregion
#region Protected Overrides UxrUnityXRControllerInput
/// <inheritdoc />
protected override void UpdateInput()
{
base.UpdateInput();
// To avoid grip requiring to press the whole button, we use the analog value and a threshold
float gripThreshold = 0.7f;
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Grip, GetInput1D(UxrHandSide.Left, UxrInput1D.Grip) > gripThreshold);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Grip, GetInput1D(UxrHandSide.Right, UxrInput1D.Grip) > gripThreshold);
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99f34313b313be54fa63910a496c06a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHtcViveFocus3Tracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.HTC
{
/// <summary>
/// Tracking for HTC Vive Focus 3 controllers using WaveXR SDK's UnityXR support.
/// </summary>
public class UxrHtcViveFocus3Tracking : UxrUnityXRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrHtcViveFocus3Input);
#endregion
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkWaveXR;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 74d5790b838df3441b94784597d32e7a
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHtcViveInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.HTC
{
/// <summary>
/// HTC Vive controllers input using SteamVR.
/// </summary>
public class UxrHtcViveInput : UxrSteamVRControllerInput
{
#region Public Overrides UxrSteamVRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "controller_vive";
yield return "Vive. Controller MV";
yield return "Vive. Controller Pro MV";
yield return "VIVE Controller MV";
yield return "VIVE Controller Pro MV";
}
}
/// <inheritdoc />
public override float GetInput1D(UxrHandSide handSide, UxrInput1D input1D, bool getIgnoredInput = false)
{
// Since Vive controllers don't have an analog grip button, make sure the analog
// grip functionality is supported.
if (input1D == UxrInput1D.Grip)
{
return GetButtonsPress(handSide, UxrInputButtons.Grip, getIgnoredInput) ? 1.0f : 0.0f;
}
return 0.0f;
}
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => true;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick | // Joystick
UxrControllerElements.Grip | // Grip
UxrControllerElements.Trigger | // Trigger
UxrControllerElements.Button1 | // Button A,
UxrControllerElements.Button2 |
UxrControllerElements.Menu |
UxrControllerElements.DPad); // Joystick
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return UxrControllerInputCapabilities.HapticImpulses;
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9ab26074711a00449bb89e018281422d
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHtcViveTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.HTC
{
/// <summary>
/// Tracking for HTC Vive controllers using SteamVR SDK.
/// </summary>
public class UxrHtcViveTracking : UxrSteamVRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrHtcViveInput);
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f9f613010cce8f0408243773fe913d9f
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 570a4a7e3a0905c42a29df863535996b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,126 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMagicLeap2Input.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.MagicLeap
{
/// <summary>
/// Magic Leap 2 controller input using Magic Leap SDK.
/// </summary>
public class UxrMagicLeap2Input : UxrUnityXRControllerInput
{
#region Public Overrides UxrControllerInput
/// <summary>
/// Gets the SDK dependency: Magic Leap 2.
/// </summary>
public override string SDKDependency => UxrConstants.SdkMagicLeap;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => true;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Trigger |
UxrControllerElements.Grip |
UxrControllerElements.Bumper |
UxrControllerElements.Menu |
UxrControllerElements.DPad);
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
#region Public Overrides UxrUnityXRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get { yield return "MagicLeap Controller"; }
}
#endregion
#region Event Trigger Methods
/// <inheritdoc />
protected override void OnDeviceConnected(UxrDeviceConnectEventArgs e)
{
base.OnDeviceConnected(e);
#if ULTIMATEXR_USE_MAGICLEAP_SDK
if (e.IsConnected)
{
_mlInputs = new MagicLeapInputs();
_mlInputs.Enable();
}
else
{
if (_mlInputs != null)
{
_mlInputs.Dispose();
_mlInputs = null;
}
}
#endif
}
#endregion
#region Protected Overrides UxrUnityXRControllerInput
/// <inheritdoc />
protected override void UpdateInput()
{
base.UpdateInput();
// Propagate touchpad touch to press, since only touch is signaled by the API
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick, GetButtonsTouch(UxrHandSide.Left, UxrInputButtons.Joystick));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Joystick, GetButtonsTouch(UxrHandSide.Right, UxrInputButtons.Joystick));
}
/// <inheritdoc />
protected override bool HasButtonContactOther(UxrHandSide handSide, UxrInputButtons button, ButtonContact buttonContact)
{
#if ULTIMATEXR_USE_MAGICLEAP_SDK
if (button == UxrInputButtons.Bumper)
{
return _mlInputs.Controller.Bumper.IsPressed();
}
// To allow quick integration with UltimateXR manipulation, and since the ML2 doesn't have a grip button, we map
// the bumper to the grip too.
if (button == UxrInputButtons.Grip)
{
return _mlInputs.Controller.Bumper.IsPressed();
}
#endif
return false;
}
#endregion
#region Private Types & Data
#if ULTIMATEXR_USE_MAGICLEAP_SDK
private MagicLeapInputs _mlInputs;
#endif
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3110ba3566d315a41af6c0e8535ee19b
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMagicLeap2Tracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.MagicLeap
{
/// <summary>
/// Tracking for Magic Leap 2 devices using the Magic Leap SDK.
/// </summary>
public class UxrMagicLeap2Tracking : UxrUnityXRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrMagicLeap2Input);
#endregion
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override bool IsMixedRealityDevice => true;
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkMagicLeap;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 207d5725f18c1eb4eaba95a17cdf1794
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dc2e3b5030e4f874b8db7909c4b35781
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaHandTracking.FlipMode.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace UltimateXR.Devices.Integrations.Meta
{
public partial class UxrMetaHandTracking
{
#region Private Types & Data
/// <summary>
/// Enumerates the different ways to retrieve an Oculus SDK Quaternion.
/// </summary>
private enum FlipMode
{
None,
FlipX,
FlipZ
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 42cd7d7680024864810a8c3cf3a42dbc
timeCreated: 1654777476

View File

@@ -0,0 +1,266 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaHandTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
#if ULTIMATEXR_USE_OCULUS_SDK
using UltimateXR.Avatar.Rig;
using UltimateXR.Core.Math;
using UltimateXR.Extensions.Unity.Math;
using UnityEngine;
#endif
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Hand tracking for Meta devices.
/// </summary>
public partial class UxrMetaHandTracking : UxrHandTracking
{
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkOculus;
#endregion
#region Public Overrides UxrHandTracking
/// <inheritdoc />
public override bool IsLeftHandAvailable
{
get
{
#if ULTIMATEXR_USE_OCULUS_SDK
if (OVRPlugin.GetHandState(OVRPlugin.Step.Render, OVRPlugin.Hand.HandLeft, ref _leftHandState))
{
_isLeftHandAvailable = _leftHandState.Status.HasFlag(OVRPlugin.HandStatus.HandTracked);
}
else
{
_isLeftHandAvailable = false;
}
return _isLeftHandAvailable;
#else
return false;
#endif
}
}
/// <inheritdoc />
public override bool IsRightHandAvailable
{
get
{
#if ULTIMATEXR_USE_OCULUS_SDK
if (OVRPlugin.GetHandState(OVRPlugin.Step.Render, OVRPlugin.Hand.HandRight, ref _rightHandState))
{
_isRightHandAvailable = _rightHandState.Status.HasFlag(OVRPlugin.HandStatus.HandTracked);
}
else
{
_isRightHandAvailable = false;
}
return _isRightHandAvailable;
#else
return false;
#endif
}
}
#endregion
#region Unity
/// <summary>
/// Subscribes to events so that the component can be enabled or disabled based on the presence of hand tracking.
/// </summary>
protected override void Awake()
{
base.Awake();
#if ULTIMATEXR_USE_OCULUS_SDK
// Initialize axis system
if (Avatar != null && Avatar.LeftHand.HasFullHandData())
{
_leftHandOculusRotation = Quaternion.LookRotation(Vector3.right, -Vector3.up);
_leftFingerOculusRotation = Quaternion.LookRotation(-Vector3.right, -Vector3.up);
}
if (Avatar != null && Avatar.RightHand.HasFullHandData())
{
_rightHandOculusRotation = Quaternion.LookRotation(Vector3.right, Vector3.up);
_rightFingerOculusRotation = Quaternion.LookRotation(Vector3.right, Vector3.up);
}
#endif
}
#endregion
#region Protected Overrides UxrTrackingDevice
/// <inheritdoc />
protected override void UpdateSensors()
{
#if ULTIMATEXR_USE_OCULUS_SDK
_isLeftHandAvailable = OVRPlugin.GetHandState(OVRPlugin.Step.Render, OVRPlugin.Hand.HandLeft, ref _leftHandState);
_isRightHandAvailable = OVRPlugin.GetHandState(OVRPlugin.Step.Render, OVRPlugin.Hand.HandRight, ref _rightHandState);
#endif
}
/// <inheritdoc />
protected override void UpdateAvatar()
{
#if ULTIMATEXR_USE_OCULUS_SDK
Transform wristLeft = Avatar.LeftHandBone;
Transform wristRight = Avatar.RightHandBone;
if (_isLeftHandAvailable && wristLeft != null)
{
if (UseCalibration)
{
SetCalibrationPose(UxrHandSide.Left);
}
UxrAvatarArmInfo leftArmInfo = Avatar.AvatarRigInfo.GetArmInfo(UxrHandSide.Left);
UxrUniversalLocalAxes leftHandParentAxes = wristLeft.parent == Avatar.AvatarRig.LeftArm.Forearm ? leftArmInfo.ForearmUniversalLocalAxes : leftArmInfo.HandUniversalLocalAxes;
Vector3 sensorLeftPos = Avatar.transform.TransformPoint(_leftHandState.RootPose.Position.FromFlippedZVector3f());
Quaternion sensorLeftRot = Avatar.transform.rotation * ToCorrectCoordinateSystem(_leftHandState.RootPose.Orientation, FlipMode.FlipZ, _leftHandOculusRotation, leftHandParentAxes, leftArmInfo.HandUniversalLocalAxes);
wristLeft.position = sensorLeftPos;
wristLeft.rotation = sensorLeftRot;
UpdateFinger(UxrHandSide.Left, Avatar.LeftHand.Index, OVRPlugin.BoneId.Hand_Index1, 3, _leftFingerOculusRotation, leftArmInfo.HandUniversalLocalAxes, leftArmInfo.FingerUniversalLocalAxes);
UpdateFinger(UxrHandSide.Left, Avatar.LeftHand.Middle, OVRPlugin.BoneId.Hand_Middle1, 3, _leftFingerOculusRotation, leftArmInfo.HandUniversalLocalAxes, leftArmInfo.FingerUniversalLocalAxes);
UpdateFinger(UxrHandSide.Left, Avatar.LeftHand.Ring, OVRPlugin.BoneId.Hand_Ring1, 3, _leftFingerOculusRotation, leftArmInfo.HandUniversalLocalAxes, leftArmInfo.FingerUniversalLocalAxes);
UpdateFinger(UxrHandSide.Left, Avatar.LeftHand.Little, OVRPlugin.BoneId.Hand_Pinky0, 4, _leftFingerOculusRotation, leftArmInfo.HandUniversalLocalAxes, leftArmInfo.FingerUniversalLocalAxes);
UpdateFinger(UxrHandSide.Left, Avatar.LeftHand.Thumb, OVRPlugin.BoneId.Hand_Thumb0, 4, _leftFingerOculusRotation, leftArmInfo.HandUniversalLocalAxes, leftArmInfo.FingerUniversalLocalAxes);
}
if (_isRightHandAvailable && wristRight != null)
{
if (UseCalibration)
{
SetCalibrationPose(UxrHandSide.Right);
}
UxrAvatarArmInfo rightArmInfo = Avatar.AvatarRigInfo.GetArmInfo(UxrHandSide.Right);
UxrUniversalLocalAxes rightHandParentAxes = wristRight.parent == Avatar.AvatarRig.RightArm.Forearm ? rightArmInfo.ForearmUniversalLocalAxes : rightArmInfo.HandUniversalLocalAxes;
Vector3 sensorRightPos = Avatar.transform.TransformPoint(_rightHandState.RootPose.Position.FromFlippedZVector3f());
Quaternion sensorRightRot = Avatar.transform.rotation * ToCorrectCoordinateSystem(_rightHandState.RootPose.Orientation, FlipMode.FlipZ, _rightHandOculusRotation, rightHandParentAxes, rightArmInfo.HandUniversalLocalAxes);
wristRight.position = sensorRightPos;
wristRight.rotation = sensorRightRot;
UpdateFinger(UxrHandSide.Right, Avatar.RightHand.Index, OVRPlugin.BoneId.Hand_Index1, 3, _rightFingerOculusRotation, rightArmInfo.HandUniversalLocalAxes, rightArmInfo.FingerUniversalLocalAxes);
UpdateFinger(UxrHandSide.Right, Avatar.RightHand.Middle, OVRPlugin.BoneId.Hand_Middle1, 3, _rightFingerOculusRotation, rightArmInfo.HandUniversalLocalAxes, rightArmInfo.FingerUniversalLocalAxes);
UpdateFinger(UxrHandSide.Right, Avatar.RightHand.Ring, OVRPlugin.BoneId.Hand_Ring1, 3, _rightFingerOculusRotation, rightArmInfo.HandUniversalLocalAxes, rightArmInfo.FingerUniversalLocalAxes);
UpdateFinger(UxrHandSide.Right, Avatar.RightHand.Little, OVRPlugin.BoneId.Hand_Pinky1, 3, _rightFingerOculusRotation, rightArmInfo.HandUniversalLocalAxes, rightArmInfo.FingerUniversalLocalAxes);
UpdateFinger(UxrHandSide.Right, Avatar.RightHand.Thumb, OVRPlugin.BoneId.Hand_Thumb0, 4, _rightFingerOculusRotation, rightArmInfo.HandUniversalLocalAxes, rightArmInfo.FingerUniversalLocalAxes);
}
#endif
}
#endregion
#if ULTIMATEXR_USE_OCULUS_SDK
/// <summary>
/// Updates a finger using tracking information.
/// </summary>
/// <param name="handSide">Which hand the finger belongs to</param>
/// <param name="avatarFinger">The avatar finger to update</param>
/// <param name="baseBoneId">The oculus bone base id</param>
/// <param name="boneCount">The number of bones to update, usually 2, 3 or 4</param>
/// <param name="fingerOculusRotation">Oculus finger coordinate system</param>
/// <param name="wristUniversalLocalAxes">Avatar wrist coordinate system</param>
/// <param name="fingerUniversalLocalAxes">Avatar finger coordinate system</param>
private void UpdateFinger(UxrHandSide handSide, UxrAvatarFinger avatarFinger, OVRPlugin.BoneId baseBoneId, int boneCount, Quaternion fingerOculusRotation, UxrUniversalLocalAxes wristUniversalLocalAxes, UxrUniversalLocalAxes fingerUniversalLocalAxes)
{
int baseIndex = (int)baseBoneId;
OVRPlugin.HandState handState = handSide == UxrHandSide.Left ? _leftHandState : _rightHandState;
FlipMode flipMode = handSide == UxrHandSide.Left ? FlipMode.FlipX : FlipMode.FlipZ;
if (boneCount > 3)
{
if (avatarFinger.Metacarpal != null)
{
avatarFinger.Metacarpal.localRotation = ToCorrectCoordinateSystem(handState.BoneRotations[baseIndex], flipMode, fingerOculusRotation, wristUniversalLocalAxes, fingerUniversalLocalAxes);
ApplyBoneCalibration(avatarFinger.Metacarpal);
}
baseIndex++;
}
if (boneCount > 2)
{
avatarFinger.Proximal.localRotation = ToCorrectCoordinateSystem(handState.BoneRotations[baseIndex], flipMode, fingerOculusRotation, avatarFinger.Metacarpal == null ? wristUniversalLocalAxes : fingerUniversalLocalAxes, fingerUniversalLocalAxes);
ApplyBoneCalibration(avatarFinger.Proximal);
baseIndex++;
}
avatarFinger.Intermediate.localRotation = ToCorrectCoordinateSystem(handState.BoneRotations[baseIndex], flipMode, fingerOculusRotation, fingerUniversalLocalAxes, fingerUniversalLocalAxes);
avatarFinger.Distal.localRotation = ToCorrectCoordinateSystem(handState.BoneRotations[baseIndex + 1], flipMode, fingerOculusRotation, fingerUniversalLocalAxes, fingerUniversalLocalAxes);
ApplyBoneCalibration(avatarFinger.Intermediate);
ApplyBoneCalibration(avatarFinger.Distal);
}
/// <summary>
/// Converts a rotation from the Oculus SDK coordinate system to the avatar coordinate system.
/// </summary>
/// <param name="oculusRotation">Oculus rotation to convert</param>
/// <param name="flipRotation">How to process the rotation</param>
/// <param name="oculusAxes">
/// Information that converts from the "universal" coordinate system to the coordinate
/// system used by the parent's node.
/// </param>
/// <param name="parentUniversalLocalAxes"></param>
/// <param name="universalLocalAxes">
/// Information that converts from the "universal" coordinate system to the coordinate
/// system used by the node.
/// </param>
/// <returns>Rotation in the avatar coordinate system</returns>
private Quaternion ToCorrectCoordinateSystem(OVRPlugin.Quatf oculusRotation, FlipMode flipRotation, Quaternion oculusAxes, UxrUniversalLocalAxes parentUniversalLocalAxes, UxrUniversalLocalAxes universalLocalAxes)
{
Quaternion rotation = oculusRotation.FromQuatf();
switch (flipRotation)
{
case FlipMode.FlipX:
rotation = oculusRotation.FromFlippedXQuatf();
break;
case FlipMode.FlipZ:
rotation = oculusRotation.FromFlippedZQuatf();
break;
}
Quaternion finalRotation = Quaternion.Inverse(parentUniversalLocalAxes.UniversalToActualAxesRotation) * universalLocalAxes.UniversalToActualAxesRotation * rotation * Quaternion.Inverse(oculusAxes) * universalLocalAxes.UniversalToActualAxesRotation;
return finalRotation.IsValid() ? finalRotation : Quaternion.identity;
}
#endif
#if ULTIMATEXR_USE_OCULUS_SDK
private bool _isLeftHandAvailable;
private bool _isRightHandAvailable;
private OVRPlugin.HandState _leftHandState;
private OVRPlugin.HandState _rightHandState;
private Quaternion _leftHandOculusRotation;
private Quaternion _rightHandOculusRotation;
private Quaternion _leftFingerOculusRotation;
private Quaternion _rightFingerOculusRotation;
#endif
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5d33e531453e48da93053497271b4abd
timeCreated: 1654764133

View File

@@ -0,0 +1,72 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaTouchQuest2Input.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Oculus Touch controller input using Oculus SDK.
/// </summary>
public class UxrMetaTouchQuest2Input : UxrUnityXRControllerInput
{
#region Public Overrides UxrControllerInput
/// <summary>
/// Gets the SDK dependency: Oculus SDK.
/// </summary>
public override string SDKDependency => UxrConstants.SdkOculus;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Grip |
UxrControllerElements.Trigger |
UxrControllerElements.ThumbCapSense |
UxrControllerElements.Button1 |
UxrControllerElements.Button2 |
UxrControllerElements.Menu |
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Right)
{
// Remove menu button from right controller, which is reserved.
validElements = validElements & ~(uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
#region Public Overrides UxrUnityXRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
if (UxrTrackingDevice.HeadsetDeviceName is "Oculus Quest2")
{
yield return "Oculus Touch Controller - Left";
yield return "Oculus Touch Controller - Right";
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4ff66b86132a55f4a9f6efea46da64bb
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,65 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaTouchQuest2InputSteamVR.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Oculus Touch controllers input using SteamVR.
/// </summary>
public class UxrMetaTouchQuest2InputSteamVR : UxrSteamVRControllerInput
{
#region Public Overrides UxrSteamVRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "Oculus Quest2 (Left Controller)";
yield return "Oculus Quest2 (Right Controller)";
}
}
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick | // Joystick
UxrControllerElements.Grip | // Grip
UxrControllerElements.Trigger | // Trigger
UxrControllerElements.Button1 | // Button A
UxrControllerElements.Button2 | // Button B
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Left)
{
validElements |= (uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return UxrControllerInputCapabilities.HapticImpulses;
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e34315eb5a4f11d41ade48a0c1a86715
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaTouchQuest2Tracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Tracking for Oculus Touch devices using the Oculus SDK.
/// </summary>
public class UxrMetaTouchQuest2Tracking : UxrUnityXRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrMetaTouchQuest2Input);
#endregion
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkOculus;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 793d8fce02a8c7a42a9414fb6f5d3dc1
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaTouchQuest2TrackingSteamVR.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Tracking for Oculus Touch controllers using SteamVR SDK.
/// </summary>
public class UxrMetaTouchQuest2TrackingSteamVR : UxrSteamVRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrMetaTouchQuest2InputSteamVR);
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 813e0bb28152bed4ea5c634099e04934
timeCreated: 1624443263

View File

@@ -0,0 +1,72 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaTouchQuest3Input.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Oculus Touch controller input using Oculus SDK.
/// </summary>
public class UxrMetaTouchQuest3Input : UxrUnityXRControllerInput
{
#region Public Overrides UxrControllerInput
/// <summary>
/// Gets the SDK dependency: Oculus SDK.
/// </summary>
public override string SDKDependency => UxrConstants.SdkOculus;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Grip |
UxrControllerElements.Trigger |
UxrControllerElements.ThumbCapSense |
UxrControllerElements.Button1 |
UxrControllerElements.Button2 |
UxrControllerElements.Menu |
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Right)
{
// Remove menu button from right controller, which is reserved.
validElements = validElements & ~(uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
#region Public Overrides UxrUnityXRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
if (UxrTrackingDevice.HeadsetDeviceName is "Oculus Quest3" or "Meta Quest 3" or "Oculus Headset2")
{
yield return "Oculus Touch Controller - Left";
yield return "Oculus Touch Controller - Right";
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fd07cb58266720f478deb9264c45c614
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaTouchQuest3InputSteamVR.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Oculus Touch controllers input using SteamVR.
/// </summary>
public class UxrMetaTouchQuest3InputSteamVR : UxrSteamVRControllerInput
{
#region Public Overrides UxrSteamVRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "Oculus Quest3 (Left Controller)";
yield return "Oculus Quest3 (Right Controller)";
yield return "Meta Quest 3 (Left Controller)";
yield return "Meta Quest 3 (Right Controller)";
}
}
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick | // Joystick
UxrControllerElements.Grip | // Grip
UxrControllerElements.Trigger | // Trigger
UxrControllerElements.Button1 | // Button A
UxrControllerElements.Button2 | // Button B
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Left)
{
validElements |= (uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return UxrControllerInputCapabilities.HapticImpulses;
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a0acc555071f36c4fb74251d9a25c5ae
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaTouchQuest3Tracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Tracking for Oculus Touch devices using the Oculus SDK.
/// </summary>
public class UxrMetaTouchQuest3Tracking : UxrUnityXRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrMetaTouchQuest3Input);
#endregion
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkOculus;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6cc855f608e72a745b7a79e8ca93ba67
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMetaTouchQuest3TrackingSteamVR.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Meta
{
/// <summary>
/// Tracking for Oculus Touch controllers using SteamVR SDK.
/// </summary>
public class UxrMetaTouchQuest3TrackingSteamVR : UxrSteamVRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrMetaTouchQuest3InputSteamVR);
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 07ea441b9add1fd4fb72713dd14725cb
timeCreated: 1624443263

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 30f0aa17591f44647ac57e3b104cc1dc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrWindowsMixedRealityInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UnityEngine;
namespace UltimateXR.Devices.Integrations.Microsoft
{
/// <summary>
/// Windows Mixed Reality input using Unity XR.
/// </summary>
public class UxrWindowsMixedRealityInput : UxrUnityXRControllerInput
{
#region Inspector Properties/Serialized Fields
[Header("Windows Mixed Reality:")] [SerializeField] private float _joystickDeadZone = 0.15f;
#endregion
#region Public Overrides UxrControllerInput
/// <summary>
/// Requires WMR SDK using OpenXR.
/// </summary>
public override string SDKDependency => UxrConstants.SdkWindowsMixedReality;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override float JoystickDeadZone => _joystickDeadZone;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Joystick2 |
UxrControllerElements.Grip |
UxrControllerElements.Trigger |
UxrControllerElements.Menu |
UxrControllerElements.DPad);
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
#region Public Overrides UxrUnityXRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "Windows MR Controller";
yield return "Windows MR Controller OpenXR";
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3e6fba2dada135740a5cc23e3c44ab6b
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrWindowsMixedRealityTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Microsoft
{
/// <summary>
/// Tracking component for devices based on Windows Mixed Reality.
/// </summary>
public class UxrWindowsMixedRealityTracking : UxrUnityXRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrWindowsMixedRealityInput);
#endregion
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkWindowsMixedReality;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6e44a53324016f44da8b9fb0183ace63
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6e1369784c4dde144b2b46e73bd11505
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrOculusTouchRiftInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Oculus
{
/// <summary>
/// Oculus Touch controller input using Oculus SDK.
/// </summary>
public class UxrOculusTouchRiftInput : UxrUnityXRControllerInput
{
#region Public Overrides UxrControllerInput
/// <summary>
/// Gets the SDK dependency: Oculus SDK.
/// </summary>
public override string SDKDependency => UxrConstants.SdkOculus;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Grip |
UxrControllerElements.Trigger |
UxrControllerElements.ThumbCapSense |
UxrControllerElements.Button1 |
UxrControllerElements.Button2 |
UxrControllerElements.Menu |
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Right)
{
// Remove menu button from right controller, which is reserved.
validElements = validElements & ~(uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
#region Public Overrides UxrUnityXRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
if (UxrTrackingDevice.HeadsetDeviceName == "Oculus Rift CV1")
{
yield return "Oculus Touch Controller - Left";
yield return "Oculus Touch Controller - Right";
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7e00e8773baf4604392a82350eee8671
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,66 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrOculusTouchRiftInputSteamVR.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Oculus
{
/// <summary>
/// Oculus Touch controllers input using SteamVR.
/// </summary>
public class UxrOculusTouchRiftInputSteamVR : UxrSteamVRControllerInput
{
#region Public Overrides UxrSteamVRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "Oculus Rift CV1 (Left Controller)";
yield return "Oculus Rift CV1 (Right Controller)";
}
}
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick | // Joystick
UxrControllerElements.Grip | // Grip
UxrControllerElements.Trigger | // Trigger
UxrControllerElements.Button1 | // Button A
UxrControllerElements.Button2 | // Button B
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Left)
{
validElements |= (uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return UxrControllerInputCapabilities.HapticImpulses;
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e41f3824310273441b1a66dc33fc3bc6
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrOculusTouchRiftSQuestInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Oculus
{
/// <summary>
/// Oculus Touch controller input using Oculus SDK.
/// </summary>
public class UxrOculusTouchRiftSQuestInput : UxrUnityXRControllerInput
{
#region Public Overrides UxrControllerInput
/// <summary>
/// Gets the SDK dependency: Oculus SDK.
/// </summary>
public override string SDKDependency => UxrConstants.SdkOculus;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Grip |
UxrControllerElements.Trigger |
UxrControllerElements.ThumbCapSense |
UxrControllerElements.Button1 |
UxrControllerElements.Button2 |
UxrControllerElements.Menu |
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Right)
{
// Remove menu button from right controller, which is reserved.
validElements = validElements & ~(uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
#region Public Overrides UxrUnityXRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
if (UxrTrackingDevice.HeadsetDeviceName is "Oculus Rift S" or "Oculus Quest")
{
yield return "Oculus Touch Controller - Left";
yield return "Oculus Touch Controller - Right";
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c97b7d15f1e96f445a4e33190f9a5020
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrOculusTouchRiftSQuestInputSteamVR.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Oculus
{
/// <summary>
/// Oculus Touch controllers input using SteamVR.
/// </summary>
public class UxrOculusTouchRiftSQuestInputSteamVR : UxrSteamVRControllerInput
{
#region Public Overrides UxrSteamVRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "Oculus Quest (Left Controller)";
yield return "Oculus Quest (Right Controller)";
yield return "Oculus Rift S (Left Controller)";
yield return "Oculus Rift S (Right Controller)";
}
}
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick | // Joystick
UxrControllerElements.Grip | // Grip
UxrControllerElements.Trigger | // Trigger
UxrControllerElements.Button1 | // Button A
UxrControllerElements.Button2 | // Button B
UxrControllerElements.DPad);
if (handSide == UxrHandSide.Left)
{
validElements |= (uint)UxrControllerElements.Menu;
}
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return UxrControllerInputCapabilities.HapticImpulses;
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 46ee2d04c77b0bd4383d6231da50d980
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrOculusTouchRiftSQuestTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Oculus
{
/// <summary>
/// Tracking for Oculus Touch devices using the Oculus SDK.
/// </summary>
public class UxrOculusTouchRiftSQuestTracking : UxrUnityXRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrOculusTouchRiftSQuestInput);
#endregion
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkOculus;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1d9733f867143cc499549d95ef911b9b
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrOculusTouchRiftSQuestTrackingSteamVR.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Oculus
{
/// <summary>
/// Tracking for Oculus Touch controllers using SteamVR SDK.
/// </summary>
public class UxrOculusTouchRiftSQuestTrackingSteamVR : UxrSteamVRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrOculusTouchRiftSQuestInputSteamVR);
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f6d431e33dfaa8a49b2c2572cdf2c202
timeCreated: 1624443263

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrOculusTouchRiftTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Oculus
{
/// <summary>
/// Tracking for Oculus Touch devices using the Oculus SDK.
/// </summary>
public class UxrOculusTouchRiftTracking : UxrUnityXRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrOculusTouchRiftInput);
#endregion
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkOculus;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8c997e1e44845a44599cad72e2f63768
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrOculusTouchRiftTrackingSteamVR.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Oculus
{
/// <summary>
/// Tracking for Oculus Touch controllers using SteamVR SDK.
/// </summary>
public class UxrOculusTouchRiftTrackingSteamVR : UxrSteamVRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrOculusTouchRiftInputSteamVR);
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d9f2ab5b48994c7b933178d3fea37f60
timeCreated: 1624443263

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 836a0efbc8d36a546be3937cb7d41b41
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrPicoNeo3Input.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Pico
{
/// <summary>
/// Pico Neo 3 controller input using PicoXR SDK.
/// </summary>
public class UxrPicoNeo3Input : UxrUnityXRControllerInput
{
#region Public Overrides UxrControllerInput
/// <summary>
/// Gets the SDK dependency: PicoXR.
/// </summary>
public override string SDKDependency => UxrConstants.SdkPicoXR;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick |
UxrControllerElements.Grip |
UxrControllerElements.Trigger |
UxrControllerElements.Button1 |
UxrControllerElements.Button2 |
UxrControllerElements.Menu |
UxrControllerElements.Back |
UxrControllerElements.DPad);
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
#endregion
#region Public Overrides UxrUnityXRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "PicoXR Controller-Left";
yield return "PicoXR Controller-Right";
yield return "PICO Controller-Left";
yield return "PICO Controller-Right";
yield return "PICO Live Preview Controller-Left";
yield return "PICO Live Preview Controller-Right";
}
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0343e6207db6ea84a9a8d40c5170d7f3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrPicoNeo3Tracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
namespace UltimateXR.Devices.Integrations.Pico
{
/// <summary>
/// Tracking for Pico Neo 3 devices using the PicoXR SDK.
/// </summary>
public class UxrPicoNeo3Tracking : UxrUnityXRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrPicoNeo3Input);
#endregion
#region Public Overrides UxrTrackingDevice
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkPicoXR + "";
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 91427e7abc5228c44af202060dafa3af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d71f258a02cff25498b3607eb0dcc4e8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrSteamVRConstants.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace UltimateXR.Devices.Integrations.SteamVR
{
/// <summary>
/// SteamVR constants needed across our framework. At runtime and also for editor classes.
/// </summary>
public static class UxrSteamVRConstants
{
#region Public Types & Data
public const string ActionSetName = "ultimatexr";
public const string ActionNameHandSkeletonLeft = "hand_left_skeleton";
public const string ActionNameHandSkeletonRight = "hand_right_skeleton";
public const string ActionNameHandHaptics = "hand_haptics";
public const string BindingInputClick = "click";
public const string BindingInputTouch = "touch";
public const string BindingVarBool = "boolean";
public const string BindingVarVector1 = "vector1";
public const string BindingVarVector2 = "vector2";
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4b308562c7bd4762ba25e88f5f3a5aa4
timeCreated: 1623420066

View File

@@ -0,0 +1,658 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrSteamVRControllerInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Avatar.Controllers;
using UltimateXR.Core;
using UltimateXR.Haptics;
using UnityEngine;
#if ULTIMATEXR_USE_STEAMVR_SDK
using System;
using System.Linq;
using System.Text;
using Valve.VR;
using UltimateXR.Avatar.Rig;
using UltimateXR.Core.Settings;
using UltimateXR.Manipulation;
#endif
#pragma warning disable 414 // Disable warnings due to unused values
namespace UltimateXR.Devices.Integrations.SteamVR
{
/// <summary>
/// Base class for all SteamVR input devices.
/// Provides common input handling thanks to using the actions exported by the
/// SteamVRActionsExporter.
/// Child classes will require some overrides and minimal input handling if necessary.
/// </summary>
public abstract class UxrSteamVRControllerInput : UxrControllerInput
{
#region Inspector Properties/Serialized Fields
// These will be shown only in custom inspectors for controllers that use them (f.e. index controllers).
[SerializeField] [HideInInspector] private string _openHandPoseName;
[SerializeField] [HideInInspector] private float _indexCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _middleCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _ringCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _littleCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _thumbCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _thumbSpreadAmount = 30.0f;
#endregion
#region Public Types & Data
/// <summary>
/// Gets list of controller names that the component can handle.
/// </summary>
public abstract IEnumerable<string> ControllerNames { get; }
/// <summary>
/// Gets if the class will use hand skeletons.
/// </summary>
public virtual bool UsesHandSkeletons => false;
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <summary>
/// SteamVR child classes will require SteamVR SDK to access functionality.
/// </summary>
public override string SDKDependency => UxrConstants.SdkSteamVR;
/// <inheritdoc />
public override bool IsControllerEnabled(UxrHandSide handSide)
{
#if ULTIMATEXR_USE_STEAMVR_SDK
if (s_controllerList.TryGetValue(GetType().Name, out List<int> controllerIndices))
{
return controllerIndices.Contains(handSide == UxrHandSide.Left
? (int)OpenVR.System.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.LeftHand)
: (int)OpenVR.System.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.RightHand));
}
return false;
#else
return false;
#endif
}
/// <inheritdoc />
public override float GetInput1D(UxrHandSide handSide, UxrInput1D input1D, bool getIgnoredInput = false)
{
if (ShouldIgnoreInput(handSide, getIgnoredInput))
{
return 0.0f;
}
#if ULTIMATEXR_USE_STEAMVR_SDK
SteamVR_Input_Sources source = handSide == UxrHandSide.Left ? SteamVR_Input_Sources.LeftHand : SteamVR_Input_Sources.RightHand;
if (_actionsInput1D.TryGetValue(input1D, out SteamVR_Action_Single action))
{
return action[source].axis;
}
#endif
return 0.0f;
}
/// <inheritdoc />
public override Vector2 GetInput2D(UxrHandSide handSide, UxrInput2D input2D, bool getIgnoredInput = false)
{
if (ShouldIgnoreInput(handSide, getIgnoredInput))
{
return Vector2.zero;
}
#if ULTIMATEXR_USE_STEAMVR_SDK
SteamVR_Input_Sources source = handSide == UxrHandSide.Left ? SteamVR_Input_Sources.LeftHand : SteamVR_Input_Sources.RightHand;
if (_actionsInput2D.TryGetValue(input2D, out SteamVR_Action_Vector2 action))
{
return FilterTwoAxesDeadZone(action[source].axis, JoystickDeadZone);
}
#endif
return Vector2.zero;
}
/// <inheritdoc />
public override void SendHapticFeedback(UxrHandSide handSide, UxrHapticClip hapticClip)
{
if (hapticClip.FallbackClipType != UxrHapticClipType.None)
{
SendHapticFeedback(handSide, hapticClip.FallbackClipType, hapticClip.FallbackAmplitude, hapticClip.FallbackDurationSeconds, hapticClip.HapticMode);
}
}
/// <inheritdoc />
public override void SendHapticFeedback(UxrHandSide handSide,
float frequency,
float amplitude,
float durationSeconds,
UxrHapticMode hapticMode = UxrHapticMode.Mix)
{
#if ULTIMATEXR_USE_STEAMVR_SDK
SteamVR_Input_Sources source = handSide == UxrHandSide.Left ? SteamVR_Input_Sources.LeftHand : SteamVR_Input_Sources.RightHand;
_handHapticsAction.Execute(0.0f, durationSeconds, frequency, amplitude, source);
#endif
}
/// <inheritdoc />
public override void StopHapticFeedback(UxrHandSide handSide)
{
// TODO. Doesn't seem to be supported.
}
#endregion
#region Unity
/// <summary>
/// Takes care of registering the component in the global list of SteamVR input components.
/// Builds the action list to access input and starts listening for device connections.
/// </summary>
protected override void Awake()
{
base.Awake();
#if ULTIMATEXR_USE_STEAMVR_SDK
// Build actions
BuildActionObjects();
if (enabled)
{
// Listen to device connected events
SteamVR_Events.DeviceConnected.Remove(OnDeviceConnected);
SteamVR_Events.DeviceConnected.Listen(OnDeviceConnected);
}
_awakeFinished = true;
if (enabled)
{
// Disabled by default at the beginning, unless we already these controllers registered.
// If we already have the controllers registered it is due to an Awake() when loading a new scene.
enabled = s_controllerList.TryGetValue(InputClassName, out List<int> controllerIndices) && controllerIndices.Count > 0;
RaiseConnectOnStart = enabled;
if (!s_initializedSteamVR)
{
global::Valve.VR.SteamVR.Initialize();
SteamVR_Input.GetActionSet(UxrSteamVRConstants.ActionSetName).Activate();
s_initializedSteamVR = true;
}
}
#else
enabled = false;
#endif
}
/// <summary>
/// Called when the component is disabled. In the case the component was using skeletal
/// input, the hand will be driven by the Avatar Animator back again.
/// </summary>
protected override void OnDisable()
{
base.OnDisable();
if (UsesHandSkeletons)
{
if (!_awakeFinished || !UxrManager.Instance || !Avatar || !Avatar.AvatarController)
{
return;
}
UxrStandardAvatarController standardAvatarController = Avatar.AvatarController as UxrStandardAvatarController;
if (standardAvatarController == null)
{
return;
}
if (!string.IsNullOrEmpty(_openHandPoseName))
{
standardAvatarController.LeftHandDefaultPoseNameOverride = null;
standardAvatarController.RightHandDefaultPoseNameOverride = null;
standardAvatarController.LeftHandGrabPoseNameOverride = null;
standardAvatarController.RightHandGrabPoseNameOverride = null;
}
}
}
/// <summary>
/// Initializes SteamVR if necessary and activates the UltimateXR action set.
/// Will initialize skeleton functionality if necessary.
/// </summary>
protected override void Start()
{
base.Start();
#if ULTIMATEXR_USE_STEAMVR_SDK
if (UsesHandSkeletons)
{
_handSkeletonActionLeft.SetSkeletalTransformSpace(EVRSkeletalTransformSpace.Model);
_handSkeletonActionRight.SetSkeletalTransformSpace(EVRSkeletalTransformSpace.Model);
}
#endif
}
/// <summary>
/// If the component has skeleton capabilities, the hand bones will be updated here.
/// </summary>
private void LateUpdate()
{
if (Avatar == null)
{
}
#if ULTIMATEXR_USE_STEAMVR_SDK
// Update using skeleton if necessary
if (UsesHandSkeletons)
{
UxrStandardAvatarController avatarControllerStandard = Avatar.AvatarController as UxrStandardAvatarController;
UxrAvatarRig avatarRig = Avatar.AvatarRig;
if (avatarControllerStandard == null)
{
return;
}
float curlIndex = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.index] * _indexCurlAmount;
float curlMiddle = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.middle] * _middleCurlAmount;
float curlRing = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.ring] * _ringCurlAmount;
float curlLittle = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.pinky] * _littleCurlAmount;
float curlThumb = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.thumb] * _thumbCurlAmount;
float splayThumb = _handSkeletonActionLeft.fingerSplays[SteamVR_Skeleton_FingerIndexes.thumb] * _thumbSpreadAmount;
if (!UxrGrabManager.Instance.IsHandGrabbing(Avatar, UxrHandSide.Left) && !avatarControllerStandard.IsLeftHandInsideFingerPointingVolume)
{
if (!string.IsNullOrEmpty(_openHandPoseName))
{
avatarControllerStandard.LeftHandDefaultPoseNameOverride = _openHandPoseName;
avatarControllerStandard.LeftHandGrabPoseNameOverride = _openHandPoseName;
Avatar.SetCurrentHandPoseImmediately(UxrHandSide.Left, _openHandPoseName);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Index, curlIndex, curlIndex, curlIndex);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Middle, curlMiddle, curlMiddle, curlMiddle);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Ring, curlRing, curlRing, curlRing);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Little, curlLittle, curlLittle, curlLittle);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Thumb, curlThumb * 0.1f, curlThumb * 0.3f, curlThumb * 1.0f, splayThumb);
}
}
else
{
if (!string.IsNullOrEmpty(_openHandPoseName))
{
avatarControllerStandard.LeftHandDefaultPoseNameOverride = null;
}
}
curlIndex = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.index] * _indexCurlAmount;
curlMiddle = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.middle] * _middleCurlAmount;
curlRing = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.ring] * _ringCurlAmount;
curlLittle = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.pinky] * _littleCurlAmount;
curlThumb = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.thumb] * _thumbCurlAmount;
splayThumb = _handSkeletonActionRight.fingerSplays[SteamVR_Skeleton_FingerIndexes.thumb] * _thumbSpreadAmount;
if (!UxrGrabManager.Instance.IsHandGrabbing(Avatar, UxrHandSide.Right) && !avatarControllerStandard.IsRightHandInsideFingerPointingVolume)
{
if (!string.IsNullOrEmpty(_openHandPoseName))
{
avatarControllerStandard.RightHandDefaultPoseNameOverride = _openHandPoseName;
avatarControllerStandard.RightHandGrabPoseNameOverride = _openHandPoseName;
Avatar.SetCurrentHandPoseImmediately(UxrHandSide.Right, _openHandPoseName);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Index, curlIndex, curlIndex, curlIndex);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Middle, curlMiddle, curlMiddle, curlMiddle);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Ring, curlRing, curlRing, curlRing);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Little, curlLittle, curlLittle, curlLittle);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Thumb, curlThumb * 0.1f, curlThumb * 0.3f, curlThumb * 1.0f, splayThumb);
}
}
else
{
if (!string.IsNullOrEmpty(_openHandPoseName))
{
avatarControllerStandard.RightHandDefaultPoseNameOverride = null;
}
}
}
#endif
}
#endregion
#region Protected Overrides UxrControllerInput
/// <summary>
/// Updates the complete input state using our common SteamVR actions. This allows to use the same interface
/// for all controllers and enables the implementation of new devices with minimal effort.
/// </summary>
protected override void UpdateInput()
{
base.UpdateInput();
// Get joystick values
Vector2 leftJoystickValue = GetInput2D(UxrHandSide.Left, UxrInput2D.Joystick);
Vector2 rightJoystickValue = GetInput2D(UxrHandSide.Right, UxrInput2D.Joystick);
Vector2 leftJoystick2Value = GetInput2D(UxrHandSide.Left, UxrInput2D.Joystick2);
Vector2 rightJoystick2Value = GetInput2D(UxrHandSide.Right, UxrInput2D.Joystick2);
#if ULTIMATEXR_USE_STEAMVR_SDK
var system = OpenVR.System;
if (system == null)
{
return;
}
// Update buttons
foreach (UxrInputButtons button in Enum.GetValues(typeof(UxrInputButtons)))
{
if (button != UxrInputButtons.None && button != UxrInputButtons.Any && button != UxrInputButtons.Everything)
{
SetButtonFlags(ButtonFlags.PressFlagsLeft, button, _actionsButtonClick[button][SteamVR_Input_Sources.LeftHand].state);
SetButtonFlags(ButtonFlags.PressFlagsRight, button, _actionsButtonClick[button][SteamVR_Input_Sources.RightHand].state);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, button, _actionsButtonTouch[button][SteamVR_Input_Sources.LeftHand].state);
SetButtonFlags(ButtonFlags.TouchFlagsRight, button, _actionsButtonTouch[button][SteamVR_Input_Sources.RightHand].state);
}
}
#endif
// These ones are mainly for teleporting functionality when we don't get touch values out of joysticks:
if (leftJoystickValue != Vector2.zero && leftJoystickValue.magnitude > AnalogAsDPadThreshold)
{
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Joystick, true);
}
if (rightJoystickValue != Vector2.zero && rightJoystickValue.magnitude > AnalogAsDPadThreshold)
{
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Joystick, true);
}
// Same for joystick2 just in case
if (leftJoystick2Value != Vector2.zero && leftJoystick2Value.magnitude > AnalogAsDPadThreshold)
{
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Joystick2, true);
}
if (rightJoystick2Value != Vector2.zero && rightJoystick2Value.magnitude > AnalogAsDPadThreshold)
{
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Joystick2, true);
}
// Update joystick/DPad direction buttons using joystick analog value and pressed state
uint leftDirectionFlags = GetButtonFlags(MainJoystickIsTouchpad ? ButtonFlags.PressFlagsLeft : ButtonFlags.TouchFlagsLeft);
if (leftJoystickValue != Vector2.zero && leftJoystickValue.magnitude > AnalogAsDPadThreshold && (leftDirectionFlags & (int)UxrInputButtons.Joystick) != 0)
{
float leftJoystickAngle = Input2DToAngle(leftJoystickValue);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, IsInput2dDPadLeft(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, IsInput2dDPadRight(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, IsInput2dDPadUp(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, IsInput2dDPadDown(leftJoystickAngle));
}
else
{
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, false);
}
uint leftButtonPressFlags = GetButtonFlags(ButtonFlags.PressFlagsLeft);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, (leftButtonPressFlags & (uint)UxrInputButtons.DPadLeft) != 0);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, (leftButtonPressFlags & (uint)UxrInputButtons.DPadRight) != 0);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, (leftButtonPressFlags & (uint)UxrInputButtons.DPadUp) != 0);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, (leftButtonPressFlags & (uint)UxrInputButtons.DPadDown) != 0);
uint rightDirectionFlags = GetButtonFlags(MainJoystickIsTouchpad ? ButtonFlags.PressFlagsRight : ButtonFlags.TouchFlagsRight);
if (rightJoystickValue != Vector2.zero && rightJoystickValue.magnitude > AnalogAsDPadThreshold && (rightDirectionFlags & (int)UxrInputButtons.Joystick) != 0)
{
float rightJoystickAngle = Input2DToAngle(rightJoystickValue);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadLeft, IsInput2dDPadLeft(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadRight, IsInput2dDPadRight(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadUp, IsInput2dDPadUp(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadDown, IsInput2dDPadDown(rightJoystickAngle));
}
else
{
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadLeft, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadRight, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadUp, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadDown, false);
}
uint rightButtonPressFlags = GetButtonFlags(ButtonFlags.PressFlagsRight);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickLeft, (rightButtonPressFlags & (uint)UxrInputButtons.DPadLeft) != 0);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickRight, (rightButtonPressFlags & (uint)UxrInputButtons.DPadRight) != 0);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickUp, (rightButtonPressFlags & (uint)UxrInputButtons.DPadUp) != 0);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickDown, (rightButtonPressFlags & (uint)UxrInputButtons.DPadDown) != 0);
}
#endregion
#region Private Types & Data
private string InputClassName => GetType().Name;
// Global data
private static readonly Dictionary<string, List<int>> s_controllerList = new Dictionary<string, List<int>>();
private static bool s_initializedSteamVR;
// Local data
private bool _awakeFinished;
#endregion
#if ULTIMATEXR_USE_STEAMVR_SDK
/// <summary>
/// Given a controller name, gets a list of controller names using the Virtual Desktop controller naming convention.
/// </summary>
/// <param name="controllerName">Controller name to get the virtual desktop controller names for</param>
/// <returns>List of virtual desktop controller names</returns>
private static IEnumerable<string> GetVirtualDesktopWrappedControllerNames(string controllerName)
{
yield return $"OpenVR Controller({controllerName}) - Left";
yield return $"OpenVR Controller({controllerName}) - Right";
}
/// <summary>
/// Called when a SteamVR device is connected
/// </summary>
/// <param name="index">Device index</param>
/// <param name="connected">True if connected, false if disconnected</param>
private static void OnDeviceConnected(int index, bool connected)
{
if (OpenVR.System == null)
{
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Errors)
{
Debug.LogError($"{UxrConstants.DevicesModule} {nameof(UxrSteamVRControllerInput)}::{nameof(OnDeviceConnected)}: OpenVR.System is null");
}
return;
}
if (OpenVR.System.GetTrackedDeviceClass((uint)index) != ETrackedDeviceClass.Controller)
{
// Ignore devices that aren't controllers
return;
}
var renderModelName = new StringBuilder(ModelNameMaxLength);
var error = ETrackedPropertyError.TrackedProp_Success;
OpenVR.System.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_ModelNumber_String, renderModelName, ModelNameMaxLength, ref error);
string modelNameString = renderModelName.ToString();
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {nameof(UxrSteamVRControllerInput)}::{nameof(OnDeviceConnected)}: connected={connected}, model={modelNameString}");
}
IEnumerable<UxrSteamVRControllerInput> inputsSteamVR = AllComponents.Where(i => i is UxrSteamVRControllerInput).Cast<UxrSteamVRControllerInput>();
UxrSteamVRControllerInput inputSteamVR = inputsSteamVR.FirstOrDefault(i =>
i.ControllerNames.Any(n => string.Equals(n, modelNameString)) || i.ControllerNames.SelectMany(GetVirtualDesktopWrappedControllerNames).Any(n => string.Equals(n, modelNameString)));
if (inputSteamVR != null)
{
// Model is one of the registered SteamVR inputs and needs to be processed
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {nameof(UxrSteamVRControllerInput)}::{nameof(OnDeviceConnected)}: Device name {modelNameString} was registered by {inputSteamVR.InputClassName} and is being processed!");
}
if (!s_controllerList.TryGetValue(inputSteamVR.InputClassName, out List<int> controllerIndices))
{
controllerIndices = new List<int>();
s_controllerList.Add(inputSteamVR.InputClassName, controllerIndices);
}
if (connected)
{
// Connected
controllerIndices.Add(index);
if (inputSteamVR.enabled == false)
{
// First controller: Notify device is connected since we consider the device the whole setup
inputSteamVR.enabled = true;
inputSteamVR.OnDeviceConnected(new UxrDeviceConnectEventArgs(true));
}
}
else
{
// Disconnected
controllerIndices.Remove(index);
if (controllerIndices.Count == 0)
{
// Last controller disconnected: Notify device is disconnected.
inputSteamVR.enabled = false;
inputSteamVR.OnDeviceConnected(new UxrDeviceConnectEventArgs(false));
}
}
}
else
{
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {nameof(UxrSteamVRControllerInput)}::{nameof(OnDeviceConnected)}: Device is not recognized as input by any of {inputsSteamVR.Count()} components");
}
}
}
/// <summary>
/// Gets the action bound to the given button and input type.
/// </summary>
/// <param name="button">Button to look for</param>
/// <param name="inputType">Type of input to handle. Use <see cref="UxrSteamVRConstants" />.</param>
/// <returns>
/// Action bound to the given button and input type. If the button doesn't exist
/// in the current controller it will return a fake action showing no input
/// </returns>
private static SteamVR_Action_Boolean GetButtonAction(UxrInputButtons button, string inputType)
{
return SteamVR_Input.GetAction<SteamVR_Action_Boolean>(UxrSteamVRConstants.ActionSetName, $"{button.ToString().ToLower()}_{inputType}_{UxrSteamVRConstants.BindingVarBool}");
}
/// <summary>
/// Gets the action bound to the given <see cref="UxrInput1D" />.
/// </summary>
/// <param name="input1D">Element to look for</param>
/// <returns>
/// Action bound to the given 1D input. If the element doesn't exist in the current controller it will return a
/// fake action showing no input
/// </returns>
private static SteamVR_Action_Single GetInput1DAction(UxrInput1D input1D)
{
return SteamVR_Input.GetAction<SteamVR_Action_Single>(UxrSteamVRConstants.ActionSetName, $"{input1D.ToString().ToLower()}_{UxrSteamVRConstants.BindingVarVector1}");
}
/// <summary>
/// Gets the action bound to the given <see cref="UxrInput2D" />.
/// </summary>
/// <param name="input2D">Element to look for</param>
/// <returns>
/// Action bound to the given 2D input. If the element doesn't exist in the current controller it will return a fake
/// action showing no input
/// </returns>
private static SteamVR_Action_Vector2 GetInput2DAction(UxrInput2D input2D)
{
return SteamVR_Input.GetAction<SteamVR_Action_Vector2>(UxrSteamVRConstants.ActionSetName, $"{input2D.ToString().ToLower()}_{UxrSteamVRConstants.BindingVarVector2}");
}
/// <summary>
/// Builds all action objects needed to check for input using SteamVR.
/// We use enumeration of all elements inside an Enum to build our action list and,
/// thanks to the functionality of SteamVR, when an action doesn't exist it will
/// generate a fake action showing no input.
/// </summary>
private void BuildActionObjects()
{
// Buttons
foreach (UxrInputButtons button in Enum.GetValues(typeof(UxrInputButtons)))
{
if (button != UxrInputButtons.None && button != UxrInputButtons.Any && button != UxrInputButtons.Everything)
{
_actionsButtonClick.Add(button, GetButtonAction(button, UxrSteamVRConstants.BindingInputClick));
_actionsButtonTouch.Add(button, GetButtonAction(button, UxrSteamVRConstants.BindingInputTouch));
}
}
// UxrInput1D
foreach (UxrInput1D input1D in Enum.GetValues(typeof(UxrInput1D)))
{
if (input1D != UxrInput1D.None)
{
_actionsInput1D.Add(input1D, GetInput1DAction(input1D));
}
}
// UxrInput2D
foreach (UxrInput2D input2D in Enum.GetValues(typeof(UxrInput2D)))
{
if (input2D != UxrInput2D.None)
{
_actionsInput2D.Add(input2D, GetInput2DAction(input2D));
}
}
}
#endif
#if ULTIMATEXR_USE_STEAMVR_SDK
private const int ModelNameMaxLength = 256;
private readonly Dictionary<UxrInputButtons, SteamVR_Action_Boolean> _actionsButtonClick = new Dictionary<UxrInputButtons, SteamVR_Action_Boolean>();
private readonly Dictionary<UxrInputButtons, SteamVR_Action_Boolean> _actionsButtonTouch = new Dictionary<UxrInputButtons, SteamVR_Action_Boolean>();
private readonly Dictionary<UxrInput1D, SteamVR_Action_Single> _actionsInput1D = new Dictionary<UxrInput1D, SteamVR_Action_Single>();
private readonly Dictionary<UxrInput2D, SteamVR_Action_Vector2> _actionsInput2D = new Dictionary<UxrInput2D, SteamVR_Action_Vector2>();
private readonly SteamVR_Action_Skeleton _handSkeletonActionLeft = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(UxrSteamVRConstants.ActionSetName, UxrSteamVRConstants.ActionNameHandSkeletonLeft);
private readonly SteamVR_Action_Skeleton _handSkeletonActionRight = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(UxrSteamVRConstants.ActionSetName, UxrSteamVRConstants.ActionNameHandSkeletonRight);
private readonly SteamVR_Action_Vibration _handHapticsAction = SteamVR_Input.GetAction<SteamVR_Action_Vibration>(UxrSteamVRConstants.ActionSetName, UxrSteamVRConstants.ActionNameHandHaptics);
#endif
}
}
#pragma warning restore 414 // Restore warnings due to unused values

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e95eafbdf5bd474e8b9b19b85ed37f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,103 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrSteamVRControllerTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
#if ULTIMATEXR_USE_STEAMVR_SDK
using Valve.VR;
#endif
namespace UltimateXR.Devices.Integrations.SteamVR
{
/// <summary>
/// Base class for tracking devices that use SteamVR.
/// </summary>
public abstract class UxrSteamVRControllerTracking : UxrControllerTracking
{
#region Public Overrides UxrTrackingDevice
/// <summary>
/// Gets SDK dependency. SteamVR tracking devices require SteamVR SDK installed.
/// </summary>
public override string SDKDependency => UxrConstants.SdkSteamVR;
#endregion
#region MonoBehaviour
/// <summary>
/// Subscribes to SteamVR pose update events
/// </summary>
protected override void OnEnable()
{
base.OnEnable();
#if ULTIMATEXR_USE_STEAMVR_SDK
global::Valve.VR.SteamVR.Initialize();
if (global::Valve.VR.SteamVR.initializedState is global::Valve.VR.SteamVR.InitializedStates.Initializing or global::Valve.VR.SteamVR.InitializedStates.InitializeSuccess)
{
if (poseAction != null)
{
poseAction[SteamVR_Input_Sources.LeftHand].onUpdate += PoseAction_OnUpdate;
poseAction[SteamVR_Input_Sources.RightHand].onUpdate += PoseAction_OnUpdate;
}
}
#endif
}
/// <summary>
/// Subscribes from SteamVR pose update events
/// </summary>
protected override void OnDisable()
{
base.OnDisable();
#if ULTIMATEXR_USE_STEAMVR_SDK
if (global::Valve.VR.SteamVR.initializedState is global::Valve.VR.SteamVR.InitializedStates.Initializing or global::Valve.VR.SteamVR.InitializedStates.InitializeSuccess)
{
if (poseAction != null)
{
poseAction[SteamVR_Input_Sources.LeftHand].onUpdate -= PoseAction_OnUpdate;
poseAction[SteamVR_Input_Sources.RightHand].onUpdate -= PoseAction_OnUpdate;
}
}
#endif
}
#endregion
#region Event Handling Methods
#if ULTIMATEXR_USE_STEAMVR_SDK
/// <summary>
/// Handles the pose action update
/// </summary>
/// <param name="fromAction">The action that triggered the event</param>
/// <param name="fromSource">The source that was updated</param>
private void PoseAction_OnUpdate(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource)
{
if (fromSource == SteamVR_Input_Sources.LeftHand)
{
UpdateSensor(UxrHandSide.Left, poseAction[fromSource].localPosition, poseAction[fromSource].localRotation);
}
else if (fromSource == SteamVR_Input_Sources.RightHand)
{
UpdateSensor(UxrHandSide.Right, poseAction[fromSource].localPosition, poseAction[fromSource].localRotation);
}
}
#endif
#endregion
#region Private types & Data
#if ULTIMATEXR_USE_STEAMVR_SDK
private readonly SteamVR_Action_Pose poseAction = SteamVR_Input.GetAction<SteamVR_Action_Pose>("Pose");
#endif
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ada8ee64cca041b7bab08de0867749c2
timeCreated: 1624002590

View File

@@ -0,0 +1,64 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrDummyControllerInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UnityEngine;
namespace UltimateXR.Devices.Integrations
{
/// <summary>
/// Dummy input class that is used when there is no active input component in the avatar.
/// It has the advantage of avoiding to check for null input component and it doesn't generate any type of input
/// events.
/// </summary>
public class UxrDummyControllerInput : UxrControllerInput
{
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override string LeftControllerName => "Dummy Left";
/// <inheritdoc />
public override string RightControllerName => "Dummy Right";
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <inheritdoc />
public override bool IsControllerEnabled(UxrHandSide handSide)
{
return false;
}
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElement)
{
return false;
}
/// <inheritdoc />
public override float GetInput1D(UxrHandSide handSide, UxrInput1D input1D, bool getIgnoredInput = false)
{
return 0.0f;
}
/// <inheritdoc />
public override Vector2 GetInput2D(UxrHandSide handSide, UxrInput2D input2D, bool getIgnoredInput = false)
{
return Vector2.zero;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return 0;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 69f904c3378e5b644ab8bb4cf3257be6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,310 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrGamepadInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UnityEngine;
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
using UnityEngine.InputSystem;
#endif
namespace UltimateXR.Devices.Integrations
{
/// <summary>
/// Standard X-box like gamepad input.
/// </summary>
public class UxrGamepadInput : UxrControllerInput
{
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override string SDKDependency => UxrConstants.SdkUnityInputSystem;
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Single;
/// <inheritdoc />
public override bool IsHandednessSupported => false;
/// <inheritdoc />
public override bool IsControllerEnabled(UxrHandSide handSide)
{
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
return Gamepad.current != null;
#else
return false;
#endif
}
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick | // Left thumbstick
UxrControllerElements.Joystick2 | // Right thumbstick
UxrControllerElements.Trigger | // Left index trigger
UxrControllerElements.Trigger2 | // Right index trigger
UxrControllerElements.Button1 | // Button 1
UxrControllerElements.Button2 | // Button 2
UxrControllerElements.Button3 | // Button 3
UxrControllerElements.Button4 | // Button 4
UxrControllerElements.Bumper | // Left shoulder button
UxrControllerElements.Bumper2 | // Right shoulder button
UxrControllerElements.Back | // Left system button
UxrControllerElements.Menu | // Right system button
UxrControllerElements.DPad); // Digital pad
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return UxrControllerInputCapabilities.HapticImpulses;
}
/// <inheritdoc />
public override float GetInput1D(UxrHandSide handSide, UxrInput1D input1D, bool getIgnoredInput = false)
{
if (ShouldIgnoreInput(handSide, getIgnoredInput))
{
return 0.0f;
}
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
switch (input1D)
{
case UxrInput1D.Trigger: return Gamepad.current.leftTrigger.ReadValue();
case UxrInput1D.Trigger2: return Gamepad.current.rightTrigger.ReadValue();
}
#endif
return 0.0f;
}
/// <inheritdoc />
public override Vector2 GetInput2D(UxrHandSide handSide, UxrInput2D input2D, bool getIgnoredInput = false)
{
if (ShouldIgnoreInput(handSide, getIgnoredInput))
{
return Vector2.zero;
}
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
switch (input2D)
{
case UxrInput2D.Joystick: return Gamepad.current.leftStick.ReadValue();
case UxrInput2D.Joystick2: return Gamepad.current.rightStick.ReadValue();
}
#else
switch (input2D)
{
case UxrInput2D.Joystick: return new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
case UxrInput2D.Joystick2: return Vector2.zero;
}
#endif
return Vector2.zero;
}
#endregion
#region Unity
/// <summary>
/// Subscribes to device events.
/// </summary>
protected override void Awake()
{
base.Awake();
if (enabled)
{
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
InputSystem.onDeviceChange += InputSystem_DeviceChanged;
enabled = _gamepad != null;
#else
enabled = false;
#endif
RaiseConnectOnStart = enabled;
}
}
/// <summary>
/// Unsubscribes from device events.
/// </summary>
protected override void OnDestroy()
{
base.OnDestroy();
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
InputSystem.onDeviceChange -= InputSystem_DeviceChanged;
#endif
}
#endregion
#region Event Handling Methods
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
/// <summary>
/// Handles the <see cref="InputSystem.onDeviceChange" /> event.
/// </summary>
/// <param name="device">Device changed</param>
/// <param name="deviceChange">The change</param>
private void InputSystem_DeviceChanged(InputDevice device, InputDeviceChange deviceChange)
{
if (enabled == false && Gamepad.current != null)
{
// If component is disabled and gamepad is available, act as connect
enabled = true;
_gamepad = Gamepad.current;
OnDeviceConnected(new UxrDeviceConnectEventArgs(true));
}
else if (enabled && Gamepad.current == null)
{
// If component is enabled and gamepad is unavailable, act as disconnect
enabled = false;
_gamepad = null;
OnDeviceConnected(new UxrDeviceConnectEventArgs(false));
}
}
#endif
#endregion
#region Protected Overrides UxrControllerInput
/// <inheritdoc />
protected override void UpdateInput()
{
base.UpdateInput();
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
if (Gamepad.current == null)
{
return;
}
float leftJoystickAngle = Input2DToAngle(Gamepad.current.leftStick.ReadValue());
float rightJoystickAngle = Input2DToAngle(Gamepad.current.rightStick.ReadValue());
// For single devices where there is no handedness, IUxrControllerInputUpdater.UpdateInput() expects the left button flags to be updated
// and it will take care of copying them to the right so that both hands return the same input.
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, IsInput2dDPadLeft(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, IsInput2dDPadRight(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, IsInput2dDPadUp(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, IsInput2dDPadDown(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2Left, IsInput2dDPadLeft(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2Right, IsInput2dDPadRight(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2Up, IsInput2dDPadUp(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2Down, IsInput2dDPadDown(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Trigger, Gamepad.current.leftTrigger.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Trigger2, Gamepad.current.rightTrigger.ReadValue() > AnalogAsDPadThreshold);
#else
Vector2 leftJoystick = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (leftJoystick != Vector2.zero && leftJoystick.magnitude > AnalogAsDPadThreshold)
{
float joystickAngle = Input2DToAngle(leftJoystick);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, IsInput2dDPadLeft(joystickAngle));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, IsInput2dDPadRight(joystickAngle));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, IsInput2dDPadUp(joystickAngle));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, IsInput2dDPadDown(joystickAngle));
}
else
{
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, false);
}
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2Left, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2Right, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2Up, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2Down, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Trigger, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Trigger2, false);
#endif
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick, Gamepad.current.leftStickButton.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2, Gamepad.current.rightStickButton.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper, Gamepad.current.leftShoulder.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper2, Gamepad.current.rightShoulder.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button1, Gamepad.current.buttonSouth.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button2, Gamepad.current.buttonEast.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button3, Gamepad.current.buttonWest.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button4, Gamepad.current.buttonNorth.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Back, Gamepad.current.selectButton.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Menu, Gamepad.current.startButton.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, Gamepad.current.dpad.left.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, Gamepad.current.dpad.right.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, Gamepad.current.dpad.up.ReadValue() > AnalogAsDPadThreshold);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, Gamepad.current.dpad.down.ReadValue() > AnalogAsDPadThreshold);
#elif UNITY_STANDALONE_OSX
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick, Input.GetKey(KeyCode.JoystickButton11));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2, Input.GetKey(KeyCode.JoystickButton12));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper, Input.GetKey(KeyCode.JoystickButton13));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper2, Input.GetKey(KeyCode.JoystickButton14));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button1, Input.GetKey(KeyCode.JoystickButton16));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button2, Input.GetKey(KeyCode.JoystickButton17));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button3, Input.GetKey(KeyCode.JoystickButton18));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button4, Input.GetKey(KeyCode.JoystickButton19));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Menu, Input.GetKey(KeyCode.JoystickButton9));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, Input.GetKey(KeyCode.JoystickButton7));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, Input.GetKey(KeyCode.JoystickButton8));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, Input.GetKey(KeyCode.JoystickButton5));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, Input.GetKey(KeyCode.JoystickButton6));
#elif UNITY_STANDALONE_LINUX
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick, Input.GetKey(KeyCode.JoystickButton9));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2, Input.GetKey(KeyCode.JoystickButton10));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper, Input.GetKey(KeyCode.JoystickButton4));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper2, Input.GetKey(KeyCode.JoystickButton5));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button1, Input.GetKey(KeyCode.JoystickButton0));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button2, Input.GetKey(KeyCode.JoystickButton1));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button3, Input.GetKey(KeyCode.JoystickButton2));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button4, Input.GetKey(KeyCode.JoystickButton3));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Menu, Input.GetKey(KeyCode.JoystickButton7));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, Input.GetKey(KeyCode.JoystickButton11));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, Input.GetKey(KeyCode.JoystickButton12));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, Input.GetKey(KeyCode.JoystickButton13));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, Input.GetKey(KeyCode.JoystickButton14)));
#else
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick, Input.GetKey(KeyCode.JoystickButton8));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2, Input.GetKey(KeyCode.JoystickButton9));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper, Input.GetKey(KeyCode.JoystickButton4));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper2, Input.GetKey(KeyCode.JoystickButton5));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button1, Input.GetKey(KeyCode.JoystickButton0));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button2, Input.GetKey(KeyCode.JoystickButton1));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button3, Input.GetKey(KeyCode.JoystickButton2));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button4, Input.GetKey(KeyCode.JoystickButton3));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Back, Input.GetKey(KeyCode.JoystickButton6));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Menu, Input.GetKey(KeyCode.JoystickButton7));
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, false);
this.SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, false);
#endif
}
#endregion
#region Private Types & Data
#if ULTIMATEXR_USE_UNITYINPUTSYSTEM_SDK
private Gamepad _gamepad;
#endif
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1cf3f2ab4b560be4e90fce9b1ca24f10
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrUnityXRControllerInput.ButtonContact.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace UltimateXR.Devices.Integrations
{
public abstract partial class UxrUnityXRControllerInput
{
#region Private Types & Data
/// <summary>
/// Types of button contact.
/// </summary>
protected enum ButtonContact
{
/// <summary>
/// Button press.
/// </summary>
Press,
/// <summary>
/// Button contact without pressing.
/// </summary>
Touch
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4bfa0e7c496b4585957a85feaa88b564
timeCreated: 1643734934

View File

@@ -0,0 +1,946 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrUnityXRControllerInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using UltimateXR.Core;
using UltimateXR.Core.Settings;
using UltimateXR.Haptics;
using UnityEngine;
using UnityEngine.XR;
#if ULTIMATEXR_UNITY_XR_OCULUS
using Unity.XR.Oculus;
#endif
namespace UltimateXR.Devices.Integrations
{
/// <summary>
/// Generic base class for left-right input devices that can be handled through the new
/// generic Unity XR input interface. Before, we had to manually support each SDK individually.
/// </summary>
public abstract partial class UxrUnityXRControllerInput : UxrControllerInput
{
#region Public Types & Data
/// <summary>
/// Gets list of controller names that the component can handle
/// </summary>
public abstract IEnumerable<string> ControllerNames { get; }
/// <summary>
/// We use this when we are implementing new controllers that we don't know the name of, in order to
/// show the controller names in the UxrDebugControllerPanel.
/// Returning true will register the controllers in <see cref="InputDevices_DeviceConnected" /> no
/// matter which input device gets connected. Then using the UxrDebugControllerPanel we can see which
/// devices got connected.
/// This is mostly useful for untethered devices that cannot be tested directly in Unity.
/// </summary>
public virtual bool ForceUseAlways => false;
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override string LeftControllerName => _deviceLeft.isValid ? _deviceLeft.name : string.Empty;
/// <inheritdoc />
public override string RightControllerName => _deviceRight.isValid ? _deviceRight.name : string.Empty;
/// <inheritdoc />
public override bool IsControllerEnabled(UxrHandSide handSide)
{
return GetInputDevice(handSide).isValid;
}
/// <inheritdoc />
public override float GetInput1D(UxrHandSide handSide, UxrInput1D input1D, bool getIgnoredInput = false)
{
if (ShouldIgnoreInput(handSide, getIgnoredInput))
{
return 0.0f;
}
InputDevice inputDevice = GetInputDevice(handSide);
if (inputDevice.isValid)
{
float value;
switch (input1D)
{
case UxrInput1D.Grip:
if (inputDevice.TryGetFeatureValue(CommonUsages.grip, out value))
{
return value;
}
break;
case UxrInput1D.Trigger:
if (inputDevice.TryGetFeatureValue(CommonUsages.trigger, out value))
{
return value;
}
break;
case UxrInput1D.Trigger2: break;
}
}
return 0.0f;
}
/// <inheritdoc />
public override Vector2 GetInput2D(UxrHandSide handSide, UxrInput2D input2D, bool getIgnoredInput = false)
{
if (ShouldIgnoreInput(handSide, getIgnoredInput))
{
return Vector2.zero;
}
InputDevice inputDevice = GetInputDevice(handSide);
if (inputDevice.isValid)
{
Vector2 value;
switch (input2D)
{
case UxrInput2D.Joystick:
if (inputDevice.TryGetFeatureValue(CommonUsages.primary2DAxis, out value))
{
return FilterTwoAxesDeadZone(value, JoystickDeadZone);
}
break;
case UxrInput2D.Joystick2:
if (inputDevice.TryGetFeatureValue(CommonUsages.secondary2DAxis, out value))
{
return FilterTwoAxesDeadZone(value, JoystickDeadZone);
}
break;
}
}
return Vector2.zero;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
UxrControllerInputCapabilities capabilities = 0;
InputDevice inputDevice = GetInputDevice(handSide);
if (!inputDevice.isValid)
{
return capabilities;
}
if (inputDevice.TryGetHapticCapabilities(out HapticCapabilities hapticCapabilities))
{
if (hapticCapabilities.supportsBuffer)
{
capabilities |= UxrControllerInputCapabilities.HapticClips;
}
if (hapticCapabilities.supportsImpulse)
{
capabilities |= UxrControllerInputCapabilities.HapticImpulses;
}
}
return capabilities;
}
/// <inheritdoc />
public override void SendHapticFeedback(UxrHandSide handSide, UxrHapticClip hapticClip)
{
InputDevice inputDevice = GetInputDevice(handSide);
if (!inputDevice.isValid)
{
return;
}
if (hapticClip == null)
{
return;
}
if (!inputDevice.TryGetHapticCapabilities(out HapticCapabilities hapticCapabilities))
{
return;
}
if (hapticClip.Clip == null || !hapticCapabilities.supportsBuffer)
{
SendHapticFeedback(handSide,
hapticClip.FallbackClipType,
hapticClip.FallbackAmplitude,
hapticClip.FallbackDurationSeconds,
hapticClip.HapticMode);
return;
}
// Create haptics clip from audio
byte[] hapticBuffer = CreateHapticBufferFromAudioClip(inputDevice, hapticClip.Clip);
if (hapticBuffer == null)
{
SendHapticFeedback(handSide,
hapticClip.FallbackClipType,
hapticClip.FallbackAmplitude,
hapticClip.FallbackDurationSeconds,
hapticClip.HapticMode);
return;
}
// Readjust amplitude?
if (Mathf.Approximately(hapticClip.ClipAmplitude, 1.0f) == false)
{
for (int i = 0; i < hapticBuffer.Length; ++i)
{
hapticBuffer[i] = (byte)Mathf.Clamp(Mathf.RoundToInt(hapticBuffer[i] * hapticClip.ClipAmplitude), 0, 255);
}
}
// Send using replace or mix
uint channel = 0;
if (hapticClip.HapticMode == UxrHapticMode.Mix && hapticCapabilities.numChannels > 0)
{
if (handSide == UxrHandSide.Left)
{
_leftHapticChannel = (_leftHapticChannel + 1) % hapticCapabilities.numChannels;
channel = _leftHapticChannel;
}
else
{
_rightHapticChannel = (_rightHapticChannel + 1) % hapticCapabilities.numChannels;
channel = _rightHapticChannel;
}
}
else
{
inputDevice.StopHaptics();
_leftHapticChannel = 0;
_rightHapticChannel = 0;
}
inputDevice.SendHapticBuffer(channel, hapticBuffer);
}
/// <inheritdoc />
public override void SendHapticFeedback(UxrHandSide handSide,
float frequency,
float amplitude,
float durationSeconds,
UxrHapticMode hapticMode = UxrHapticMode.Mix)
{
InputDevice inputDevice = GetInputDevice(handSide);
if (!inputDevice.isValid)
{
return;
}
if (!inputDevice.TryGetHapticCapabilities(out HapticCapabilities hapticCapabilities))
{
return;
}
// Setup using replace or mix
uint channel = 0;
if (hapticMode == UxrHapticMode.Mix && hapticCapabilities.numChannels > 0)
{
if (handSide == UxrHandSide.Left)
{
_leftHapticChannel = (_leftHapticChannel + 1) % hapticCapabilities.numChannels;
channel = _leftHapticChannel;
}
else
{
_rightHapticChannel = (_rightHapticChannel + 1) % hapticCapabilities.numChannels;
channel = _rightHapticChannel;
}
}
else
{
inputDevice.StopHaptics();
_leftHapticChannel = 0;
_rightHapticChannel = 0;
}
// Send
if (hapticCapabilities.supportsBuffer)
{
byte[] samples = new byte[(int)(hapticCapabilities.bufferFrequencyHz * durationSeconds)];
int steps = frequency > 0.0f ? Mathf.RoundToInt(hapticCapabilities.bufferFrequencyHz / frequency) : -1;
byte sample = (byte)Mathf.Clamp(amplitude * 255.0f, 0, 255.0f);
for (int i = 0; i < samples.Length; ++i)
{
if (steps < 2)
{
samples[i] = sample;
}
else
{
samples[i] = i % steps == 0 ? sample : (byte)0;
}
}
inputDevice.SendHapticBuffer(channel, samples);
}
else if (hapticCapabilities.supportsImpulse)
{
inputDevice.SendHapticImpulse(channel, amplitude, durationSeconds);
}
}
/// <inheritdoc />
public override void StopHapticFeedback(UxrHandSide handSide)
{
InputDevice inputDevice = GetInputDevice(handSide);
if (!inputDevice.isValid)
{
return;
}
inputDevice.StopHaptics();
}
#endregion
#region Unity
/// <summary>
/// Initializes variables and subscribes to events.
/// If the controllers were already initialized, enables the component. Otherwise it begins disabled until devices are
/// connected.
/// </summary>
protected override void Awake()
{
base.Awake();
_leftHapticChannel = 0;
_rightHapticChannel = 0;
if (enabled)
{
InputDevices.deviceConnected += InputDevices_DeviceConnected;
InputDevices.deviceDisconnected += InputDevices_DeviceDisconnected;
// Check if the device is already connected. This may happen if a new scene was loaded, because
// the connection events were already triggered and processed. We should have them registered in
// our static fields.
_deviceLeft = s_activeInputDevices.FirstOrDefault(d => ControllerNames.Any(n => string.Equals(d.name, n)) && IsLeftController(d));
_deviceRight = s_activeInputDevices.FirstOrDefault(d => ControllerNames.Any(n => string.Equals(d.name, n)) && IsRightController(d));
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevices(devices);
if (!_deviceLeft.isValid)
{
_deviceLeft = devices.FirstOrDefault(d => ControllerNames.Any(n => string.Equals(d.name, n)) && IsLeftController(d));
}
if (!_deviceRight.isValid)
{
_deviceRight = devices.FirstOrDefault(d => ControllerNames.Any(n => string.Equals(d.name, n)) && IsRightController(d));
}
enabled = _deviceLeft.isValid || _deviceRight.isValid;
RaiseConnectOnStart = enabled;
}
}
/// <summary>
/// Unsubscribes from device events.
/// </summary>
protected override void OnDestroy()
{
base.OnDestroy();
InputDevices.deviceConnected -= InputDevices_DeviceConnected;
InputDevices.deviceDisconnected -= InputDevices_DeviceDisconnected;
}
#endregion
#region Event Handling Methods
/// <summary>
/// Event called when a device is connected. Check for compatible devices.
/// </summary>
/// <param name="inputDevice">The device that was connected</param>
private void InputDevices_DeviceConnected(InputDevice inputDevice)
{
// Check if device is compatible with component
if (ForceUseAlways || ControllerNames.Any(n => string.Equals(n, inputDevice.name)))
{
// Found compatible device. Look for features.
List<InputFeatureUsage> listFeatures = new List<InputFeatureUsage>();
bool isController = false;
// Check for controllers and side
if (IsLeftController(inputDevice))
{
// Left controller
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceConnected)}: Device name {inputDevice.name} was registered by {InputClassName} and is being processed as left controller. InputDevice.isValid={inputDevice.isValid}");
}
_deviceLeft = inputDevice;
isController = true;
}
else if (IsRightController(inputDevice))
{
// Right controller
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceConnected)}: Device name {inputDevice.name} was registered by {InputClassName} and is being processed as right controller. InputDevice.isValid={inputDevice.isValid}");
}
_deviceRight = inputDevice;
isController = true;
}
if (isController)
{
// Register active device
s_activeInputDevices.Add(inputDevice);
if (!enabled)
{
// Component is disabled. Enable it and send Connected event.
enabled = true;
OnDeviceConnected(new UxrDeviceConnectEventArgs(true));
}
}
}
else
{
// Check for controllers and side
if (IsLeftController(inputDevice))
{
// Left controller
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceConnected)}: Left device connected unknown: {inputDevice.name}. InputDevice.isValid={inputDevice.isValid}");
}
}
else if (IsRightController(inputDevice))
{
// Right controller
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceConnected)}: Right device connected unknown: {inputDevice.name}. InputDevice.isValid={inputDevice.isValid}");
}
}
}
}
/// <summary>
/// Event called when a device is disconnected. We use it to update our internal lists.
/// </summary>
/// <param name="inputDevice">The device that was disconnected</param>
private void InputDevices_DeviceDisconnected(InputDevice inputDevice)
{
// Check if device is compatible with component
if (ForceUseAlways || ControllerNames.Any(n => string.Equals(n, inputDevice.name)))
{
if (string.Equals(inputDevice.serialNumber, _deviceLeft.serialNumber) || string.Equals(inputDevice.serialNumber, _deviceRight.serialNumber))
{
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceDisconnected)}: Device name {inputDevice.name} was registered by {InputClassName} and is being disconnected. InputDevice.isValid={inputDevice.isValid}");
}
}
// Unregister device
s_activeInputDevices.RemoveAll(i => string.Equals(i.name, inputDevice.name));
// If last device was disconnected, disable component. Component will be re-enabled using connection event.
if (enabled && !_deviceLeft.isValid && !_deviceRight.isValid)
{
enabled = false;
OnDeviceConnected(new UxrDeviceConnectEventArgs(false));
}
}
}
#endregion
#region Protected Overrides UxrControllerInput
/// <summary>
/// Updates the input state. This should not be called by the user since it is called by the framework already.
/// </summary>
protected override void UpdateInput()
{
base.UpdateInput();
bool buttonPressTriggerLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Trigger, ButtonContact.Press);
bool buttonPressTriggerRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Trigger, ButtonContact.Press);
bool buttonPressTrigger2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Trigger2, ButtonContact.Press);
bool buttonPressTrigger2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Trigger2, ButtonContact.Press);
bool buttonPressJoystickLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Joystick, ButtonContact.Press);
bool buttonPressJoystickRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Joystick, ButtonContact.Press);
bool buttonPressJoystick2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Joystick2, ButtonContact.Press);
bool buttonPressJoystick2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Joystick2, ButtonContact.Press);
bool buttonPressButton1Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button1, ButtonContact.Press);
bool buttonPressButton1Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button1, ButtonContact.Press);
bool buttonPressButton2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button2, ButtonContact.Press);
bool buttonPressButton2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button2, ButtonContact.Press);
bool buttonPressButton3Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button3, ButtonContact.Press);
bool buttonPressButton3Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button3, ButtonContact.Press);
bool buttonPressButton4Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button4, ButtonContact.Press);
bool buttonPressButton4Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button4, ButtonContact.Press);
bool buttonPressBumperLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Bumper, ButtonContact.Press);
bool buttonPressBumperRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Bumper, ButtonContact.Press);
bool buttonPressBumper2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Bumper2, ButtonContact.Press);
bool buttonPressBumper2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Bumper2, ButtonContact.Press);
bool buttonPressMenuLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Menu, ButtonContact.Press);
bool buttonPressMenuRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Menu, ButtonContact.Press);
bool buttonPressGripLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Grip, ButtonContact.Press);
bool buttonPressGripRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Grip, ButtonContact.Press);
bool buttonPressThumbCapSenseLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.ThumbCapSense, ButtonContact.Press);
bool buttonPressThumbCapSenseRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.ThumbCapSense, ButtonContact.Press);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Trigger, buttonPressTriggerLeft);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Trigger, buttonPressTriggerRight);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Trigger2, buttonPressTrigger2Left);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Trigger2, buttonPressTrigger2Right);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick, buttonPressJoystickLeft);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Joystick, buttonPressJoystickRight);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2, buttonPressJoystick2Left);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Joystick2, buttonPressJoystick2Right);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button1, buttonPressButton1Left);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Button1, buttonPressButton1Right);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button2, buttonPressButton2Left);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Button2, buttonPressButton2Right);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button3, buttonPressButton3Left);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Button3, buttonPressButton3Right);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button4, buttonPressButton4Left);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Button4, buttonPressButton4Right);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper, buttonPressBumperLeft);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Bumper, buttonPressBumperRight);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper2, buttonPressBumper2Left);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Bumper2, buttonPressBumper2Right);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Menu, buttonPressMenuLeft);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Menu, buttonPressMenuRight);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Grip, buttonPressGripLeft);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Grip, buttonPressGripRight);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.ThumbCapSense, buttonPressThumbCapSenseLeft);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.ThumbCapSense, buttonPressThumbCapSenseRight);
bool buttonTouchTriggerLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Trigger, ButtonContact.Touch);
bool buttonTouchTriggerRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Trigger, ButtonContact.Touch);
bool buttonTouchTrigger2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Trigger2, ButtonContact.Touch);
bool buttonTouchTrigger2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Trigger2, ButtonContact.Touch);
bool buttonTouchJoystickLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Joystick, ButtonContact.Touch);
bool buttonTouchJoystickRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Joystick, ButtonContact.Touch);
bool buttonTouchJoystick2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Joystick2, ButtonContact.Touch);
bool buttonTouchJoystick2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Joystick2, ButtonContact.Touch);
bool buttonTouchButton1Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button1, ButtonContact.Touch);
bool buttonTouchButton1Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button1, ButtonContact.Touch);
bool buttonTouchButton2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button2, ButtonContact.Touch);
bool buttonTouchButton2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button2, ButtonContact.Touch);
bool buttonTouchButton3Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button3, ButtonContact.Touch);
bool buttonTouchButton3Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button3, ButtonContact.Touch);
bool buttonTouchButton4Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button4, ButtonContact.Touch);
bool buttonTouchButton4Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button4, ButtonContact.Touch);
bool buttonTouchBumperLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Bumper, ButtonContact.Touch);
bool buttonTouchBumperRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Bumper, ButtonContact.Touch);
bool buttonTouchBumper2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Bumper2, ButtonContact.Touch);
bool buttonTouchBumper2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Bumper2, ButtonContact.Touch);
bool buttonTouchMenuLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Menu, ButtonContact.Touch);
bool buttonTouchMenuRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Menu, ButtonContact.Touch);
bool buttonTouchGripLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Grip, ButtonContact.Touch);
bool buttonTouchGripRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Grip, ButtonContact.Touch);
bool buttonTouchThumbCapSenseLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.ThumbCapSense, ButtonContact.Touch);
bool buttonTouchThumbCapSenseRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.ThumbCapSense, ButtonContact.Touch);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Trigger, buttonTouchTriggerLeft);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Trigger, buttonTouchTriggerRight);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Trigger2, buttonTouchTrigger2Left);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Trigger2, buttonTouchTrigger2Right);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Joystick, buttonTouchJoystickLeft);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Joystick, buttonTouchJoystickRight);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Joystick2, buttonTouchJoystick2Left);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Joystick2, buttonTouchJoystick2Right);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Button1, buttonTouchButton1Left);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Button1, buttonTouchButton1Right);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Button2, buttonTouchButton2Left);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Button2, buttonTouchButton2Right);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Button3, buttonTouchButton3Left);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Button3, buttonTouchButton3Right);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Button4, buttonTouchButton4Left);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Button4, buttonTouchButton4Right);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Bumper, buttonTouchBumperLeft);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Bumper, buttonTouchBumperRight);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Bumper2, buttonTouchBumper2Left);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Bumper2, buttonTouchBumper2Right);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Menu, buttonTouchMenuLeft);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Menu, buttonTouchMenuRight);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Grip, buttonTouchGripLeft);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Grip, buttonTouchGripRight);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.ThumbCapSense, buttonTouchThumbCapSenseLeft);
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.ThumbCapSense, buttonTouchThumbCapSenseRight);
Vector2 leftJoystick = GetInput2D(UxrHandSide.Left, UxrInput2D.Joystick, true);
Vector2 leftDPad = leftJoystick; // Mapped to joystick by default
if (leftJoystick != Vector2.zero && leftJoystick.magnitude > AnalogAsDPadThreshold)
{
float joystickAngle = Input2DToAngle(leftJoystick);
bool touchPadFix = !MainJoystickIsTouchpad || buttonPressJoystickLeft;
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, touchPadFix && IsInput2dDPadLeft(joystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, touchPadFix && IsInput2dDPadRight(joystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, touchPadFix && IsInput2dDPadUp(joystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, touchPadFix && IsInput2dDPadDown(joystickAngle));
}
else
{
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, false);
}
if (leftDPad != Vector2.zero && leftDPad.magnitude > AnalogAsDPadThreshold)
{
float dPadAngle = Input2DToAngle(leftDPad);
bool touchPadFix = !MainJoystickIsTouchpad || buttonPressJoystickLeft;
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, touchPadFix && IsInput2dDPadLeft(dPadAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, touchPadFix && IsInput2dDPadRight(dPadAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, touchPadFix && IsInput2dDPadUp(dPadAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, touchPadFix && IsInput2dDPadDown(dPadAngle));
}
else
{
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, false);
}
Vector2 rightJoystick = GetInput2D(UxrHandSide.Right, UxrInput2D.Joystick, true);
Vector2 rightDPad = rightJoystick; // Mapped to joystick by default
if (rightJoystick != Vector2.zero && rightJoystick.magnitude > AnalogAsDPadThreshold)
{
float joystickAngle = Input2DToAngle(rightJoystick);
bool touchPadFix = !MainJoystickIsTouchpad || buttonPressJoystickRight;
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickLeft, touchPadFix && IsInput2dDPadLeft(joystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickRight, touchPadFix && IsInput2dDPadRight(joystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickUp, touchPadFix && IsInput2dDPadUp(joystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickDown, touchPadFix && IsInput2dDPadDown(joystickAngle));
}
else
{
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickLeft, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickRight, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickUp, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickDown, false);
}
if (rightDPad != Vector2.zero && rightDPad.magnitude > AnalogAsDPadThreshold)
{
float dPadAngle = Input2DToAngle(rightDPad);
bool touchPadFix = !MainJoystickIsTouchpad || buttonPressJoystickRight;
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadLeft, touchPadFix && IsInput2dDPadLeft(dPadAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadRight, touchPadFix && IsInput2dDPadRight(dPadAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadUp, touchPadFix && IsInput2dDPadUp(dPadAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadDown, touchPadFix && IsInput2dDPadDown(dPadAngle));
}
else
{
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadLeft, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadRight, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadUp, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadDown, false);
}
}
#endregion
#region Protected Methods
/// <summary>
/// Checks whether a non-standard button in a controller is currently being touched or pressed.
/// </summary>
/// <param name="handSide">Which controller side to check</param>
/// <param name="button">Button to check</param>
/// <param name="buttonContact">Type of contact to check for (touch or press)</param>
/// <returns>Boolean telling whether the specified button has contact</returns>
protected virtual bool HasButtonContactOther(UxrHandSide handSide, UxrInputButtons button, ButtonContact buttonContact)
{
return false;
}
/// <summary>
/// Gets the input device interface in Unity's input system for a given hand.
/// Usually if it is a left+right setup it will give a list with a single entry but the system is very generic
/// so it is prepared to handle different setups.
/// Normally we get the list and just use the first entry if available.
/// </summary>
/// <param name="handSide">Hand to get the input devices for</param>
/// <returns><see cref="InputDevice" /> representing the input device</returns>
protected InputDevice GetInputDevice(UxrHandSide handSide)
{
return handSide == UxrHandSide.Left ? _deviceLeft : _deviceRight;
}
/// <summary>
/// Using an audio file, creates a haptic samples buffer that can be sent for feedback.
/// This code is based on the Oculus SDK (OVRHaptics.cs).
/// </summary>
/// <param name="inputDevice">Unity input device that will be the feedback target</param>
/// <param name="audioClip">Audio clip whose audio sample will be used to create haptics</param>
/// <returns>Buffer that can be sent to the device as haptic feedback</returns>
protected byte[] CreateHapticBufferFromAudioClip(InputDevice inputDevice, AudioClip audioClip)
{
float[] audioData = new float[audioClip.samples * audioClip.channels];
audioClip.GetData(audioData, 0);
if (!inputDevice.TryGetHapticCapabilities(out HapticCapabilities hapticCapabilities) || !hapticCapabilities.supportsBuffer)
{
return null;
}
if (hapticCapabilities.bufferFrequencyHz == 0)
{
return null;
}
double stepSizePrecise = (audioClip.frequency + 1e-6) / hapticCapabilities.bufferFrequencyHz;
if (stepSizePrecise < 1.0)
{
return null;
}
int stepSize = (int)stepSizePrecise;
double stepSizeError = stepSizePrecise - stepSize;
int length = audioData.Length;
double accumStepSizeError = 0.0f;
byte[] samples = new byte[length];
int i = 0;
int s = 0;
while (i < length)
{
byte sample = (byte)(Mathf.Clamp01(Mathf.Abs(audioData[i])) * byte.MaxValue);
if (s < samples.Length)
{
samples[s] = sample;
s++;
}
else
{
break;
}
i += stepSize * audioClip.channels;
accumStepSizeError += stepSizeError;
if ((int)accumStepSizeError > 0)
{
i += (int)accumStepSizeError * audioClip.channels;
accumStepSizeError = accumStepSizeError - (int)accumStepSizeError;
}
}
return samples;
}
#endregion
#region Private Methods
/// <summary>
/// Gets if the given input device is a left side VR controller
/// </summary>
/// <param name="inputDevice">Device to check</param>
/// <returns>Whether the given input device is a left side VR controller</returns>
private static bool IsLeftController(InputDevice inputDevice)
{
return inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left);
}
/// <summary>
/// Gets if the given input device is a right side VR controller
/// </summary>
/// <param name="inputDevice">Device to check</param>
/// <returns>Whether the given input device is a right side VR controller</returns>
private static bool IsRightController(InputDevice inputDevice)
{
return inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right);
}
/// <summary>
/// Checks whether the given button in a controller is currently being touched or pressed.
/// </summary>
/// <param name="handSide">Which controller side to check</param>
/// <param name="button">Button to check</param>
/// <param name="buttonContact">Type of contact to check for (touch or press)</param>
/// <returns>Boolean telling whether the specified button has contact</returns>
private bool HasButtonContact(UxrHandSide handSide, UxrInputButtons button, ButtonContact buttonContact)
{
InputDevice inputDevice = GetInputDevice(handSide);
if (!inputDevice.isValid)
{
return false;
}
if (button == UxrInputButtons.Joystick)
{
var featureUsage = buttonContact == ButtonContact.Press ? CommonUsages.primary2DAxisClick : CommonUsages.primary2DAxisTouch;
if (inputDevice.TryGetFeatureValue(featureUsage, out bool value))
{
return value;
}
}
else if (button == UxrInputButtons.Joystick2)
{
return false;
}
else if (button == UxrInputButtons.Trigger)
{
if (buttonContact == ButtonContact.Touch)
{
#if ULTIMATEXR_UNITY_XR_OCULUS
if (inputDevice.TryGetFeatureValue(OculusUsages.indexTouch, out bool valueTouch))
{
return valueTouch;
}
#endif
}
if (inputDevice.TryGetFeatureValue(CommonUsages.trigger, out float valueFloat))
{
// We try getting the float value first because in analog buttons like the oculus it will trigger too early with the bool version.
return valueFloat > AnalogAsDPadThreshold;
}
if (inputDevice.TryGetFeatureValue(CommonUsages.triggerButton, out bool value))
{
return value;
}
}
else if (button == UxrInputButtons.Trigger2)
{
return false;
}
else if (button == UxrInputButtons.Grip)
{
if (inputDevice.TryGetFeatureValue(CommonUsages.gripButton, out bool value))
{
return value;
}
}
else if (button == UxrInputButtons.Button1)
{
var featureUsage = buttonContact == ButtonContact.Press ? CommonUsages.primaryButton : CommonUsages.primaryTouch;
if (inputDevice.TryGetFeatureValue(featureUsage, out bool value))
{
return value;
}
}
else if (button == UxrInputButtons.Button2)
{
var featureUsage = buttonContact == ButtonContact.Press ? CommonUsages.secondaryButton : CommonUsages.secondaryTouch;
if (inputDevice.TryGetFeatureValue(featureUsage, out bool value))
{
return value;
}
}
else if (button == UxrInputButtons.Menu)
{
if (inputDevice.TryGetFeatureValue(CommonUsages.menuButton, out bool value))
{
return value;
}
}
else if (button == UxrInputButtons.ThumbCapSense)
{
if (buttonContact == ButtonContact.Press)
{
#if ULTIMATEXR_UNITY_XR_OCULUS
if (inputDevice.TryGetFeatureValue(OculusUsages.thumbrest, out bool value))
{
return value;
}
#endif
}
if (buttonContact == ButtonContact.Touch)
{
#if ULTIMATEXR_UNITY_XR_OCULUS
if (inputDevice.TryGetFeatureValue(OculusUsages.thumbTouch, out bool value))
{
return value;
}
#endif
}
}
else if (button == UxrInputButtons.IndexCapSense)
{
}
else if (button == UxrInputButtons.MiddleCapSense)
{
}
else if (button == UxrInputButtons.RingCapSense)
{
}
else if (button == UxrInputButtons.LittleCapSense)
{
}
return false;
}
#endregion
#region Private Types & Data
private string InputClassName => GetType().Name;
private static readonly List<InputDevice> s_activeInputDevices = new List<InputDevice>();
private InputDevice _deviceLeft;
private InputDevice _deviceRight;
private uint _leftHapticChannel;
private uint _rightHapticChannel;
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f85b57eaa39cce438201cb182d59147
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrUnityXRControllerTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Core.Settings;
using UnityEngine;
using UnityEngine.XR;
namespace UltimateXR.Devices.Integrations
{
/// <summary>
/// Base class for tracking devices based on OpenVR.
/// </summary>
public abstract class UxrUnityXRControllerTracking : UxrControllerTracking
{
#region Protected Overrides UxrTrackingDevice
/// <inheritdoc />
protected override void UpdateSensors()
{
base.UpdateSensors();
if (Avatar.CameraComponent == null)
{
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Warnings)
{
Debug.LogWarning($"{UxrConstants.DevicesModule}: No camera has been setup for this avatar");
}
return;
}
List<XRNodeState> nodeStates = new List<XRNodeState>();
InputTracking.GetNodeStates(nodeStates);
foreach (XRNodeState nodeState in nodeStates)
{
if (nodeState.nodeType == XRNode.LeftHand)
{
Vector3 localAvatarLeftHandSensorPos = LocalAvatarLeftHandSensorPos;
Quaternion localAvatarLeftHandSensorRot = LocalAvatarLeftHandSensorRot;
nodeState.TryGetRotation(out localAvatarLeftHandSensorRot);
nodeState.TryGetPosition(out localAvatarLeftHandSensorPos);
UpdateSensor(UxrHandSide.Left, localAvatarLeftHandSensorPos, localAvatarLeftHandSensorRot);
}
else if (nodeState.nodeType == XRNode.RightHand)
{
Vector3 localAvatarRightHandSensorPos = LocalAvatarRightHandSensorPos;
Quaternion localAvatarRightHandSensorRot = LocalAvatarRightHandSensorRot;
nodeState.TryGetRotation(out localAvatarRightHandSensorRot);
nodeState.TryGetPosition(out localAvatarRightHandSensorPos);
UpdateSensor(UxrHandSide.Right, localAvatarRightHandSensorPos, localAvatarRightHandSensorRot);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3e81ce09144eac54bb33e8bff7ddf811
timeCreated: 1499842642
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f38dee19b883b1342bf0816189bd9ce0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrValveIndexInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Core;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Valve
{
/// <summary>
/// Valve index controllers. Also known as Knuckles.
/// </summary>
public class UxrValveIndexInput : UxrSteamVRControllerInput
{
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override UxrControllerSetupType SetupType => UxrControllerSetupType.Dual;
/// <inheritdoc />
public override bool MainJoystickIsTouchpad => false;
/// <inheritdoc />
public override bool HasControllerElements(UxrHandSide handSide, UxrControllerElements controllerElements)
{
uint validElements = (uint)(UxrControllerElements.Joystick | // Joystick
UxrControllerElements.Joystick2 | // Trackpad
UxrControllerElements.Grip | // Grip
UxrControllerElements.Trigger | // Trigger
UxrControllerElements.Button1 | // Button A
UxrControllerElements.Button2 | // Button B
UxrControllerElements.DPad); // Joystick
return (validElements & (uint)controllerElements) == (uint)controllerElements;
}
/// <inheritdoc />
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
{
return UxrControllerInputCapabilities.HapticImpulses | UxrControllerInputCapabilities.TrackedHandPose;
}
#endregion
#region Public Overrides UxrSteamVRControllerInput
/// <inheritdoc />
public override IEnumerable<string> ControllerNames
{
get
{
yield return "indexcontroller";
yield return "Knuckles EV3.0 Left";
yield return "Knuckles EV3.0 Right";
yield return "Knuckles EV2.0 Left";
yield return "Knuckles EV2.0 Right";
yield return "Knuckles Left";
yield return "Knuckles Right";
}
}
/// <inheritdoc />
public override bool UsesHandSkeletons => true;
#endregion
#region Protected Overrides UxrSteamVRControllerInput
/// <inheritdoc />
protected override void UpdateInput()
{
base.UpdateInput();
// Propagate touchpad touch to press, since only touch is signaled by the API
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2, GetButtonsTouch(UxrHandSide.Left, UxrInputButtons.Joystick2));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Joystick2, GetButtonsTouch(UxrHandSide.Right, UxrInputButtons.Joystick2));
// Propagate grip touch to press, since only touch is signaled by the API
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Grip, GetButtonsTouch(UxrHandSide.Left, UxrInputButtons.Grip));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Grip, GetButtonsTouch(UxrHandSide.Right, UxrInputButtons.Grip));
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d38a842ac6135e64babe0def2b78c7f0
timeCreated: 1499677449
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrValveIndexTracking.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Devices.Integrations.SteamVR;
namespace UltimateXR.Devices.Integrations.Valve
{
/// <summary>
/// Tracking component for Valve Index controllers, also known as Knuckles, using SteamVR.
/// </summary>
public class UxrValveIndexTracking : UxrSteamVRControllerTracking
{
#region Public Overrides UxrControllerTracking
/// <inheritdoc />
public override Type RelatedControllerInputType => typeof(UxrValveIndexInput);
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c210797670b3ccb4faa0d527c28face7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: