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.
376 lines
14 KiB
376 lines
14 KiB
3 years ago
|
//========= Copyright 2016-2018, HTC Corporation. All rights reserved. ===========
|
||
|
|
||
|
using HTC.UnityPlugin.Utility;
|
||
|
using HTC.UnityPlugin.VRModuleManagement;
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace HTC.UnityPlugin.Vive
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Defines roles for those devices that have buttons
|
||
|
/// </summary>
|
||
|
[ViveRoleEnum((int)HandRole.Invalid)]
|
||
|
public enum HandRole
|
||
|
{
|
||
|
Invalid = -1,
|
||
|
RightHand,
|
||
|
LeftHand,
|
||
|
ExternalCamera,
|
||
|
Controller3 = ExternalCamera,
|
||
|
Controller4,
|
||
|
Controller5,
|
||
|
Controller6,
|
||
|
Controller7,
|
||
|
Controller8,
|
||
|
Controller9,
|
||
|
Controller10,
|
||
|
Controller11,
|
||
|
Controller12,
|
||
|
Controller13,
|
||
|
Controller14,
|
||
|
Controller15,
|
||
|
}
|
||
|
|
||
|
public static class ConvertRoleExtension
|
||
|
{
|
||
|
[Obsolete("HandRole and DeviceRole are not related now")]
|
||
|
public static DeviceRole ToDeviceRole(this HandRole role)
|
||
|
{
|
||
|
switch (role)
|
||
|
{
|
||
|
case HandRole.RightHand: return DeviceRole.RightHand;
|
||
|
case HandRole.LeftHand: return DeviceRole.LeftHand;
|
||
|
case HandRole.Controller3: return DeviceRole.Controller3;
|
||
|
case HandRole.Controller4: return DeviceRole.Controller4;
|
||
|
case HandRole.Controller5: return DeviceRole.Controller5;
|
||
|
case HandRole.Controller6: return DeviceRole.Controller6;
|
||
|
case HandRole.Controller7: return DeviceRole.Controller7;
|
||
|
case HandRole.Controller8: return DeviceRole.Controller8;
|
||
|
case HandRole.Controller9: return DeviceRole.Controller9;
|
||
|
case HandRole.Controller10: return DeviceRole.Controller10;
|
||
|
case HandRole.Controller11: return DeviceRole.Controller11;
|
||
|
case HandRole.Controller12: return DeviceRole.Controller12;
|
||
|
case HandRole.Controller13: return DeviceRole.Controller13;
|
||
|
case HandRole.Controller14: return DeviceRole.Controller14;
|
||
|
case HandRole.Controller15: return DeviceRole.Controller15;
|
||
|
default: return (DeviceRole)((int)DeviceRole.Hmd - 1); // returns invalid value
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class HandRoleHandler : ViveRole.MapHandler<HandRole>
|
||
|
{
|
||
|
#if __VIU_STEAMVR
|
||
|
private uint[] m_sortedDevices = new uint[VRModule.MAX_DEVICE_COUNT];
|
||
|
#endif
|
||
|
private List<uint> m_sortedDeviceList = new List<uint>();
|
||
|
|
||
|
// HandRole only tracks controllers
|
||
|
private bool IsController(uint deviceIndex)
|
||
|
{
|
||
|
return IsController(VRModule.GetCurrentDeviceState(deviceIndex).deviceClass);
|
||
|
}
|
||
|
|
||
|
private bool IsController(VRModuleDeviceClass deviceClass)
|
||
|
{
|
||
|
return deviceClass == VRModuleDeviceClass.Controller;
|
||
|
}
|
||
|
|
||
|
private bool IsTracker(uint deviceIndex)
|
||
|
{
|
||
|
return IsTracker(VRModule.GetCurrentDeviceState(deviceIndex).deviceClass);
|
||
|
}
|
||
|
|
||
|
private bool IsTracker(VRModuleDeviceClass deviceClass)
|
||
|
{
|
||
|
return deviceClass == VRModuleDeviceClass.GenericTracker;
|
||
|
}
|
||
|
|
||
|
public override void OnAssignedAsCurrentMapHandler() { Refresh(); }
|
||
|
|
||
|
public override void OnTrackedDeviceRoleChanged() { Refresh(); }
|
||
|
|
||
|
public override void OnConnectedDeviceChanged(uint deviceIndex, VRModuleDeviceClass deviceClass, string deviceSN, bool connected)
|
||
|
{
|
||
|
if (!RoleMap.IsDeviceBound(deviceSN) && !IsController(deviceClass) && !IsTracker(deviceClass)) { return; }
|
||
|
|
||
|
Refresh();
|
||
|
}
|
||
|
|
||
|
public override void OnBindingChanged(string deviceSN, bool previousIsBound, HandRole previousRole, bool currentIsBound, HandRole currentRole)
|
||
|
{
|
||
|
uint deviceIndex;
|
||
|
if (!VRModule.TryGetConnectedDeviceIndex(deviceSN, out deviceIndex)) { return; }
|
||
|
|
||
|
Refresh();
|
||
|
}
|
||
|
|
||
|
public void Refresh()
|
||
|
{
|
||
|
MappingLeftRightHands();
|
||
|
MappingOtherControllers();
|
||
|
}
|
||
|
|
||
|
private void MappingLeftRightHands()
|
||
|
{
|
||
|
// assign left/right controllers according to the hint
|
||
|
var rightIndex = VRModule.GetRightControllerDeviceIndex();
|
||
|
var leftIndex = VRModule.GetLeftControllerDeviceIndex();
|
||
|
|
||
|
if (VRModule.GetCurrentDeviceState(rightIndex).isConnected)
|
||
|
{
|
||
|
MappingRoleIfUnbound(HandRole.RightHand, rightIndex);
|
||
|
rightIndex = RoleMap.GetMappedDeviceByRole(HandRole.RightHand);
|
||
|
}
|
||
|
else if (RoleMap.IsRoleBound(HandRole.RightHand))
|
||
|
{
|
||
|
rightIndex = RoleMap.GetMappedDeviceByRole(HandRole.RightHand);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rightIndex = VRModule.INVALID_DEVICE_INDEX;
|
||
|
}
|
||
|
|
||
|
if (VRModule.GetCurrentDeviceState(leftIndex).isConnected && leftIndex != rightIndex)
|
||
|
{
|
||
|
MappingRoleIfUnbound(HandRole.LeftHand, leftIndex);
|
||
|
leftIndex = RoleMap.GetMappedDeviceByRole(HandRole.LeftHand);
|
||
|
}
|
||
|
else if (RoleMap.IsRoleBound(HandRole.LeftHand))
|
||
|
{
|
||
|
leftIndex = RoleMap.GetMappedDeviceByRole(HandRole.LeftHand);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
leftIndex = VRModule.INVALID_DEVICE_INDEX;
|
||
|
}
|
||
|
|
||
|
// if not both left/right controllers are assigned, find and assign them with left/right most controller
|
||
|
if (!VRModule.IsValidDeviceIndex(rightIndex) || !VRModule.IsValidDeviceIndex(leftIndex))
|
||
|
{
|
||
|
// find right to left sorted controllers
|
||
|
// FIXME: GetSortedTrackedDeviceIndicesOfClass doesn't return correct devices count right after device connected
|
||
|
#if __VIU_STEAMVR
|
||
|
if (VRModule.activeModule == SupportedVRModule.SteamVR)
|
||
|
{
|
||
|
var count = 0;
|
||
|
var system = Valve.VR.OpenVR.System;
|
||
|
if (system != null)
|
||
|
{
|
||
|
count = (int)system.GetSortedTrackedDeviceIndicesOfClass(Valve.VR.ETrackedDeviceClass.Controller, m_sortedDevices, Valve.VR.OpenVR.k_unTrackedDeviceIndex_Hmd);
|
||
|
}
|
||
|
|
||
|
foreach (var deviceIndex in m_sortedDevices)
|
||
|
{
|
||
|
if (m_sortedDeviceList.Count >= count) { break; }
|
||
|
if (IsController(deviceIndex) && deviceIndex != rightIndex && deviceIndex != leftIndex && !RoleMap.IsDeviceConnectedAndBound(deviceIndex))
|
||
|
{
|
||
|
m_sortedDeviceList.Add(deviceIndex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
for (uint deviceIndex = 1u; deviceIndex < VRModule.MAX_DEVICE_COUNT; ++deviceIndex)
|
||
|
{
|
||
|
if (IsController(deviceIndex) && deviceIndex != rightIndex && deviceIndex != leftIndex && !RoleMap.IsDeviceConnectedAndBound(deviceIndex))
|
||
|
{
|
||
|
m_sortedDeviceList.Add(deviceIndex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_sortedDeviceList.Count > 1)
|
||
|
{
|
||
|
SortDeviceIndicesByDirection(m_sortedDeviceList, VRModule.GetCurrentDeviceState(VRModule.HMD_DEVICE_INDEX).pose);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_sortedDeviceList.Count > 0 && !VRModule.IsValidDeviceIndex(rightIndex))
|
||
|
{
|
||
|
rightIndex = m_sortedDeviceList[0];
|
||
|
m_sortedDeviceList.RemoveAt(0);
|
||
|
// mapping right most controller
|
||
|
MappingRole(HandRole.RightHand, rightIndex);
|
||
|
}
|
||
|
|
||
|
if (m_sortedDeviceList.Count > 0 && !VRModule.IsValidDeviceIndex(leftIndex))
|
||
|
{
|
||
|
leftIndex = m_sortedDeviceList[m_sortedDeviceList.Count - 1];
|
||
|
// mapping left most controller
|
||
|
MappingRole(HandRole.LeftHand, leftIndex);
|
||
|
}
|
||
|
|
||
|
m_sortedDeviceList.Clear();
|
||
|
}
|
||
|
|
||
|
if (!VRModule.IsValidDeviceIndex(rightIndex)) { UnmappingRole(HandRole.RightHand); }
|
||
|
if (!VRModule.IsValidDeviceIndex(leftIndex)) { UnmappingRole(HandRole.LeftHand); }
|
||
|
}
|
||
|
|
||
|
private void MappingOtherControllers()
|
||
|
{
|
||
|
// mapping other controllers in order of device index
|
||
|
var deviceIndex = 0u;
|
||
|
var firstFoundTracker = VRModule.INVALID_DEVICE_INDEX;
|
||
|
var rightIndex = RoleMap.GetMappedDeviceByRole(HandRole.RightHand);
|
||
|
var leftIndex = RoleMap.GetMappedDeviceByRole(HandRole.LeftHand);
|
||
|
|
||
|
for (var role = RoleInfo.MinValidRole; role <= RoleInfo.MaxValidRole; ++role)
|
||
|
{
|
||
|
if (!RoleInfo.IsValidRole(role)) { continue; }
|
||
|
if (role == HandRole.RightHand || role == HandRole.LeftHand) { continue; }
|
||
|
if (RoleMap.IsRoleBound(role)) { continue; }
|
||
|
|
||
|
// find next valid device
|
||
|
if (VRModule.IsValidDeviceIndex(deviceIndex))
|
||
|
{
|
||
|
while (!IsController(deviceIndex) || RoleMap.IsDeviceConnectedAndBound(deviceIndex) || deviceIndex == rightIndex || deviceIndex == leftIndex)
|
||
|
{
|
||
|
if (!VRModule.IsValidDeviceIndex(firstFoundTracker) && IsTracker(deviceIndex)) { firstFoundTracker = deviceIndex; }
|
||
|
if (!VRModule.IsValidDeviceIndex(++deviceIndex)) { break; }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (VRModule.IsValidDeviceIndex(deviceIndex))
|
||
|
{
|
||
|
MappingRole(role, deviceIndex++);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UnmappingRole(role);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if external camera is not mapped, try mapping first found tracker
|
||
|
if (!RoleMap.IsRoleMapped(HandRole.ExternalCamera) && VRModule.IsValidDeviceIndex(firstFoundTracker) && !RoleMap.IsDeviceConnectedAndBound(firstFoundTracker))
|
||
|
{
|
||
|
MappingRole(HandRole.ExternalCamera, firstFoundTracker);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static readonly float[] s_deviceDirPoint = new float[VRModule.MAX_DEVICE_COUNT];
|
||
|
public static void SortDeviceIndicesByDirection(List<uint> deviceList, RigidPose sortingReference)
|
||
|
{
|
||
|
if (deviceList == null || deviceList.Count == 0) { return; }
|
||
|
|
||
|
for (int i = 0, imax = deviceList.Count; i < imax; ++i)
|
||
|
{
|
||
|
var deviceIndex = deviceList[i];
|
||
|
if (!VRModule.IsValidDeviceIndex(deviceIndex)) { continue; }
|
||
|
|
||
|
var deviceState = VRModule.GetCurrentDeviceState(deviceIndex);
|
||
|
if (deviceState.isConnected)
|
||
|
{
|
||
|
var localPos = sortingReference.InverseTransformPoint(deviceState.pose.pos);
|
||
|
s_deviceDirPoint[deviceIndex] = GetDirectionPoint(new Vector2(localPos.x, localPos.z));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s_deviceDirPoint[deviceIndex] = -1f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
deviceList.Sort(CompareDirection);
|
||
|
}
|
||
|
|
||
|
[Obsolete]
|
||
|
public static void SortDeviceIndicesByDirection(List<uint> deviceList, PoseTracker.Pose sortingReference)
|
||
|
{
|
||
|
SortDeviceIndicesByDirection(deviceList, sortingReference);
|
||
|
}
|
||
|
|
||
|
private static int CompareDirection(uint d1, uint d2)
|
||
|
{
|
||
|
var d1Point = s_deviceDirPoint[d1];
|
||
|
var d2Point = s_deviceDirPoint[d2];
|
||
|
var d1Valid = VRModule.IsValidDeviceIndex(d1) && d1Point >= 0f;
|
||
|
var d2Valid = VRModule.IsValidDeviceIndex(d2) && d2Point >= 0f;
|
||
|
|
||
|
if (!d1Valid || !d2Valid)
|
||
|
{
|
||
|
if (d1Valid) { return -1; }
|
||
|
if (d2Valid) { return 1; }
|
||
|
|
||
|
if (d1 < d2) { return -1; }
|
||
|
if (d1 > d2) { return 1; }
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (d1Point < d2Point) { return -1; }
|
||
|
if (d1Point > d2Point) { return 1; }
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Y+
|
||
|
// ||
|
||
|
// \\ 4 || 3 //
|
||
|
// \\ || //
|
||
|
// 5 \\ ^^ // 2
|
||
|
// =========[]========= X+
|
||
|
// 6 // || \\ 1
|
||
|
// // || \\
|
||
|
// // 7 || 0 \\
|
||
|
// ||
|
||
|
// less point => right side
|
||
|
public static float GetDirectionPoint(Vector2 pos)
|
||
|
{
|
||
|
var ax = Mathf.Abs(pos.x);
|
||
|
var ay = Mathf.Abs(pos.y);
|
||
|
if (pos.x > 0f)
|
||
|
{
|
||
|
if (pos.y < 0f)
|
||
|
{
|
||
|
if (ax < ay)
|
||
|
{
|
||
|
return 0f + (ax / ay);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 1f + (1f - ay / ax);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ax > ay)
|
||
|
{
|
||
|
return 2f + (ay / ax);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 3f + (1f - ax / ay);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pos.y > 0f)
|
||
|
{
|
||
|
if (ax < ay)
|
||
|
{
|
||
|
return 4f + (ax / ay);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 5f + (1f - ay / ax);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ax > ay)
|
||
|
{
|
||
|
return 6f + (ay / ax);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 7f + (1 - ax / ay);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|