2021년 4학년 1학기 기업연계프로젝트2 컴퓨터소프트웨어공학과 <원광투어팀> 팀장 : 송유진 팀원 : 김나영, 이경희, 한유진
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1034 lines
48 KiB

//========= Copyright 2016-2020, HTC Corporation. All rights reserved. ===========
using HTC.UnityPlugin.Utility;
using HTC.UnityPlugin.Vive;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
#if UNITY_2017_2_OR_NEWER
using UnityEngine.XR;
#endif
#if VIU_XR_GENERAL_SETTINGS
using UnityEngine.XR.Management;
using UnityEngine.SpatialTracking;
using System;
#if VIU_WAVEXR_ESSENCE_RENDERMODEL
using Wave.Essence;
#endif
#endif
namespace HTC.UnityPlugin.VRModuleManagement
{
public enum XRInputSubsystemType
{
Unknown,
OpenVR,
Oculus,
WMR,
MagicLeap,
}
public sealed class UnityXRModule : VRModule.ModuleBase
{
public override int moduleOrder { get { return (int)DefaultModuleOrder.UnityXR; } }
public override int moduleIndex { get { return (int)VRModuleSelectEnum.UnityXR; } }
public const string WAVE_XR_LOADER_NAME = "Wave XR Loader";
public const string WAVE_XR_LOADER_CLASS_NAME = "WaveXRLoader";
#if UNITY_2019_3_OR_NEWER && VIU_XR_GENERAL_SETTINGS
private class CameraCreator : VRCameraHook.CameraCreator
{
public override bool shouldActive { get { return s_moduleInstance != null && s_moduleInstance.isActivated; } }
public override void CreateCamera(VRCameraHook hook)
{
if (hook.GetComponent<TrackedPoseDriver>() == null)
{
hook.gameObject.AddComponent<TrackedPoseDriver>();
}
}
}
[RenderModelHook.CreatorPriorityAttirbute(0)]
private class RenderModelCreator : RenderModelHook.DefaultRenderModelCreator
{
#if VIU_WAVEXR_ESSENCE_RENDERMODEL
private uint m_index = INVALID_DEVICE_INDEX;
#endif
public override bool shouldActive { get { return s_moduleInstance == null ? false : s_moduleInstance.isActivated; } }
public override void UpdateRenderModel()
{
#if VIU_WAVEXR_ESSENCE_RENDERMODEL
if (HasActiveLoader(WAVE_XR_LOADER_NAME))
{
if (!ChangeProp.Set(ref m_index, hook.GetModelDeviceIndex())) { return; }
if (VRModule.IsValidDeviceIndex(m_index) && m_index == VRModule.GetRightControllerDeviceIndex())
{
var go = new GameObject("Model");
go.transform.SetParent(hook.transform, false);
go.AddComponent<Wave.Essence.Controller.RenderModel>();
go.AddComponent<Wave.Essence.Controller.ButtonEffect>();
go.AddComponent<Wave.Essence.Controller.ShowIndicator>();
}
else if (VRModule.IsValidDeviceIndex(m_index) && m_index == VRModule.GetLeftControllerDeviceIndex())
{
var go = new GameObject("Model");
go.transform.SetParent(hook.transform, false);
var rm = go.AddComponent<Wave.Essence.Controller.RenderModel>();
rm.transform.gameObject.SetActive(false);
rm.WhichHand = XR_Hand.NonDominant;
rm.transform.gameObject.SetActive(true);
var be = go.AddComponent<Wave.Essence.Controller.ButtonEffect>();
be.transform.gameObject.SetActive(false);
be.HandType = XR_Hand.NonDominant;
be.transform.gameObject.SetActive(true);
go.AddComponent<Wave.Essence.Controller.ShowIndicator>();
}
else
{
// deacitvate object for render model
if (m_model != null)
{
m_model.gameObject.SetActive(false);
}
}
}
else
#endif
{
base.UpdateRenderModel();
}
}
}
private class HapticVibrationState
{
public uint deviceIndex;
public float amplitude;
public float remainingDuration;
public float remainingDelay;
public HapticVibrationState(uint index, float amp, float duration, float delay)
{
deviceIndex = index;
amplitude = amp;
remainingDuration = duration;
remainingDelay = delay;
}
}
private const uint DEVICE_STATE_LENGTH = 16;
private static UnityXRModule s_moduleInstance;
private XRInputSubsystemType m_currentInputSubsystemType = XRInputSubsystemType.Unknown;
private uint m_rightHandedDeviceIndex = INVALID_DEVICE_INDEX;
private uint m_leftHandedDeviceIndex = INVALID_DEVICE_INDEX;
private Dictionary<int, uint> m_deviceUidToIndex = new Dictionary<int, uint>();
private List<InputDevice> m_indexToDevices = new List<InputDevice>();
private List<InputDevice> m_connectedDevices = new List<InputDevice>();
private List<HapticVibrationState> m_activeHapticVibrationStates = new List<HapticVibrationState>();
public static bool HasActiveLoader(string loaderName = null)
{
var instance = XRGeneralSettings.Instance;
if (instance == null) { return false; }
var manager = instance.Manager;
if (manager == null) { return false; }
var loader = manager.activeLoader;
if (loader == null) { return false; }
if (loaderName != null && loaderName != loader.name) { return false; }
return true;
}
public override bool ShouldActiveModule()
{
return VIUSettings.activateUnityXRModule && HasActiveLoader();
}
public override void OnActivated()
{
s_moduleInstance = this;
m_currentInputSubsystemType = DetectCurrentInputSubsystemType();
EnsureDeviceStateLength(DEVICE_STATE_LENGTH);
UpdateTrackingSpaceType();
Debug.Log("Activated XRLoader Name: " + XRGeneralSettings.Instance.Manager.activeLoader.name);
}
public override void OnDeactivated()
{
s_moduleInstance = null;
m_deviceUidToIndex.Clear();
m_indexToDevices.Clear();
m_connectedDevices.Clear();
}
public override uint GetLeftControllerDeviceIndex() { return m_leftHandedDeviceIndex; }
public override uint GetRightControllerDeviceIndex() { return m_rightHandedDeviceIndex; }
public override void UpdateTrackingSpaceType()
{
switch (VRModule.trackingSpaceType)
{
case VRModuleTrackingSpaceType.Stationary:
SetAllXRInputSubsystemTrackingOriginMode(TrackingOriginModeFlags.Device);
break;
case VRModuleTrackingSpaceType.RoomScale:
SetAllXRInputSubsystemTrackingOriginMode(TrackingOriginModeFlags.Floor);
break;
}
}
// NOTE: Frequency not supported
public override void TriggerHapticVibration(uint deviceIndex, float durationSeconds = 0.01f, float frequency = 85.0f, float amplitude = 0.125f, float startSecondsFromNow = 0.0f)
{
InputDevice device;
if (TryGetDevice(deviceIndex, out device))
{
if (!device.isValid)
{
return;
}
HapticCapabilities capabilities;
if (device.TryGetHapticCapabilities(out capabilities))
{
if (capabilities.supportsImpulse)
{
for (int i = m_activeHapticVibrationStates.Count - 1; i >= 0; i--)
{
if (m_activeHapticVibrationStates[i].deviceIndex == deviceIndex)
{
m_activeHapticVibrationStates.RemoveAt(i);
}
}
m_activeHapticVibrationStates.Add(new HapticVibrationState(deviceIndex, amplitude, durationSeconds, startSecondsFromNow));
}
}
}
}
public override void Update()
{
UpdateLockPhysicsUpdateRate();
UpdateHapticVibration();
}
public override void BeforeRenderUpdate()
{
IVRModuleDeviceState prevState;
IVRModuleDeviceStateRW currState;
uint deviceIndex;
FlushDeviceState();
// mark all devices as disconnected
deviceIndex = 0u;
while (TryGetValidDeviceState(deviceIndex++, out prevState, out currState))
{
currState.isConnected = false;
}
bool roleChanged = false;
InputDevices.GetDevices(m_connectedDevices);
foreach (InputDevice device in m_connectedDevices)
{
deviceIndex = GetOrCreateDeviceIndex(device);
EnsureValidDeviceState(deviceIndex, out prevState, out currState);
if (!prevState.isConnected)
{
currState.deviceClass = GetDeviceClass(device.name, device.characteristics);
currState.serialNumber = device.name + " " + device.serialNumber + " " + (int)device.characteristics;
currState.modelNumber = device.name;
currState.renderModelName = device.name;
SetupKnownDeviceModel(currState);
if ((device.characteristics & InputDeviceCharacteristics.Left) > 0u)
{
m_leftHandedDeviceIndex = deviceIndex;
roleChanged = true;
}
else if ((device.characteristics & InputDeviceCharacteristics.Right) > 0u)
{
m_rightHandedDeviceIndex = deviceIndex;
roleChanged = true;
}
Debug.LogFormat("Device connected: {0} / {1} / {2} / {3} / {4} / {5} ({6})", deviceIndex, currState.deviceClass, currState.deviceModel, currState.modelNumber, currState.serialNumber, device.name, device.characteristics);
}
bool isTracked = false;
device.TryGetFeatureValue(CommonUsages.isTracked, out isTracked);
currState.isPoseValid = device.isValid && isTracked;
currState.isConnected = true;
UpdateTrackingState(currState, device);
if (currState.deviceClass == VRModuleDeviceClass.Controller || currState.deviceModel == VRModuleDeviceModel.ViveTracker)
{
UpdateControllerState(currState, device);
}
}
//UpdateHandHeldDeviceIndex();
deviceIndex = 0u;
// reset all devices that is not connected in this frame
while (TryGetValidDeviceState(deviceIndex, out prevState, out currState))
{
if (!currState.isConnected)
{
currState.Reset();
if (deviceIndex == m_leftHandedDeviceIndex)
{
m_leftHandedDeviceIndex = VRModule.INVALID_DEVICE_INDEX;
roleChanged = true;
}
else if (deviceIndex == m_rightHandedDeviceIndex)
{
m_rightHandedDeviceIndex = VRModule.INVALID_DEVICE_INDEX;
roleChanged = true;
}
}
++deviceIndex;
}
if (roleChanged) { InvokeControllerRoleChangedEvent(); }
ProcessConnectedDeviceChanged();
ProcessDevicePoseChanged();
ProcessDeviceInputChanged();
}
private void UpdateLockPhysicsUpdateRate()
{
if (VRModule.lockPhysicsUpdateRateToRenderFrequency && Time.timeScale > 0.0f)
{
List<XRDisplaySubsystem> displaySystems = new List<XRDisplaySubsystem>();
SubsystemManager.GetInstances<XRDisplaySubsystem>(displaySystems);
float minRefreshRate = float.MaxValue;
foreach (XRDisplaySubsystem system in displaySystems)
{
float rate = 60.0f;
if (system.TryGetDisplayRefreshRate(out rate))
{
if (rate < minRefreshRate)
{
minRefreshRate = rate;
}
}
}
if (minRefreshRate > 0 && minRefreshRate < float.MaxValue)
{
Time.fixedDeltaTime = 1.0f / minRefreshRate;
}
}
}
private void UpdateHapticVibration()
{
for (int i = m_activeHapticVibrationStates.Count - 1; i >= 0; i--)
{
HapticVibrationState state = m_activeHapticVibrationStates[i];
if (state.remainingDelay > 0.0f)
{
state.remainingDelay -= Time.deltaTime;
continue;
}
InputDevice device;
if (TryGetDevice(state.deviceIndex, out device))
{
if (device.isValid)
{
device.SendHapticImpulse(0, state.amplitude);
}
}
state.remainingDuration -= Time.deltaTime;
if (state.remainingDuration <= 0)
{
m_activeHapticVibrationStates.RemoveAt(i);
}
}
}
private void UpdateTrackingState(IVRModuleDeviceStateRW state, InputDevice device)
{
Vector3 position = Vector3.zero;
if (device.TryGetFeatureValue(CommonUsages.devicePosition, out position))
{
state.position = position;
}
Quaternion rotation = Quaternion.identity;
if (device.TryGetFeatureValue(CommonUsages.deviceRotation, out rotation))
{
state.rotation = rotation;
}
Vector3 velocity = Vector3.zero;
if (device.TryGetFeatureValue(CommonUsages.deviceVelocity, out velocity))
{
state.velocity = velocity;
}
Vector3 angularVelocity = Vector3.zero;
if (device.TryGetFeatureValue(CommonUsages.deviceAngularVelocity, out angularVelocity))
{
state.angularVelocity = angularVelocity;
}
}
private void UpdateControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
switch (state.deviceModel)
{
case VRModuleDeviceModel.ViveController:
UpdateViveControllerState(state, device);
break;
case VRModuleDeviceModel.ViveCosmosControllerLeft:
case VRModuleDeviceModel.ViveCosmosControllerRight:
UpdateViveCosmosControllerState(state, device);
break;
case VRModuleDeviceModel.ViveTracker:
UpdateViveTrackerState(state, device);
break;
case VRModuleDeviceModel.OculusTouchLeft:
case VRModuleDeviceModel.OculusTouchRight:
case VRModuleDeviceModel.OculusGoController:
case VRModuleDeviceModel.OculusQuestControllerLeft:
case VRModuleDeviceModel.OculusQuestControllerRight:
UpdateOculusControllerState(state, device);
break;
case VRModuleDeviceModel.WMRControllerLeft:
case VRModuleDeviceModel.WMRControllerRight:
UpdateWMRControllerState(state, device);
break;
case VRModuleDeviceModel.KnucklesLeft:
case VRModuleDeviceModel.KnucklesRight:
case VRModuleDeviceModel.IndexControllerLeft:
case VRModuleDeviceModel.IndexControllerRight:
UpdateIndexControllerState(state, device);
break;
case VRModuleDeviceModel.MagicLeapController:
UpdateMagicLeapControllerState(state, device);
break;
case VRModuleDeviceModel.ViveFocusChirp:
UpdateViveFocusChirpControllerState(state, device);
break;
case VRModuleDeviceModel.ViveFocusFinch:
UpdateViveFocusFinchControllerState(state, device);
break;
}
}
private bool TryGetDevice(uint index, out InputDevice deviceOut)
{
deviceOut = default;
if (index < m_indexToDevices.Count)
{
deviceOut = m_indexToDevices[(int)index];
return true;
}
return false;
}
private uint GetOrCreateDeviceIndex(InputDevice device)
{
uint index = 0;
int uid = GetDeviceUID(device);
if (m_deviceUidToIndex.TryGetValue(uid, out index))
{
return index;
}
uint newIndex = (uint)m_deviceUidToIndex.Count;
m_deviceUidToIndex.Add(uid, newIndex);
m_indexToDevices.Add(device);
return newIndex;
}
private VRModuleDeviceClass GetDeviceClass(string name, InputDeviceCharacteristics characteristics)
{
bool isTracker = Regex.IsMatch(name, @"tracker", RegexOptions.IgnoreCase);
if ((characteristics & InputDeviceCharacteristics.HeadMounted) != 0)
{
return VRModuleDeviceClass.HMD;
}
if ((characteristics & InputDeviceCharacteristics.Controller) != 0 && !isTracker)
{
return VRModuleDeviceClass.Controller;
}
if ((characteristics & InputDeviceCharacteristics.TrackingReference) != 0)
{
return VRModuleDeviceClass.TrackingReference;
}
if ((characteristics & InputDeviceCharacteristics.TrackedDevice) != 0)
{
return VRModuleDeviceClass.GenericTracker;
}
return VRModuleDeviceClass.Invalid;
}
private void SetAllXRInputSubsystemTrackingOriginMode(TrackingOriginModeFlags mode)
{
List<XRInputSubsystem> systems = new List<XRInputSubsystem>();
SubsystemManager.GetInstances(systems);
foreach (XRInputSubsystem system in systems)
{
if (!system.TrySetTrackingOriginMode(mode))
{
Debug.LogWarning("Failed to set TrackingOriginModeFlags to XRInputSubsystem: " + system.SubsystemDescriptor.id);
}
}
}
private int GetDeviceUID(InputDevice device)
{
#if CSHARP_7_OR_LATER
return (device.name, device.serialNumber, device.characteristics).GetHashCode();
#else
return new { device.name, device.serialNumber, device.characteristics }.GetHashCode();
#endif
}
private XRInputSubsystemType DetectCurrentInputSubsystemType()
{
List<XRInputSubsystem> systems = new List<XRInputSubsystem>();
SubsystemManager.GetInstances(systems);
if (systems.Count == 0)
{
Debug.LogWarning("No XRInputSubsystem detected.");
return XRInputSubsystemType.Unknown;
}
string id = systems[0].SubsystemDescriptor.id;
Debug.Log("Activated XRInputSubsystem Name: " + id);
if (Regex.IsMatch(id, @"openvr", RegexOptions.IgnoreCase))
{
return XRInputSubsystemType.OpenVR;
}
else if (Regex.IsMatch(id, @"oculus", RegexOptions.IgnoreCase))
{
return XRInputSubsystemType.Oculus;
}
else if (Regex.IsMatch(id, @"windows mixed reality", RegexOptions.IgnoreCase))
{
return XRInputSubsystemType.WMR;
}
else if (Regex.IsMatch(id, @"magicleap", RegexOptions.IgnoreCase))
{
return XRInputSubsystemType.MagicLeap;
}
return XRInputSubsystemType.Unknown;
}
private void UpdateViveControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
bool menuButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.menuButton);
bool primaryAxisClick = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisClick);
bool triggerButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.triggerButton);
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch);
bool gripButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.gripButton);
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger);
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis);
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, menuButton);
state.SetButtonPress(VRModuleRawButton.Touchpad, primaryAxisClick);
state.SetButtonPress(VRModuleRawButton.Grip, gripButton);
state.SetButtonPress(VRModuleRawButton.CapSenseGrip, gripButton);
state.SetButtonPress(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonTouch(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonTouch(VRModuleRawButton.Touchpad, primary2DAxisTouch);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
state.SetAxisValue(VRModuleRawAxis.TouchpadX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.TouchpadY, primary2DAxis.y);
}
private void UpdateViveCosmosControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
bool primaryButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.primaryButton); // X/A
bool primaryTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primaryTouch); // X/A
bool secondaryButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondaryButton); // Y/B
bool secondaryTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondaryTouch); // Y/B
bool primaryAxisClick = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisClick);
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch);
bool triggerButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.triggerButton);
bool triggerTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("TriggerTouch"));
bool gripButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.gripButton);
bool bumperButton = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("BumperButton"));
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger);
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis);
state.SetButtonPress(VRModuleRawButton.A, primaryButton);
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, secondaryButton);
state.SetButtonPress(VRModuleRawButton.Touchpad, primaryAxisClick);
state.SetButtonPress(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonPress(VRModuleRawButton.Grip, gripButton);
state.SetButtonPress(VRModuleRawButton.Bumper, bumperButton);
state.SetButtonTouch(VRModuleRawButton.A, primaryTouch);
state.SetButtonTouch(VRModuleRawButton.ApplicationMenu, secondaryTouch);
state.SetButtonTouch(VRModuleRawButton.Touchpad, primary2DAxisTouch);
state.SetButtonTouch(VRModuleRawButton.Trigger, triggerTouch);
state.SetButtonTouch(VRModuleRawButton.Grip, gripButton);
state.SetButtonTouch(VRModuleRawButton.Bumper, bumperButton);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
state.SetAxisValue(VRModuleRawAxis.TouchpadX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.TouchpadY, primary2DAxis.y);
}
private void UpdateViveTrackerState(IVRModuleDeviceStateRW state, InputDevice device)
{
bool menuButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.menuButton);
bool primary2DAxisClick = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisClick);
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch);
bool gripButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.gripButton);
bool triggerButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.triggerButton);
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger);
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis);
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, menuButton);
state.SetButtonPress(VRModuleRawButton.Touchpad, primary2DAxisClick);
state.SetButtonPress(VRModuleRawButton.Grip, gripButton);
state.SetButtonPress(VRModuleRawButton.CapSenseGrip, gripButton);
state.SetButtonPress(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonTouch(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonTouch(VRModuleRawButton.Touchpad, primary2DAxisTouch);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
state.SetAxisValue(VRModuleRawAxis.TouchpadX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.TouchpadY, primary2DAxis.y);
}
private void UpdateOculusControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
bool primaryButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.primaryButton); // X/A
bool secondaryButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondaryButton); // Y/B
bool triggerButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.triggerButton);
bool gripButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.gripButton);
bool primaryTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primaryTouch); // X/A
bool secondaryTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondaryTouch); // Y/B
bool primary2DAxisClick = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisClick); // Joystick
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch); // Joystick
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger);
float grip = GetDeviceFeatureValueOrDefault(device, CommonUsages.grip);
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis); // Joystick
state.SetButtonPress(VRModuleRawButton.A, primaryButton);
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, secondaryButton);
state.SetButtonPress(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonPress(VRModuleRawButton.Grip, gripButton);
state.SetButtonPress(VRModuleRawButton.CapSenseGrip, gripButton);
state.SetButtonPress(VRModuleRawButton.Axis0, primary2DAxisClick);
state.SetButtonTouch(VRModuleRawButton.A, primaryTouch);
state.SetButtonTouch(VRModuleRawButton.ApplicationMenu, secondaryTouch);
state.SetButtonTouch(VRModuleRawButton.Grip, grip >= 0.05f);
state.SetButtonTouch(VRModuleRawButton.CapSenseGrip, grip >= 0.05f);
state.SetButtonTouch(VRModuleRawButton.Axis0, primary2DAxisTouch);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
state.SetAxisValue(VRModuleRawAxis.CapSenseGrip, grip);
state.SetAxisValue(VRModuleRawAxis.JoystickX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.JoystickY, primary2DAxis.y);
if (m_currentInputSubsystemType == XRInputSubsystemType.OpenVR)
{
bool triggerTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("TriggerTouch"));
state.SetButtonTouch(VRModuleRawButton.Trigger, triggerTouch);
}
else if (m_currentInputSubsystemType == XRInputSubsystemType.Oculus)
{
bool thumbrest = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("Thumbrest"));
float indexTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<float>("IndexTouch"));
float thumbTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<float>("ThumbTouch")); // Not in use
state.SetButtonTouch(VRModuleRawButton.Touchpad, thumbrest);
state.SetButtonTouch(VRModuleRawButton.Trigger, indexTouch >= 1.0f);
if ((device.characteristics & InputDeviceCharacteristics.Left) != 0)
{
bool menuButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.menuButton);
state.SetButtonPress(VRModuleRawButton.System, menuButton);
}
}
}
private void UpdateWMRControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
bool menuButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.menuButton);
bool triggerButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.triggerButton);
bool gripButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.gripButton);
bool primary2DAxisClick = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisClick); // Touchpad
bool secondary2DAxisClick = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("Secondary2DAxisClick"));
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch); // Touchpad
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger);
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis); // Touchpad
Vector2 secondary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondary2DAxis); // Joystick
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, menuButton);
state.SetButtonPress(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonPress(VRModuleRawButton.Grip, gripButton);
state.SetButtonPress(VRModuleRawButton.Touchpad, primary2DAxisClick);
state.SetButtonPress(VRModuleRawButton.Axis0, secondary2DAxisClick);
state.SetButtonTouch(VRModuleRawButton.Touchpad, primary2DAxisTouch);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
state.SetAxisValue(VRModuleRawAxis.TouchpadX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.TouchpadY, primary2DAxis.y);
state.SetAxisValue(VRModuleRawAxis.JoystickX, secondary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.JoystickY, secondary2DAxis.y);
if (m_currentInputSubsystemType == XRInputSubsystemType.WMR)
{
float grip = GetDeviceFeatureValueOrDefault(device, CommonUsages.grip);
float sourceLossRisk = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<float>("SourceLossRisk")); // Not in use
Vector3 pointerPosition = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<Vector3>("PointerPosition")); // Not in use
Vector3 sourceMitigationDirection = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<Vector3>("SourceMitigationDirection")); // Not in use
Quaternion pointerRotation = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<Quaternion>("PointerRotation")); // Not in use
// conflict with JoystickX
//state.SetAxisValue(VRModuleRawAxis.CapSenseGrip, grip);
}
}
private void UpdateIndexControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
// TODO: Get finger curl values once OpenVR XR Plugin supports
bool primaryButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.primaryButton);
bool secondaryButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondaryButton); // B
bool primary2DAxisClick = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisClick);
bool secondary2DAxisClick = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("Secondary2DAxisClick")); // Joystick
bool triggerButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.triggerButton); // trigger >= 0.5
bool gripButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.gripButton); // grip force >= 0.5
bool primaryTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("PrimaryTouch"));
bool secondaryTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("SecondaryTouch"));
bool triggerTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("TriggerTouch"));
bool gripTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("GripTouch"));
bool gripGrab = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("GripGrab")); // gripCapacitive >= 0.7
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch);
bool secondary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("Secondary2DAxisTouch")); // Joystick
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger);
float grip = GetDeviceFeatureValueOrDefault(device, CommonUsages.grip); // grip force
float gripCapacitive = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<float>("GripCapacitive")); // touch area on grip
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis);
Vector2 secondary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondary2DAxis);
state.SetButtonPress(VRModuleRawButton.A, primaryButton);
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, secondaryButton);
state.SetButtonPress(VRModuleRawButton.Touchpad, primary2DAxisClick);
state.SetButtonPress(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonPress(VRModuleRawButton.Grip, gripButton);
state.SetButtonPress(VRModuleRawButton.Axis0, secondary2DAxisClick);
state.SetButtonTouch(VRModuleRawButton.A, primaryTouch);
state.SetButtonTouch(VRModuleRawButton.ApplicationMenu, secondaryTouch);
state.SetButtonTouch(VRModuleRawButton.Trigger, triggerTouch);
state.SetButtonTouch(VRModuleRawButton.Grip, gripTouch);
state.SetButtonTouch(VRModuleRawButton.Touchpad, primary2DAxisTouch);
state.SetButtonTouch(VRModuleRawButton.Axis0, secondary2DAxisTouch);
state.SetAxisValue(VRModuleRawAxis.TouchpadX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.TouchpadY, primary2DAxis.y);
state.SetAxisValue(VRModuleRawAxis.JoystickX, secondary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.JoystickY, secondary2DAxis.y);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
// conflict with JoystickX
//state.SetAxisValue(VRModuleRawAxis.CapSenseGrip, grip);
}
private void UpdateMagicLeapControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
bool menuButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.menuButton);
bool secondaryButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondaryButton); // Bumper
bool triggerButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.triggerButton);
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch);
uint MLControllerType = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<uint>("MLControllerType")); // Not in use
uint MLControllerDOF = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<uint>("MLControllerDOF")); // Not in use
uint MLControllerCalibrationAccuracy = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<uint>("MLControllerCalibrationAccuracy")); // Not in use
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger);
float MLControllerTouch1Force = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<float>("MLControllerTouch1Force")); // Not in use
float MLControllerTouch2Force = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<float>("MLControllerTouch2Force")); // Not in use
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis);
Vector2 secondary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondary2DAxis); // Not in use
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, menuButton);
state.SetButtonPress(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonPress(VRModuleRawButton.Bumper, secondaryButton);
state.SetButtonTouch(VRModuleRawButton.Touchpad, primary2DAxisTouch);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
state.SetAxisValue(VRModuleRawAxis.TouchpadX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.TouchpadY, primary2DAxis.y);
}
private void UpdateViveFocusChirpControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
bool primary2DAxisClick = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisClick); // Touchpad
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch); // Touchpad
bool secondary2DAxisClick = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("Secondary2DAxisClick")); // No data
bool secondary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("Secondary2DAxisTouch")); // No data
bool gripButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.gripButton);
bool triggerButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.triggerButton);
bool menuButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.menuButton);
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger);
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis); // Touchpad
Vector2 secondary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondary2DAxis); // No data
Vector2 dPad = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<Vector2>("DPad"));
state.SetButtonPress(VRModuleRawButton.Touchpad, primary2DAxisClick);
state.SetButtonPress(VRModuleRawButton.Grip, gripButton);
state.SetButtonPress(VRModuleRawButton.Trigger, triggerButton);
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, menuButton);
state.SetButtonPress(VRModuleRawButton.DPadUp, dPad.y > 0);
state.SetButtonPress(VRModuleRawButton.DPadDown, dPad.y < 0);
state.SetButtonPress(VRModuleRawButton.DPadLeft, dPad.x < 0);
state.SetButtonPress(VRModuleRawButton.DPadRight, dPad.x > 0);
state.SetButtonTouch(VRModuleRawButton.Touchpad, primary2DAxisTouch);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
state.SetAxisValue(VRModuleRawAxis.TouchpadX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.TouchpadY, primary2DAxis.y);
}
private void UpdateViveFocusFinchControllerState(IVRModuleDeviceStateRW state, InputDevice device)
{
bool primary2DAxisClick = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisClick); // Touchpad
bool primary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxisTouch); // Touchpad
bool secondary2DAxisClick = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("Secondary2DAxisClick")); // No data
bool secondary2DAxisTouch = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<bool>("Secondary2DAxisTouch")); // No data
bool gripButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.gripButton); // Trigger
bool menuButton = GetDeviceFeatureValueOrDefault(device, CommonUsages.menuButton); // No Data
float trigger = GetDeviceFeatureValueOrDefault(device, CommonUsages.trigger); // No Data
Vector2 primary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.primary2DAxis); // Touchpad
Vector2 secondary2DAxis = GetDeviceFeatureValueOrDefault(device, CommonUsages.secondary2DAxis); // No data
Vector2 dPad = GetDeviceFeatureValueOrDefault(device, new InputFeatureUsage<Vector2>("DPad")); // No Data
state.SetButtonPress(VRModuleRawButton.Touchpad, primary2DAxisClick);
state.SetButtonPress(VRModuleRawButton.Trigger, gripButton);
state.SetButtonPress(VRModuleRawButton.ApplicationMenu, menuButton);
state.SetButtonPress(VRModuleRawButton.DPadUp, dPad.y > 0);
state.SetButtonPress(VRModuleRawButton.DPadDown, dPad.y < 0);
state.SetButtonPress(VRModuleRawButton.DPadLeft, dPad.x < 0);
state.SetButtonPress(VRModuleRawButton.DPadRight, dPad.x > 0);
state.SetButtonTouch(VRModuleRawButton.Touchpad, primary2DAxisTouch);
state.SetAxisValue(VRModuleRawAxis.Trigger, trigger);
state.SetAxisValue(VRModuleRawAxis.TouchpadX, primary2DAxis.x);
state.SetAxisValue(VRModuleRawAxis.TouchpadY, primary2DAxis.y);
}
private bool GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<bool> feature)
{
bool value = false;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have bool feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private uint GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<uint> feature)
{
uint value = 0;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have uint feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private float GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<float> feature)
{
float value = 0.0f;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have float feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private Vector2 GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<Vector2> feature)
{
Vector2 value = Vector2.zero;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have Vector2 feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private Vector3 GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<Vector3> feature)
{
Vector3 value = Vector3.zero;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have Vector3 feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private Quaternion GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<Quaternion> feature)
{
Quaternion value = Quaternion.identity;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have Quaternion feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private UnityEngine.XR.Hand GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<UnityEngine.XR.Hand> feature)
{
UnityEngine.XR.Hand value;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have Hand feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private Bone GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<Bone> feature)
{
Bone value;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have Bone feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private Eyes GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<Eyes> feature)
{
Eyes value;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have Eyes feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private InputTrackingState GetDeviceFeatureValueOrDefault(InputDevice device, InputFeatureUsage<InputTrackingState> feature)
{
InputTrackingState value;
if (device.TryGetFeatureValue(feature, out value))
{
return value;
}
#if UNITY_EDITOR
Debug.LogWarningFormat("Device {0} doesn't have InputTrackingState feature {1}. Return default value instead.", device.name, feature.name);
#endif
return default;
}
private void LogDeviceFeatureUsages(InputDevice device)
{
List<InputFeatureUsage> usages = new List<InputFeatureUsage>();
if (device.TryGetFeatureUsages(usages))
{
string strUsages = "";
foreach (var usage in usages)
{
strUsages += "[" + usage.type.Name + "] " + usage.name + "\n";
}
Debug.Log(device.name + " feature usages:\n\n" + strUsages);
}
}
private static string CharacteristicsToString(InputDeviceCharacteristics ch)
{
if (ch == 0u) { return " No Characteristic"; }
var chu = (uint)ch;
var str = string.Empty;
for (var i = 1u; chu > 0u; i <<= 1)
{
if ((chu & i) == 0u) { continue; }
str += " " + (InputDeviceCharacteristics)i;
chu &= ~i;
}
return str;
}
#endif
}
}