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.

168 lines
6.1 KiB

5 years ago
  1. //========= Copyright 2016-2020, HTC Corporation. All rights reserved. ===========
  2. using HTC.UnityPlugin.VRModuleManagement;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace HTC.UnityPlugin.Vive
  6. {
  7. [ViveRoleEnum((int)TrackerRole.Invalid)]
  8. public enum BodyRole
  9. {
  10. Invalid,
  11. Head,
  12. RightHand,
  13. LeftHand,
  14. RightFoot,
  15. LeftFoot,
  16. Hip,
  17. }
  18. public class BodyRoleHandler : ViveRole.MapHandler<BodyRole>
  19. {
  20. private float[] m_directionPoint = new float[VRModule.MAX_DEVICE_COUNT];
  21. private float[] m_distanceSqr = new float[VRModule.MAX_DEVICE_COUNT];
  22. private List<uint> m_sortedDevices = new List<uint>();
  23. private bool IsTrackingDevice(uint deviceIndex)
  24. {
  25. return IsTrackingDevice(VRModule.GetCurrentDeviceState(deviceIndex).deviceClass);
  26. }
  27. private bool IsTrackingDevice(VRModuleDeviceClass deviceClass)
  28. {
  29. return deviceClass == VRModuleDeviceClass.HMD || deviceClass == VRModuleDeviceClass.Controller || deviceClass == VRModuleDeviceClass.GenericTracker;
  30. }
  31. public override void OnAssignedAsCurrentMapHandler() { Refresh(); }
  32. public override void OnConnectedDeviceChanged(uint deviceIndex, VRModuleDeviceClass deviceClass, string deviceSN, bool connected)
  33. {
  34. if (!RoleMap.IsDeviceBound(deviceSN) && !IsTrackingDevice(deviceClass)) { return; }
  35. Refresh();
  36. }
  37. public override void OnBindingChanged(string deviceSN, bool previousIsBound, BodyRole previousRole, bool currentIsBound, BodyRole currentRole)
  38. {
  39. uint deviceIndex;
  40. if (!VRModule.TryGetConnectedDeviceIndex(deviceSN, out deviceIndex)) { return; }
  41. Refresh();
  42. }
  43. public void Refresh()
  44. {
  45. m_sortedDevices.Clear();
  46. UnmappingAll();
  47. if (!VRModule.IsValidDeviceIndex(VRModule.HMD_DEVICE_INDEX)) { return; }
  48. MappingRoleIfUnbound(BodyRole.Head, VRModule.HMD_DEVICE_INDEX);
  49. // get related poses and record controller/tracker devices
  50. var hmdPose = VivePose.GetPose(0u);
  51. // preserve only y-axis rotation
  52. hmdPose.rot = Quaternion.Euler(0f, hmdPose.rot.eulerAngles.y, 0f);
  53. // move center to half height
  54. hmdPose.pos = Vector3.Scale(hmdPose.pos, new Vector3(1f, 0.5f, 1f));
  55. var halfHeight = hmdPose.pos.y;
  56. var centerPoseInverse = hmdPose.GetInverse();
  57. for (uint i = 1, imax = VRModule.GetDeviceStateCount(); i < imax; ++i)
  58. {
  59. if (!IsTrackingDevice(i)) { continue; }
  60. var relatedCenterPos = centerPoseInverse.TransformPoint(VRModule.GetCurrentDeviceState(i).pose.pos);
  61. m_directionPoint[i] = HandRoleHandler.GetDirectionPoint(new Vector2(relatedCenterPos.x, -relatedCenterPos.y));
  62. m_distanceSqr[i] = relatedCenterPos.sqrMagnitude / (halfHeight * halfHeight);
  63. m_sortedDevices.Add(i);
  64. }
  65. if (m_sortedDevices.Count == 0)
  66. {
  67. return;
  68. }
  69. var index = m_sortedDevices.Count - 1; // pointing last index
  70. // find 2 feet, should be most farest 2 devices
  71. m_sortedDevices.Sort(CompareDistance);
  72. if (IsFoot(m_sortedDevices[index]))
  73. {
  74. if (m_sortedDevices.Count <= 1)
  75. {
  76. MappingRoleIfUnbound(BodyRole.RightFoot, m_sortedDevices[index]);
  77. return;
  78. }
  79. if (!IsFoot(m_sortedDevices[index - 1]))
  80. {
  81. // only 1 foot found
  82. MappingRoleIfUnbound(BodyRole.RightFoot, m_sortedDevices[index]);
  83. m_sortedDevices.RemoveAt(index--);
  84. if (index < 0) { return; }
  85. }
  86. else
  87. {
  88. // 2 feet found, determine lef/right foot
  89. if (m_directionPoint[m_sortedDevices[index]] < m_directionPoint[m_sortedDevices[index - 1]])
  90. {
  91. MappingRoleIfUnbound(BodyRole.RightFoot, m_sortedDevices[index]);
  92. MappingRoleIfUnbound(BodyRole.LeftFoot, m_sortedDevices[index - 1]);
  93. }
  94. else
  95. {
  96. MappingRoleIfUnbound(BodyRole.RightFoot, m_sortedDevices[index - 1]);
  97. MappingRoleIfUnbound(BodyRole.LeftFoot, m_sortedDevices[index]);
  98. }
  99. m_sortedDevices.RemoveAt(index--);
  100. m_sortedDevices.RemoveAt(index--);
  101. if (index < 0) { return; }
  102. }
  103. }
  104. // find 2 hands, should be most left and most right device
  105. m_sortedDevices.Sort(CompareDirection);
  106. // right most device as right hand
  107. MappingRoleIfUnbound(BodyRole.RightHand, m_sortedDevices[0]);
  108. if (m_sortedDevices.Count == 1) { return; }
  109. // left most device as left hand
  110. MappingRoleIfUnbound(BodyRole.LeftHand, m_sortedDevices[index]);
  111. if (m_sortedDevices.Count == 2) { return; }
  112. // middle one as hip
  113. MappingRoleIfUnbound(BodyRole.Hip, m_sortedDevices[index / 2]);
  114. }
  115. private bool IsFoot(uint di)
  116. {
  117. var dist = m_distanceSqr[di];
  118. var dir = m_directionPoint[di];
  119. return dist > (0.25f * 0.25f) && dir > 3.5f && dir < 4.5f;
  120. }
  121. private int CompareDistance(uint d1, uint d2)
  122. {
  123. var dd1 = m_distanceSqr[d1];
  124. var dd2 = m_distanceSqr[d2];
  125. if (dd1 == dd2) { return 0; }
  126. if (dd1 < dd2) { return -1; }
  127. return 1;
  128. }
  129. private int CompareDirection(uint d1, uint d2)
  130. {
  131. var sd1 = m_directionPoint[d1];
  132. var sd2 = m_directionPoint[d2];
  133. if (sd1 == sd2) { return 0; }
  134. if (sd1 < sd2) { return -1; }
  135. return 1;
  136. }
  137. }
  138. }