HandCollider.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace Valve.VR.InteractionSystem
  5. {
  6. public class HandCollider : MonoBehaviour
  7. {
  8. private new Rigidbody rigidbody;
  9. [HideInInspector]
  10. public HandPhysics hand;
  11. public LayerMask collisionMask;
  12. Collider[] colliders;
  13. public FingerColliders fingerColliders;
  14. [System.Serializable]
  15. public class FingerColliders
  16. {
  17. [Tooltip("Starting at tip and going down. Max 2.")]
  18. public Transform[] thumbColliders = new Transform[1];
  19. [Tooltip("Starting at tip and going down. Max 3.")]
  20. public Transform[] indexColliders = new Transform[2];
  21. [Tooltip("Starting at tip and going down. Max 3.")]
  22. public Transform[] middleColliders = new Transform[2];
  23. [Tooltip("Starting at tip and going down. Max 3.")]
  24. public Transform[] ringColliders = new Transform[2];
  25. [Tooltip("Starting at tip and going down. Max 3.")]
  26. public Transform[] pinkyColliders = new Transform[2];
  27. public Transform[] this[int finger]
  28. {
  29. get
  30. {
  31. switch (finger)
  32. {
  33. case 0:
  34. return thumbColliders;
  35. case 1:
  36. return indexColliders;
  37. case 2:
  38. return middleColliders;
  39. case 3:
  40. return ringColliders;
  41. case 4:
  42. return pinkyColliders;
  43. default:
  44. return null;
  45. }
  46. }
  47. set
  48. {
  49. switch (finger)
  50. {
  51. case 0:
  52. thumbColliders = value; break;
  53. case 1:
  54. indexColliders = value; break;
  55. case 2:
  56. middleColliders = value; break;
  57. case 3:
  58. ringColliders = value; break;
  59. case 4:
  60. pinkyColliders = value; break;
  61. }
  62. }
  63. }
  64. }
  65. private static PhysicMaterial physicMaterial_lowfriction;
  66. private static PhysicMaterial physicMaterial_highfriction;
  67. private void Awake()
  68. {
  69. rigidbody = GetComponent<Rigidbody>();
  70. rigidbody.maxAngularVelocity = 50;
  71. }
  72. private void Start()
  73. {
  74. colliders = GetComponentsInChildren<Collider>();
  75. if (physicMaterial_lowfriction == null)
  76. {
  77. physicMaterial_lowfriction = new PhysicMaterial("hand_lowFriction");
  78. physicMaterial_lowfriction.dynamicFriction = 0;
  79. physicMaterial_lowfriction.staticFriction = 0;
  80. physicMaterial_lowfriction.bounciness = 0;
  81. physicMaterial_lowfriction.bounceCombine = PhysicMaterialCombine.Minimum;
  82. physicMaterial_lowfriction.frictionCombine = PhysicMaterialCombine.Minimum;
  83. }
  84. if (physicMaterial_highfriction == null)
  85. {
  86. physicMaterial_highfriction = new PhysicMaterial("hand_highFriction");
  87. physicMaterial_highfriction.dynamicFriction = 1f;
  88. physicMaterial_highfriction.staticFriction = 1f;
  89. physicMaterial_highfriction.bounciness = 0;
  90. physicMaterial_highfriction.bounceCombine = PhysicMaterialCombine.Minimum;
  91. physicMaterial_highfriction.frictionCombine = PhysicMaterialCombine.Average;
  92. }
  93. SetPhysicMaterial(physicMaterial_lowfriction);
  94. scale = SteamVR_Utils.GetLossyScale(hand.transform);
  95. }
  96. void SetPhysicMaterial(PhysicMaterial mat)
  97. {
  98. if (colliders == null) colliders = GetComponentsInChildren<Collider>();
  99. for (int i = 0; i < colliders.Length; i++)
  100. {
  101. colliders[i].sharedMaterial = mat;
  102. }
  103. }
  104. float scale;
  105. public void SetCollisionDetectionEnabled(bool value)
  106. {
  107. rigidbody.detectCollisions = value;
  108. }
  109. public void MoveTo(Vector3 position, Quaternion rotation)
  110. {
  111. targetPosition = position;
  112. targetRotation = rotation;
  113. //rigidbody.MovePosition(position);
  114. //rigidbody.MoveRotation(rotation);
  115. ExecuteFixedUpdate();
  116. }
  117. public void TeleportTo(Vector3 position, Quaternion rotation)
  118. {
  119. targetPosition = position;
  120. targetRotation = rotation;
  121. MoveTo(position, rotation);
  122. rigidbody.position = position;
  123. if (rotation.x != 0 || rotation.y != 0 || rotation.z != 0 || rotation.w != 0)
  124. rigidbody.rotation = rotation;
  125. //also update transform in case physics is disabled
  126. transform.position = position;
  127. transform.rotation = rotation;
  128. }
  129. public void Reset()
  130. {
  131. TeleportTo(targetPosition, targetRotation);
  132. }
  133. public void SetCenterPoint(Vector3 newCenter)
  134. {
  135. center = newCenter;
  136. }
  137. private Vector3 center;
  138. private Vector3 targetPosition = Vector3.zero;
  139. private Quaternion targetRotation = Quaternion.identity;
  140. protected const float MaxVelocityChange = 10f;
  141. protected const float VelocityMagic = 6000f;
  142. protected const float AngularVelocityMagic = 50f;
  143. protected const float MaxAngularVelocityChange = 20f;
  144. public bool collidersInRadius;
  145. protected void ExecuteFixedUpdate()
  146. {
  147. collidersInRadius = Physics.CheckSphere(center, 0.2f, collisionMask);
  148. if (collidersInRadius == false)
  149. {
  150. //keep updating velocity, just in case. Otherwise you get jitter
  151. rigidbody.velocity = Vector3.zero;
  152. rigidbody.angularVelocity = Vector3.zero;
  153. /*
  154. rigidbody.velocity = (targetPosition - rigidbody.position) / Time.fixedDeltaTime;
  155. float angle; Vector3 axis;
  156. (targetRotation * Quaternion.Inverse(rigidbody.rotation)).ToAngleAxis(out angle, out axis);
  157. rigidbody.angularVelocity = axis.normalized * angle / Time.fixedDeltaTime;
  158. */
  159. rigidbody.MovePosition(targetPosition);
  160. rigidbody.MoveRotation(targetRotation);
  161. }
  162. else
  163. {
  164. Vector3 velocityTarget, angularTarget;
  165. bool success = GetTargetVelocities(out velocityTarget, out angularTarget);
  166. if (success)
  167. {
  168. float maxAngularVelocityChange = MaxAngularVelocityChange * scale;
  169. float maxVelocityChange = MaxVelocityChange * scale;
  170. rigidbody.velocity = Vector3.MoveTowards(rigidbody.velocity, velocityTarget, maxVelocityChange);
  171. rigidbody.angularVelocity = Vector3.MoveTowards(rigidbody.angularVelocity, angularTarget, maxAngularVelocityChange);
  172. }
  173. }
  174. }
  175. protected bool GetTargetVelocities(out Vector3 velocityTarget, out Vector3 angularTarget)
  176. {
  177. bool realNumbers = false;
  178. float velocityMagic = VelocityMagic;
  179. float angularVelocityMagic = AngularVelocityMagic;
  180. Vector3 positionDelta = (targetPosition - rigidbody.position);
  181. velocityTarget = (positionDelta * velocityMagic * Time.deltaTime);
  182. if (float.IsNaN(velocityTarget.x) == false && float.IsInfinity(velocityTarget.x) == false)
  183. {
  184. realNumbers = true;
  185. }
  186. else
  187. velocityTarget = Vector3.zero;
  188. Quaternion rotationDelta = targetRotation * Quaternion.Inverse(rigidbody.rotation);
  189. float angle;
  190. Vector3 axis;
  191. rotationDelta.ToAngleAxis(out angle, out axis);
  192. if (angle > 180)
  193. angle -= 360;
  194. if (angle != 0 && float.IsNaN(axis.x) == false && float.IsInfinity(axis.x) == false)
  195. {
  196. angularTarget = angle * axis * angularVelocityMagic * Time.deltaTime;
  197. realNumbers &= true;
  198. }
  199. else
  200. angularTarget = Vector3.zero;
  201. return realNumbers;
  202. }
  203. const float minCollisionEnergy = 0.1f;
  204. const float maxCollisionEnergy = 1.0f;
  205. const float minCollisionHapticsTime = 0.2f;
  206. private float lastCollisionHapticsTime;
  207. private void OnCollisionEnter(Collision collision)
  208. {
  209. bool touchingDynamic = false;
  210. if (collision.rigidbody != null)
  211. {
  212. if (collision.rigidbody.isKinematic == false) touchingDynamic = true;
  213. }
  214. // low friction if touching static object, high friction if touching dynamic
  215. SetPhysicMaterial(touchingDynamic ? physicMaterial_highfriction : physicMaterial_lowfriction);
  216. float energy = collision.relativeVelocity.magnitude;
  217. if(energy > minCollisionEnergy && Time.time - lastCollisionHapticsTime > minCollisionHapticsTime)
  218. {
  219. lastCollisionHapticsTime = Time.time;
  220. float intensity = Util.RemapNumber(energy, minCollisionEnergy, maxCollisionEnergy, 0.3f, 1.0f);
  221. float length = Util.RemapNumber(energy, minCollisionEnergy, maxCollisionEnergy, 0.0f, 0.06f);
  222. hand.hand.TriggerHapticPulse(length, 100, intensity);
  223. }
  224. }
  225. }
  226. }