NRHandMeshVisual.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. namespace NRKernal.NRExamples
  2. {
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. public class NRHandMeshVisual : MonoBehaviour
  6. {
  7. [SerializeField]
  8. private NRHandMeshJointConfig m_HandPrefab;
  9. private NRHandMeshJointConfig m_HandMeshJoint;
  10. [SerializeField]
  11. private bool m_UpdateHandScale;
  12. // Use distance between these joints to calculate the length of hand
  13. private readonly List<HandJointID> m_HandLengthJoints = new List<HandJointID>() {
  14. HandJointID.MiddleTip, HandJointID.MiddleDistal, HandJointID.MiddleMiddle, HandJointID.MiddleProximal, HandJointID.Wrist
  15. };
  16. private float m_HandLength;
  17. private void Start()
  18. {
  19. CreateMeshVisuals();
  20. }
  21. private void CreateMeshVisuals()
  22. {
  23. if (m_HandPrefab != null)
  24. {
  25. m_HandMeshJoint = Instantiate(m_HandPrefab, transform);
  26. InitHandLength();
  27. }
  28. }
  29. private void InitHandLength()
  30. {
  31. m_HandLength = 0;
  32. for (int i = 0; i < m_HandLengthJoints.Count - 1; i++)
  33. {
  34. m_HandLength += Vector3.Distance(m_HandMeshJoint.HandJoint[(int)m_HandLengthJoints[i]].position,
  35. m_HandMeshJoint.HandJoint[(int)m_HandLengthJoints[i + 1]].position);
  36. }
  37. }
  38. private void OnEnable()
  39. {
  40. NRInput.Hands.OnHandStatesUpdated += OnHandTracking;
  41. NRInput.Hands.OnHandTrackingStopped += OnHandTrackingStopped;
  42. }
  43. private void OnDisable()
  44. {
  45. NRInput.Hands.OnHandStatesUpdated -= OnHandTracking;
  46. NRInput.Hands.OnHandTrackingStopped -= OnHandTrackingStopped;
  47. }
  48. private void OnHandTracking()
  49. {
  50. if (m_HandMeshJoint != null)
  51. {
  52. var handState = NRInput.Hands.GetHandState(m_HandMeshJoint.HandEnum);
  53. m_HandMeshJoint.gameObject.SetActive(handState.isTracked);
  54. if (handState.isTracked)
  55. {
  56. if (m_UpdateHandScale)
  57. UpdateHandScale(handState);
  58. UpdateWristByMiddle(handState);
  59. UpdateFingerJoint(handState);
  60. }
  61. }
  62. }
  63. private void UpdateHandScale(HandState handState)
  64. {
  65. // if the angle between knuckles is less than this value, the finger consider to be straight
  66. const float fingerStraightAngle = 15f;
  67. Vector3 handVec = handState.GetJointPose(m_HandLengthJoints[0]).position
  68. - handState.GetJointPose(m_HandLengthJoints[m_HandLengthJoints.Count - 1]).position;
  69. float length = 0;
  70. for (int i = 0; i < m_HandLengthJoints.Count - 1; i++)
  71. {
  72. Vector3 knuckleVec = handState.GetJointPose(m_HandLengthJoints[i]).position
  73. - handState.GetJointPose(m_HandLengthJoints[i + 1]).position;
  74. if (Vector3.Angle(handVec, knuckleVec) > fingerStraightAngle)
  75. {
  76. return;
  77. }
  78. length += knuckleVec.magnitude;
  79. }
  80. float totalScale = length / m_HandLength;
  81. float angle = Vector3.Angle(NRInput.CameraCenter.forward, handVec);
  82. if (Mathf.Abs(angle - 90) > fingerStraightAngle)
  83. return;
  84. var wristTransform = m_HandMeshJoint.HandJoint[0];
  85. totalScale = Mathf.Clamp(totalScale, 0.7f, 1.3f) * 1.1f;
  86. totalScale = Mathf.MoveTowards(wristTransform.localScale.x, totalScale, 0.01f);
  87. wristTransform.localScale = Vector3.one * totalScale;
  88. }
  89. private void UpdateWristByMiddle(HandState handState)
  90. {
  91. Transform wristTransform = m_HandMeshJoint.HandJoint[(int)HandJointID.Wrist];
  92. var wristPose = handState.GetJointPose(HandJointID.Wrist);
  93. wristPose.rotation *= Quaternion.Euler(m_HandMeshJoint.RotationOffset);
  94. wristTransform.rotation = wristPose.rotation;
  95. var middlePose = handState.GetJointPose(HandJointID.MiddleProximal);
  96. Transform middleTransform = m_HandMeshJoint.HandJoint[(int)HandJointID.MiddleProximal];
  97. Vector4 middleLocalPos = middleTransform.localPosition;
  98. middleLocalPos.w = 1;
  99. Vector3 tmp = Matrix4x4.Rotate(wristTransform.rotation) * Matrix4x4.Scale(wristTransform.localScale) * middleLocalPos;
  100. wristTransform.position = middlePose.position - tmp;
  101. }
  102. private void UpdateFingerJoint(HandState handState)
  103. {
  104. for (int i = (int)HandJointID.ThumbMetacarpal; i <= (int)HandJointID.PinkyTip; i++)
  105. {
  106. var t = m_HandMeshJoint.HandJoint[i];
  107. if (t != null)
  108. {
  109. var pose = handState.GetJointPose((HandJointID)i);
  110. t.rotation = pose.rotation * Quaternion.Euler(m_HandMeshJoint.RotationOffset);
  111. }
  112. }
  113. }
  114. private void OnHandTrackingStopped()
  115. {
  116. if (m_HandMeshJoint != null)
  117. {
  118. m_HandMeshJoint.gameObject.SetActive(false);
  119. }
  120. }
  121. }
  122. }