NRHandMeshVisual.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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 = m_HandPrefab;// Instantiate(m_HandPrefab, transform);
  26. InitHandLength();
  27. }
  28. }
  29. private void Update()
  30. {
  31. // sz1.transform.position =
  32. }
  33. private void InitHandLength()
  34. {
  35. m_HandLength = 0;
  36. for (int i = 0; i < m_HandLengthJoints.Count - 1; i++)
  37. {
  38. m_HandLength += Vector3.Distance(m_HandMeshJoint.HandJoint[(int)m_HandLengthJoints[i]].position,
  39. m_HandMeshJoint.HandJoint[(int)m_HandLengthJoints[i + 1]].position);
  40. }
  41. }
  42. private void OnEnable()
  43. {
  44. NRInput.Hands.OnHandStatesUpdated += OnHandTracking;
  45. NRInput.Hands.OnHandTrackingStopped += OnHandTrackingStopped;
  46. }
  47. private void OnDisable()
  48. {
  49. NRInput.Hands.OnHandStatesUpdated -= OnHandTracking;
  50. NRInput.Hands.OnHandTrackingStopped -= OnHandTrackingStopped;
  51. }
  52. private void OnHandTracking()
  53. {
  54. if (m_HandMeshJoint != null)
  55. {
  56. var handState = NRInput.Hands.GetHandState(m_HandMeshJoint.HandEnum);
  57. m_HandMeshJoint.gameObject.SetActive(true);
  58. if (handState.isTracked)
  59. {
  60. if (m_UpdateHandScale)
  61. UpdateHandScale(handState);
  62. UpdateWristByMiddle(handState);
  63. UpdateFingerJoint(handState);
  64. }
  65. }
  66. }
  67. private void UpdateHandScale(HandState handState)
  68. {
  69. // if the angle between knuckles is less than this value, the finger consider to be straight
  70. const float fingerStraightAngle = 15f;
  71. Vector3 handVec = handState.GetJointPose(m_HandLengthJoints[0]).position
  72. - handState.GetJointPose(m_HandLengthJoints[m_HandLengthJoints.Count - 1]).position;
  73. float length = 0;
  74. for (int i = 0; i < m_HandLengthJoints.Count - 1; i++)
  75. {
  76. Vector3 knuckleVec = handState.GetJointPose(m_HandLengthJoints[i]).position
  77. - handState.GetJointPose(m_HandLengthJoints[i + 1]).position;
  78. if (Vector3.Angle(handVec, knuckleVec) > fingerStraightAngle)
  79. {
  80. return;
  81. }
  82. length += knuckleVec.magnitude;
  83. }
  84. float totalScale = length / m_HandLength;
  85. float angle = Vector3.Angle(NRInput.CameraCenter.forward, handVec);
  86. if (Mathf.Abs(angle - 90) > fingerStraightAngle)
  87. return;
  88. var wristTransform = m_HandMeshJoint.HandJoint[0];
  89. totalScale = Mathf.Clamp(totalScale, 0.7f, 1.3f) * 1.1f;
  90. totalScale = Mathf.MoveTowards(wristTransform.localScale.x, totalScale, 0.01f);
  91. wristTransform.localScale = Vector3.one * totalScale;
  92. }
  93. private void UpdateWristByMiddle(HandState handState)
  94. {
  95. Transform wristTransform = m_HandMeshJoint.HandJoint[(int)HandJointID.Wrist];
  96. var wristPose = handState.GetJointPose(HandJointID.Wrist);
  97. wristPose.rotation *= Quaternion.Euler(m_HandMeshJoint.RotationOffset);
  98. wristTransform.rotation = wristPose.rotation;
  99. var middlePose = handState.GetJointPose(HandJointID.MiddleProximal);
  100. Transform middleTransform = m_HandMeshJoint.HandJoint[(int)HandJointID.MiddleProximal];
  101. Vector4 middleLocalPos = middleTransform.localPosition;
  102. middleLocalPos.w = 1;
  103. Vector3 tmp = Matrix4x4.Rotate(wristTransform.rotation) * Matrix4x4.Scale(wristTransform.localScale) * middleLocalPos;
  104. wristTransform.position = middlePose.position - tmp;
  105. }
  106. private void UpdateFingerJoint(HandState handState)
  107. {
  108. for (int i = (int)HandJointID.ThumbMetacarpal; i <= (int)HandJointID.PinkyTip; i++)
  109. {
  110. var t = m_HandMeshJoint.HandJoint[i];
  111. if (t != null)
  112. {
  113. var pose = handState.GetJointPose((HandJointID)i);
  114. t.rotation = pose.rotation * Quaternion.Euler(m_HandMeshJoint.RotationOffset);
  115. }
  116. }
  117. }
  118. private void OnHandTrackingStopped()
  119. {
  120. if (m_HandMeshJoint != null)
  121. {
  122. m_HandMeshJoint.gameObject.SetActive(false);
  123. }
  124. }
  125. }
  126. }