HandPhysics.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: handles the physics of hands colliding with the world
  4. //
  5. //=============================================================================
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using UnityEngine;
  9. namespace Valve.VR.InteractionSystem
  10. {
  11. public class HandPhysics : MonoBehaviour
  12. {
  13. [Tooltip("Hand collider prefab to instantiate")]
  14. public HandCollider handColliderPrefab;
  15. [HideInInspector]
  16. public HandCollider handCollider;
  17. [Tooltip("Layers to consider when checking if an area is clear")]
  18. public LayerMask clearanceCheckMask;
  19. [HideInInspector]
  20. public Hand hand;
  21. // distance at which hand will teleport back to controller
  22. const float handResetDistance = 0.6f;
  23. const float collisionReenableClearanceRadius = 0.1f;
  24. private bool initialized = false;
  25. private bool collisionsEnabled = true;
  26. private void Start()
  27. {
  28. hand = GetComponent<Hand>();
  29. //spawn hand collider and link it to us
  30. handCollider = ((GameObject)Instantiate(handColliderPrefab.gameObject)).GetComponent<HandCollider>();
  31. Vector3 localPosition = handCollider.transform.localPosition;
  32. Quaternion localRotation = handCollider.transform.localRotation;
  33. handCollider.transform.parent = Player.instance.transform;
  34. handCollider.transform.localPosition = localPosition;
  35. handCollider.transform.localRotation = localRotation;
  36. handCollider.hand = this;
  37. GetComponent<SteamVR_Behaviour_Pose>().onTransformUpdated.AddListener(UpdateHand);
  38. }
  39. // cached transformations
  40. Matrix4x4 wristToRoot;
  41. Matrix4x4 rootToArmature;
  42. Matrix4x4 wristToArmature;
  43. Vector3 targetPosition = Vector3.zero;
  44. Quaternion targetRotation = Quaternion.identity;
  45. //bones
  46. const int wristBone = SteamVR_Skeleton_JointIndexes.wrist;
  47. const int rootBone = SteamVR_Skeleton_JointIndexes.root;
  48. private void FixedUpdate()
  49. {
  50. if (hand.skeleton == null) return;
  51. initialized = true;
  52. UpdateCenterPoint();
  53. handCollider.MoveTo(targetPosition, targetRotation);
  54. if ((handCollider.transform.position - targetPosition).sqrMagnitude > handResetDistance * handResetDistance)
  55. handCollider.TeleportTo(targetPosition, targetRotation);
  56. UpdateFingertips();
  57. }
  58. private void UpdateCenterPoint()
  59. {
  60. Vector3 offset = hand.skeleton.GetBonePosition(SteamVR_Skeleton_JointIndexes.middleProximal) - hand.skeleton.GetBonePosition(SteamVR_Skeleton_JointIndexes.root);
  61. if (hand.HasSkeleton())
  62. {
  63. handCollider.SetCenterPoint(hand.skeleton.transform.position + offset);
  64. }
  65. }
  66. Collider[] clearanceBuffer = new Collider[1];
  67. private void UpdatePositions()
  68. {
  69. // disable collisions when holding something
  70. if (hand.currentAttachedObject != null)
  71. {
  72. collisionsEnabled = false;
  73. }
  74. else
  75. {
  76. // wait for area to become clear before reenabling collisions
  77. if (!collisionsEnabled)
  78. {
  79. clearanceBuffer[0] = null;
  80. Physics.OverlapSphereNonAlloc(hand.objectAttachmentPoint.position, collisionReenableClearanceRadius, clearanceBuffer);
  81. // if we don't find anything in the vicinity, reenable collisions!
  82. if (clearanceBuffer[0] == null)
  83. {
  84. collisionsEnabled = true;
  85. }
  86. }
  87. }
  88. handCollider.SetCollisionDetectionEnabled(collisionsEnabled);
  89. if (hand.skeleton == null) return;
  90. initialized = true;
  91. // get the desired pose of the wrist in world space. Can't get the wrist bone transform, as this is affected by the resulting physics.
  92. wristToRoot = Matrix4x4.TRS(ProcessPos(wristBone, hand.skeleton.GetBone(wristBone).localPosition),
  93. ProcessRot(wristBone, hand.skeleton.GetBone(wristBone).localRotation),
  94. Vector3.one).inverse;
  95. rootToArmature = Matrix4x4.TRS(ProcessPos(rootBone, hand.skeleton.GetBone(rootBone).localPosition),
  96. ProcessRot(rootBone, hand.skeleton.GetBone(rootBone).localRotation),
  97. Vector3.one).inverse;
  98. wristToArmature = (wristToRoot * rootToArmature).inverse;
  99. // step up through virtual transform hierarchy and into world space
  100. targetPosition = transform.TransformPoint(wristToArmature.MultiplyPoint3x4(Vector3.zero));
  101. targetRotation = transform.rotation * wristToArmature.GetRotation();
  102. //bypass physics when game paused
  103. if (Time.timeScale == 0)
  104. {
  105. handCollider.TeleportTo(targetPosition, targetRotation);
  106. }
  107. }
  108. Transform wrist;
  109. const int thumbBone = SteamVR_Skeleton_JointIndexes.thumbDistal;
  110. const int indexBone = SteamVR_Skeleton_JointIndexes.indexDistal;
  111. const int middleBone = SteamVR_Skeleton_JointIndexes.middleDistal;
  112. const int ringBone = SteamVR_Skeleton_JointIndexes.ringDistal;
  113. const int pinkyBone = SteamVR_Skeleton_JointIndexes.pinkyDistal;
  114. void UpdateFingertips()
  115. {
  116. wrist = hand.skeleton.GetBone(SteamVR_Skeleton_JointIndexes.wrist);
  117. // set finger tip positions in wrist space
  118. for(int finger = 0; finger < 5; finger++)
  119. {
  120. int tip = SteamVR_Skeleton_JointIndexes.GetBoneForFingerTip(finger);
  121. int bone = tip;
  122. for(int i = 0; i < handCollider.fingerColliders[finger].Length; i++)
  123. {
  124. bone = tip - 1 - i; // start at distal and go down
  125. if (handCollider.fingerColliders[finger][i] != null)
  126. handCollider.fingerColliders[finger][i].localPosition = wrist.InverseTransformPoint(hand.skeleton.GetBone(bone).position);
  127. }
  128. }
  129. /*
  130. if(handCollider.tip_thumb != null)
  131. handCollider.tip_thumb.localPosition = wrist.InverseTransformPoint(hand.skeleton.GetBone(thumbBone).position);
  132. if(handCollider.tip_index != null)
  133. handCollider.tip_index.localPosition = wrist.InverseTransformPoint(hand.skeleton.GetBone(indexBone).position);
  134. if(handCollider.tip_middle != null)
  135. handCollider.tip_middle.localPosition = wrist.InverseTransformPoint(hand.skeleton.GetBone(middleBone).position);
  136. if(handCollider.tip_ring != null)
  137. handCollider.tip_ring.localPosition = wrist.InverseTransformPoint(hand.skeleton.GetBone(ringBone).position);
  138. if (handCollider.tip_pinky != null)
  139. handCollider.tip_pinky.localPosition = wrist.InverseTransformPoint(hand.skeleton.GetBone(pinkyBone).position);
  140. */
  141. }
  142. void UpdateHand(SteamVR_Behaviour_Pose pose, SteamVR_Input_Sources inputSource)
  143. {
  144. if (!initialized) return;
  145. UpdateCenterPoint();
  146. UpdatePositions();
  147. Quaternion offsetRotation = handCollider.transform.rotation * wristToArmature.inverse.GetRotation();
  148. hand.mainRenderModel.transform.rotation = offsetRotation;
  149. Vector3 offsetPosition = handCollider.transform.TransformPoint(wristToArmature.inverse.MultiplyPoint3x4(Vector3.zero));
  150. hand.mainRenderModel.transform.position = offsetPosition;
  151. /*
  152. Vector3 wristPointInArmatureSpace = transform.InverseTransformPoint(handCollider.transform.position);
  153. Vector3 handTargetPosition =
  154. hand.mainRenderModel.transform.position = handTargetPosition;
  155. //Quaternion handTargetRotation = transform.rotation * (wristToArmature.inverse.rotation * (Quaternion.Inverse(transform.rotation) * handCollider.transform.rotation));
  156. //hand.mainRenderModel.transform.rotation = handTargetRotation;
  157. */
  158. }
  159. Vector3 ProcessPos(int boneIndex, Vector3 pos)
  160. {
  161. if(hand.skeleton.mirroring != SteamVR_Behaviour_Skeleton.MirrorType.None)
  162. {
  163. return SteamVR_Behaviour_Skeleton.MirrorPosition(boneIndex, pos);
  164. }
  165. return pos;
  166. }
  167. Quaternion ProcessRot(int boneIndex, Quaternion rot)
  168. {
  169. if (hand.skeleton.mirroring != SteamVR_Behaviour_Skeleton.MirrorType.None)
  170. {
  171. return SteamVR_Behaviour_Skeleton.MirrorRotation(boneIndex, rot);
  172. }
  173. return rot;
  174. }
  175. }
  176. }