CustomHand.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Valve.VR;
  5. using Valve.VR.InteractionSystem;
  6. public class CustomHand : MonoBehaviour
  7. {
  8. public float gripRadius, indexRadius, pinchRadius;//different grabs radiuses
  9. public Vector3 grabPoint = new Vector3(0, 0, -.1f), indexPoint = new Vector3(-0.04f, -0.055f, -0.005f), pinchPoint = new Vector3(0, 0, -.05f);//локальная позиция точки захвата левой руки
  10. public LayerMask layerColliderChecker;//Layer to interact & grab with
  11. public SteamVR_Action_Boolean grabButton, pinchButton;//grab inputs
  12. public SteamVR_Action_Single SqueezeButton;//squeeze input he he
  13. public SteamVR_Input_Sources handType;//hand type, is it right or left
  14. public GrabType grabType;// current grab type
  15. public enum GrabType
  16. {
  17. None,
  18. Select,
  19. Grip,
  20. Pinch,
  21. }
  22. public SteamVR_RenderModel RenderModel;// controller model
  23. [Range(0.001f, 1f)]
  24. public float blend = .1f, blendPosition = .1f;// hand blend transition speed
  25. public bool smoothBlendPhysicsObject;// smooth pickup of physical object
  26. public Collider[] SelectedGpibColliders, SelectedIndexColliders, SelectedPinchColliders;//colliders in a grab radius
  27. public CustomInteractible SelectedIndexInteractible, SelectedPinchInteractible, SelectedGpibInteractible, GrabInteractible;// nearest interaction objects and object is currently interacting with
  28. public SteamVR_Behaviour_Skeleton skeleton;// current hand's skeleton
  29. public SteamVR_Skeleton_Poser grabPoser;// poser of object currently interacting with
  30. public Vector3 posSavePoser, rotSavePoser, inverceLocalPosition;//magic variables, which are need to calculate something ( need to know )
  31. public Transform PivotPoser, ToolTransform;//Pivot from hands poser, hidden instrument to simplify some calculations
  32. public bool HideController;//hide controller
  33. public float Squeeze;//squeeze strength
  34. public SteamVR_Action_Vibration hapticSignal = SteamVR_Input.GetAction<SteamVR_Action_Vibration>("Haptic");//Output of haptic ramble
  35. bool setHandTransform;//Assing position, to pass of the 1st frame, used to be a bug ( maybe remove, need to check if this bug still here )
  36. float blendToAnimation = 1, blendToPose = 1, blendToPoseMoveObject = 1;//smooth transition for animation and pose
  37. Vector3 endFramePos, oldInterpolatePos;
  38. Quaternion endFrameRot, oldInterpolateRot;
  39. //protected SteamVR_Events.Action renderModelLoadedAction;
  40. //protected void Awake()
  41. //{
  42. // renderModelLoadedAction = SteamVR_Events.RenderModelLoadedAction(OnRenderModelLoaded);
  43. //}
  44. //private void OnRenderModelLoaded(SteamVR_RenderModel loadedRenderModel, bool success)
  45. //{
  46. // print(1);
  47. //}
  48. void Start()
  49. {
  50. if (!PivotPoser)
  51. PivotPoser = new GameObject().transform;
  52. PivotPoser.hideFlags = HideFlags.HideInHierarchy;
  53. if (!ToolTransform)
  54. ToolTransform = new GameObject().transform;
  55. ToolTransform.hideFlags = HideFlags.HideInHierarchy;
  56. if (GetComponent<SteamVR_Behaviour_Pose>())
  57. {
  58. handType = GetComponent<SteamVR_Behaviour_Pose>().inputSource;
  59. }
  60. else
  61. {
  62. Debug.LogError("no SteamVR_Behaviour_Pose on this object");
  63. }
  64. if (GetComponentInChildren<SteamVR_Behaviour_Skeleton>())
  65. {
  66. skeleton = GetComponentInChildren<SteamVR_Behaviour_Skeleton>();
  67. }
  68. if (GetComponentInChildren<SteamVR_RenderModel>())
  69. {
  70. RenderModel = GetComponentInChildren<SteamVR_RenderModel>();
  71. }
  72. skeleton.BlendToSkeleton();
  73. StartCoroutine(HideControllerCoroutine());
  74. }
  75. void FixedUpdate()
  76. {
  77. SelectIndexObject();
  78. Squeeze = SqueezeButton.GetAxis(handType);
  79. PivotUpdate();
  80. GrabCheck();
  81. if (grabPoser && GrabInteractible)
  82. {
  83. GrabUpdate();
  84. return;
  85. }
  86. SelectPinchObject();
  87. SelectGribObject();
  88. }
  89. IEnumerator HideControllerCoroutine() {
  90. while (true)
  91. {
  92. if (RenderModel.transform.childCount > 0)
  93. {
  94. RenderModel.SetMeshRendererState(!HideController);
  95. break;
  96. }
  97. yield return 0;
  98. }
  99. }
  100. void GrabCheck()
  101. {
  102. if (grabType != GrabType.None && GrabInteractible)
  103. {
  104. if (grabType == GrabType.Pinch && pinchButton.GetStateUp(handType))
  105. {
  106. GrabInteractible.SendMessage("GrabEnd", this, SendMessageOptions.DontRequireReceiver);
  107. GrabEnd();
  108. }
  109. if (grabType == GrabType.Grip && grabButton.GetStateUp(handType))
  110. {
  111. GrabInteractible.SendMessage("GrabEnd", this, SendMessageOptions.DontRequireReceiver);
  112. GrabEnd();
  113. }
  114. }
  115. if (!grabPoser)
  116. {
  117. if (blend > 0)
  118. {
  119. blendToAnimation += 1f / blend * Time.deltaTime;
  120. blendToAnimation = Mathf.Clamp01(blendToAnimation);
  121. blendToPose += 1f / blendPosition * Time.deltaTime;
  122. blendToPose = Mathf.Clamp01(blendToPose);
  123. blendToPoseMoveObject += 1f / blendPosition * Time.deltaTime;
  124. blendToPoseMoveObject = Mathf.Clamp01(blendToPoseMoveObject);
  125. }
  126. else
  127. {
  128. blendToAnimation = 1;
  129. }
  130. CustomInteractible OldGrabInteractible = GrabInteractible;
  131. if (SelectedIndexInteractible)
  132. {
  133. GrabInteractible = SelectedIndexInteractible;
  134. if (GrabInteractible != OldGrabInteractible)
  135. {
  136. if (OldGrabInteractible)
  137. OldGrabInteractible.SendMessage("GrabEnd", this, SendMessageOptions.DontRequireReceiver);
  138. if (GrabInteractible)
  139. {
  140. GrabInteractible.SendMessage("GrabStart", this, SendMessageOptions.DontRequireReceiver);
  141. setHandTransform = false;
  142. grabType = GrabType.Select;
  143. RenderModelVisible(!GrabInteractible.HideController);
  144. SkeletonUpdate();
  145. blendToPose = 1;
  146. blendToPoseMoveObject = 1;
  147. endFramePos = transform.parent.InverseTransformPoint(skeleton.transform.position);
  148. endFrameRot = skeleton.transform.rotation;
  149. }
  150. }
  151. }
  152. else
  153. {
  154. if (SelectedPinchInteractible && pinchButton.GetStateDown(handType))
  155. {
  156. GrabInteractible = SelectedPinchInteractible;
  157. if (GrabInteractible != OldGrabInteractible)
  158. {
  159. if (OldGrabInteractible)
  160. OldGrabInteractible.SendMessage("GrabEnd", this, SendMessageOptions.DontRequireReceiver);
  161. if (GrabInteractible)
  162. {
  163. GrabInteractible.SendMessage("GrabStart", this, SendMessageOptions.DontRequireReceiver);
  164. setHandTransform = false;
  165. grabType = GrabType.Pinch;
  166. RenderModelVisible(!GrabInteractible.HideController);
  167. SkeletonUpdate();
  168. blendToPose = 1;
  169. blendToPoseMoveObject = 1;
  170. endFramePos = transform.parent.InverseTransformPoint(skeleton.transform.position);
  171. endFrameRot = skeleton.transform.rotation;
  172. }
  173. }
  174. }
  175. else
  176. {
  177. if (SelectedGpibInteractible && grabButton.GetStateDown(handType))
  178. {
  179. GrabInteractible = SelectedGpibInteractible;
  180. if (GrabInteractible != OldGrabInteractible)
  181. {
  182. if (OldGrabInteractible)
  183. OldGrabInteractible.SendMessage("GrabEnd", this, SendMessageOptions.DontRequireReceiver);
  184. if (GrabInteractible)
  185. {
  186. GrabInteractible.SendMessage("GrabStart", this, SendMessageOptions.DontRequireReceiver);
  187. setHandTransform = false;
  188. grabType = GrabType.Grip;
  189. RenderModelVisible(!GrabInteractible.HideController);
  190. SkeletonUpdate();
  191. blendToPose = 1;
  192. blendToPoseMoveObject = 1;
  193. endFramePos = transform.parent.InverseTransformPoint(skeleton.transform.position);
  194. endFrameRot = skeleton.transform.rotation;
  195. }
  196. }
  197. }
  198. }
  199. }
  200. }
  201. }
  202. public void GrabUpdateCustom()
  203. {
  204. if (grabPoser)
  205. {
  206. skeleton.BlendToPoser(grabPoser, 0);
  207. posSavePoser = grabPoser.transform.localPosition;
  208. rotSavePoser = grabPoser.transform.localEulerAngles;
  209. grabPoser.transform.rotation = transform.rotation * grabPoser.GetBlendedPose(skeleton).rotation;
  210. grabPoser.transform.position = transform.TransformPoint(grabPoser.GetBlendedPose(skeleton).position);
  211. PivotUpdate();
  212. inverceLocalPosition = grabPoser.transform.InverseTransformPoint(transform.position);
  213. grabPoser.transform.localPosition = posSavePoser;
  214. grabPoser.transform.localEulerAngles = rotSavePoser;
  215. skeleton.transform.position = grabPoser.transform.TransformPoint(inverceLocalPosition);
  216. skeleton.transform.rotation = grabPoser.transform.rotation * Quaternion.Inverse(grabPoser.GetBlendedPose(skeleton).rotation);
  217. if (blend > 0)
  218. {
  219. blendToAnimation -= 1f / blend * Time.deltaTime;
  220. blendToAnimation = Mathf.Clamp01(blendToAnimation);
  221. blendToPose -= 1f / blendPosition * Time.deltaTime;
  222. blendToPose = Mathf.Clamp01(blendToPose);
  223. blendToPoseMoveObject -= 1f / blendPosition * Time.deltaTime;
  224. blendToPoseMoveObject = Mathf.Clamp01(blendToPoseMoveObject);
  225. }
  226. else
  227. {
  228. blendToAnimation = 0;
  229. }
  230. skeleton.skeletonBlend = blendToAnimation;
  231. }
  232. }
  233. void GrabUpdate()
  234. {
  235. if (grabPoser)
  236. {
  237. skeleton.BlendToPoser(grabPoser, 0);
  238. posSavePoser = grabPoser.transform.localPosition;
  239. rotSavePoser = grabPoser.transform.localEulerAngles;
  240. grabPoser.transform.rotation = transform.rotation * grabPoser.GetBlendedPose(skeleton).rotation;
  241. grabPoser.transform.position = transform.TransformPoint(grabPoser.GetBlendedPose(skeleton).position);
  242. PivotUpdate();
  243. inverceLocalPosition = grabPoser.transform.InverseTransformPoint(transform.position);
  244. grabPoser.transform.localPosition = posSavePoser;
  245. grabPoser.transform.localEulerAngles = rotSavePoser;
  246. GrabInteractible.SendMessage("GrabUpdate", this, SendMessageOptions.DontRequireReceiver);
  247. if (blend > 0)
  248. {
  249. blendToAnimation -= 1f / blend * Time.deltaTime;
  250. blendToAnimation = Mathf.Clamp01(blendToAnimation);
  251. blendToPose -= 1f / blendPosition * Time.deltaTime;
  252. blendToPose = Mathf.Clamp01(blendToPose);
  253. blendToPoseMoveObject -= 1f / blendPosition * Time.deltaTime;
  254. blendToPoseMoveObject = Mathf.Clamp01(blendToPoseMoveObject);
  255. }
  256. else
  257. {
  258. blendToAnimation = 0;
  259. }
  260. skeleton.skeletonBlend = blendToAnimation;
  261. }
  262. }
  263. public void HapticResponse(float hlength, float hfreq, float hpower)
  264. {
  265. hapticSignal.Execute(0, hlength, hfreq, hpower, handType);
  266. }
  267. void LateUpdate()
  268. {
  269. if (grabPoser)
  270. {
  271. if (setHandTransform)
  272. {
  273. skeleton.transform.position = grabPoser.transform.TransformPoint(inverceLocalPosition);
  274. skeleton.transform.rotation = grabPoser.transform.rotation * Quaternion.Inverse(grabPoser.GetBlendedPose(skeleton).rotation);
  275. skeleton.transform.position = Vector3.Lerp(skeleton.transform.position, transform.parent.TransformPoint(endFramePos), blendToPose);
  276. skeleton.transform.rotation = Quaternion.Lerp(skeleton.transform.rotation, endFrameRot, blendToPose);
  277. oldInterpolatePos = skeleton.transform.position;
  278. oldInterpolateRot = skeleton.transform.rotation;
  279. }
  280. else
  281. {
  282. setHandTransform = true;
  283. }
  284. }
  285. else
  286. {
  287. skeleton.transform.position = Vector3.Lerp(transform.parent.TransformPoint(endFramePos), skeleton.transform.parent.position, blendToPose);
  288. skeleton.transform.rotation = Quaternion.Lerp(endFrameRot, skeleton.transform.parent.rotation, blendToPose);
  289. }
  290. }
  291. public void RenderModelVisible(bool visible)
  292. {
  293. if (RenderModel)
  294. {
  295. RenderModel.SetMeshRendererState(visible);
  296. }
  297. }
  298. void GrabEnd()
  299. {
  300. endFramePos = transform.parent.InverseTransformPoint(oldInterpolatePos);
  301. endFrameRot = oldInterpolateRot;
  302. skeleton.transform.localPosition = Vector3.zero;
  303. skeleton.transform.localEulerAngles = Vector3.zero; ///save coord
  304. skeleton.BlendToSkeleton(blend);
  305. RenderModelVisible(!HideController);
  306. blendToPose = 0;
  307. blendToPoseMoveObject = 0;
  308. grabPoser = null;
  309. GrabInteractible = null;
  310. grabType = GrabType.None;
  311. }
  312. public void DetachHand()
  313. {
  314. GrabEnd();
  315. }
  316. void SelectIndexObject()
  317. {
  318. if (!grabPoser)
  319. {
  320. SelectedIndexColliders = Physics.OverlapSphere(IndexPoint(), indexRadius, layerColliderChecker);
  321. SelectedIndexInteractible = null;
  322. float tempCloseDistance = float.MaxValue;
  323. for (int i = 0; i < SelectedIndexColliders.Length; i++)
  324. {
  325. CustomInteractible tempCustomInteractible = SelectedIndexColliders[i].GetComponentInParent<CustomInteractible>();
  326. if (tempCustomInteractible != null && tempCustomInteractible.isInteractible && tempCustomInteractible.grabType == GrabType.Select)
  327. {
  328. if (Vector3.Distance(tempCustomInteractible.transform.position, IndexPoint()) < tempCloseDistance)
  329. {
  330. tempCloseDistance = Vector3.Distance(tempCustomInteractible.transform.position, IndexPoint());
  331. SelectedIndexInteractible = tempCustomInteractible;
  332. }
  333. }
  334. }
  335. }
  336. else
  337. {
  338. if (SelectedIndexInteractible)
  339. {
  340. SelectedIndexColliders = Physics.OverlapSphere(IndexPoint(), indexRadius * 2f, layerColliderChecker);
  341. if (SelectedIndexColliders == null || SelectedIndexColliders.Length == 0)
  342. {
  343. SelectedIndexInteractible.SendMessage("GrabEnd", this, SendMessageOptions.DontRequireReceiver);
  344. GrabEnd();
  345. SelectedIndexInteractible = null;
  346. return;
  347. }
  348. for (int i = 0; i < SelectedIndexColliders.Length; i++)
  349. {
  350. CustomInteractible tempCustomInteractible = SelectedIndexColliders[i].GetComponentInParent<CustomInteractible>();
  351. if (tempCustomInteractible && tempCustomInteractible == SelectedIndexInteractible)
  352. {
  353. return;
  354. }
  355. }
  356. SelectedIndexInteractible.SendMessage("GrabEnd", this, SendMessageOptions.DontRequireReceiver);
  357. GrabEnd();
  358. SelectedIndexInteractible = null;
  359. }
  360. }
  361. }
  362. void SelectPinchObject()
  363. {
  364. if (!grabPoser)
  365. {
  366. SelectedPinchColliders = Physics.OverlapSphere(PinchPoint(), pinchRadius, layerColliderChecker);
  367. SelectedPinchInteractible = null;
  368. float tempCloseDistance = float.MaxValue;
  369. for (int i = 0; i < SelectedPinchColliders.Length; i++)
  370. {
  371. CustomInteractible tempCustomInteractible = SelectedPinchColliders[i].GetComponentInParent<CustomInteractible>();
  372. if (tempCustomInteractible != null && tempCustomInteractible.isInteractible && tempCustomInteractible.grabType == GrabType.Pinch)
  373. {
  374. if (Vector3.Distance(tempCustomInteractible.transform.position, PinchPoint()) < tempCloseDistance)
  375. {
  376. tempCloseDistance = Vector3.Distance(tempCustomInteractible.transform.position, PinchPoint());
  377. SelectedPinchInteractible = tempCustomInteractible;
  378. }
  379. }
  380. }
  381. }
  382. }
  383. void SelectGribObject()
  384. {
  385. if (!grabPoser)
  386. {
  387. SelectedGpibColliders = Physics.OverlapSphere(GrabPoint(), gripRadius, layerColliderChecker);
  388. SelectedGpibInteractible = null;
  389. float tempCloseDistance = float.MaxValue;
  390. for (int i = 0; i < SelectedGpibColliders.Length; i++)
  391. {
  392. CustomInteractible tempCustomInteractible = SelectedGpibColliders[i].GetComponentInParent<CustomInteractible>();
  393. if (tempCustomInteractible != null && tempCustomInteractible.isInteractible && tempCustomInteractible.grabType == GrabType.Grip)
  394. {
  395. if (Vector3.Distance(tempCustomInteractible.transform.position, GrabPoint()) < tempCloseDistance)
  396. {
  397. tempCloseDistance = Vector3.Distance(tempCustomInteractible.transform.position, GrabPoint());
  398. SelectedGpibInteractible = tempCustomInteractible;
  399. }
  400. }
  401. }
  402. }
  403. }
  404. public void SkeletonUpdate()
  405. {
  406. if (skeleton)
  407. {
  408. if (grabPoser)
  409. {
  410. skeleton.BlendToPoser(grabPoser);
  411. PivotUpdate();
  412. }
  413. }
  414. }
  415. public void PivotUpdate()
  416. {
  417. if (grabPoser)
  418. {
  419. PivotPoser.rotation = transform.rotation * grabPoser.GetBlendedPose(skeleton).rotation;
  420. PivotPoser.position = transform.TransformPoint(grabPoser.GetBlendedPose(skeleton).position);
  421. }
  422. }
  423. public Vector3 GrabPoint()
  424. {
  425. if (handType == SteamVR_Input_Sources.RightHand)
  426. return transform.TransformPoint(Vector3.Scale(new Vector3(-1, 1, 1), grabPoint));
  427. if (handType == SteamVR_Input_Sources.LeftHand)
  428. return transform.TransformPoint(grabPoint);
  429. return Vector3.zero;
  430. }
  431. public Vector3 PinchPoint()
  432. {
  433. if (handType == SteamVR_Input_Sources.RightHand)
  434. return transform.TransformPoint(Vector3.Scale(new Vector3(-1, 1, 1), pinchPoint));
  435. if (handType == SteamVR_Input_Sources.LeftHand)
  436. return transform.TransformPoint(pinchPoint);
  437. return Vector3.zero;
  438. }
  439. public Vector3 IndexPoint()
  440. {
  441. if (handType == SteamVR_Input_Sources.RightHand)
  442. return transform.TransformPoint(Vector3.Scale(new Vector3(-1, 1, 1), indexPoint));
  443. if (handType == SteamVR_Input_Sources.LeftHand)
  444. return transform.TransformPoint(indexPoint);
  445. return Vector3.zero;
  446. }
  447. public void SetEndFramePos() {
  448. endFramePos = transform.parent.InverseTransformPoint(skeleton.transform.position);
  449. }
  450. public void SetBlendPose(float setBlend) {
  451. blendToPoseMoveObject = setBlend;
  452. }
  453. public float GetBlendPose()
  454. {
  455. if (smoothBlendPhysicsObject)
  456. return 1 - blendToPoseMoveObject;
  457. else
  458. return 1;
  459. }
  460. void OnDrawGizmosSelected()
  461. {
  462. Gizmos.DrawWireSphere(PinchPoint(), gripRadius);
  463. Gizmos.DrawWireSphere(GrabPoint(), pinchRadius);
  464. Gizmos.DrawWireSphere(IndexPoint(), indexRadius);
  465. }
  466. }