123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- namespace NRKernal.NRExamples
- {
- using System.Collections.Generic;
- using UnityEngine;
- public class NRHandMeshVisual : MonoBehaviour
- {
- [SerializeField]
- private NRHandMeshJointConfig m_HandPrefab;
- private NRHandMeshJointConfig m_HandMeshJoint;
- [SerializeField]
- private bool m_UpdateHandScale;
- // Use distance between these joints to calculate the length of hand
- private readonly List<HandJointID> m_HandLengthJoints = new List<HandJointID>() {
- HandJointID.MiddleTip, HandJointID.MiddleDistal, HandJointID.MiddleMiddle, HandJointID.MiddleProximal, HandJointID.Wrist
- };
- private float m_HandLength;
- private void Start()
- {
- CreateMeshVisuals();
- }
- private void CreateMeshVisuals()
- {
- if (m_HandPrefab != null)
- {
- m_HandMeshJoint = Instantiate(m_HandPrefab, transform);
- InitHandLength();
- }
- }
- private void InitHandLength()
- {
- m_HandLength = 0;
- for (int i = 0; i < m_HandLengthJoints.Count - 1; i++)
- {
- m_HandLength += Vector3.Distance(m_HandMeshJoint.HandJoint[(int)m_HandLengthJoints[i]].position,
- m_HandMeshJoint.HandJoint[(int)m_HandLengthJoints[i + 1]].position);
- }
- }
- private void OnEnable()
- {
- NRInput.Hands.OnHandStatesUpdated += OnHandTracking;
- NRInput.Hands.OnHandTrackingStopped += OnHandTrackingStopped;
- }
- private void OnDisable()
- {
- NRInput.Hands.OnHandStatesUpdated -= OnHandTracking;
- NRInput.Hands.OnHandTrackingStopped -= OnHandTrackingStopped;
- }
- private void OnHandTracking()
- {
- if (m_HandMeshJoint != null)
- {
- var handState = NRInput.Hands.GetHandState(m_HandMeshJoint.HandEnum);
- m_HandMeshJoint.gameObject.SetActive(handState.isTracked);
- if (handState.isTracked)
- {
- if (m_UpdateHandScale)
- UpdateHandScale(handState);
- UpdateWristByMiddle(handState);
- UpdateFingerJoint(handState);
- }
- }
- }
- private void UpdateHandScale(HandState handState)
- {
- // if the angle between knuckles is less than this value, the finger consider to be straight
- const float fingerStraightAngle = 15f;
- Vector3 handVec = handState.GetJointPose(m_HandLengthJoints[0]).position
- - handState.GetJointPose(m_HandLengthJoints[m_HandLengthJoints.Count - 1]).position;
- float length = 0;
- for (int i = 0; i < m_HandLengthJoints.Count - 1; i++)
- {
- Vector3 knuckleVec = handState.GetJointPose(m_HandLengthJoints[i]).position
- - handState.GetJointPose(m_HandLengthJoints[i + 1]).position;
- if (Vector3.Angle(handVec, knuckleVec) > fingerStraightAngle)
- {
- return;
- }
- length += knuckleVec.magnitude;
- }
- float totalScale = length / m_HandLength;
- float angle = Vector3.Angle(NRInput.CameraCenter.forward, handVec);
- if (Mathf.Abs(angle - 90) > fingerStraightAngle)
- return;
- var wristTransform = m_HandMeshJoint.HandJoint[0];
- totalScale = Mathf.Clamp(totalScale, 0.7f, 1.3f) * 1.1f;
- totalScale = Mathf.MoveTowards(wristTransform.localScale.x, totalScale, 0.01f);
- wristTransform.localScale = Vector3.one * totalScale;
- }
- private void UpdateWristByMiddle(HandState handState)
- {
- Transform wristTransform = m_HandMeshJoint.HandJoint[(int)HandJointID.Wrist];
- var wristPose = handState.GetJointPose(HandJointID.Wrist);
- wristPose.rotation *= Quaternion.Euler(m_HandMeshJoint.RotationOffset);
- wristTransform.rotation = wristPose.rotation;
- var middlePose = handState.GetJointPose(HandJointID.MiddleProximal);
- Transform middleTransform = m_HandMeshJoint.HandJoint[(int)HandJointID.MiddleProximal];
- Vector4 middleLocalPos = middleTransform.localPosition;
- middleLocalPos.w = 1;
- Vector3 tmp = Matrix4x4.Rotate(wristTransform.rotation) * Matrix4x4.Scale(wristTransform.localScale) * middleLocalPos;
- wristTransform.position = middlePose.position - tmp;
- }
- private void UpdateFingerJoint(HandState handState)
- {
- for (int i = (int)HandJointID.ThumbMetacarpal; i <= (int)HandJointID.PinkyTip; i++)
- {
- var t = m_HandMeshJoint.HandJoint[i];
- if (t != null)
- {
- var pose = handState.GetJointPose((HandJointID)i);
- t.rotation = pose.rotation * Quaternion.Euler(m_HandMeshJoint.RotationOffset);
- }
- }
- }
- private void OnHandTrackingStopped()
- {
- if (m_HandMeshJoint != null)
- {
- m_HandMeshJoint.gameObject.SetActive(false);
- }
- }
- }
- }
|