Advertisement
Guest User

Grabber.cs Oculus Touch

a guest
Dec 28th, 2016
478
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.00 KB | None | 0 0
  1. /********************************************************************************//**
  2. \file Grabber.cs
  3. \brief Basic sample to demonstrating adding grabbing to Avatar SDK or custom hands.
  4. \copyright Copyright 2015 Oculus VR, LLC All Rights reserved.
  5. ************************************************************************************/
  6.  
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using UnityEngine;
  10. using OVRTouchSample;
  11.  
  12. namespace OVRTouchSample
  13. {
  14.  
  15. [RequireComponent(typeof(Rigidbody))]
  16. [RequireComponent(typeof(VelocityTracker))]
  17. public class Grabber : MonoBehaviour
  18. {
  19. // Grip trigger thresholds for picking up objects, with some hysteresis.
  20. public const float THRESH_GRAB_BEGIN = 0.55f;
  21. public const float THRESH_GRAB_END = 0.35f;
  22. // Velocity threshold to distinguish between a throw and a drop.
  23. public const float THRESH_THROW_SPEED = 1.0f;
  24.  
  25. // Demonstrates a quick/experimental approach to attaching objects to the hand using a FixedJoint.
  26. // Not satisfactory in this use case. Since the Hand is allowed inside the geometry and the
  27. // non-kinematic held object is not, this leads to jittery physics as it attempts to move the
  28. // held object into the geometry, unless we specify a trivially breakable break force.
  29. // Needs a more elaborate solution.
  30. [SerializeField]
  31. private bool m_useFixedJointForGrabbedObject = false;
  32.  
  33. // Demonstrates parenting the held object to the hand's transform when grabbed.
  34. // When false, the grabbed object is moved every FixedUpdate using MovePosition.
  35. // Note that MovePosition is required for proper physics simulation. If you set this to true, you can
  36. // easily observe broken physics simulation by, for example, moving the bottom cube of a stacked
  37. // tower and noting a complete loss of friction.
  38. [SerializeField]
  39. private bool m_parentHeldObject = false;
  40.  
  41. // Child/attached transforms of the grabber, indicating where to snap held objects to (if you snap them).
  42. // Also used for ranking grab targets in case of multiple candidates.
  43. [SerializeField]
  44. private Transform m_gripTransform = null;
  45. // Child/attached Colliders to detect candidate grabbable objects.
  46. [SerializeField]
  47. private Collider[] m_grabVolumes = null;
  48.  
  49. // Avatar to pull hand poses from.
  50. [SerializeField]
  51. private OvrAvatar m_avatar;
  52. // Should be OVRInput.Controller.LTouch or OVRInput.Controller.RTouch.
  53. [SerializeField]
  54. private OVRInput.Controller m_controller;
  55.  
  56. private VelocityTracker m_velocityTracker = null;
  57. private bool m_grabVolumeEnabled = true;
  58. private Vector3 m_lastPos;
  59. private Quaternion m_lastRot;
  60. private Quaternion m_anchorOffsetRotation;
  61. private Vector3 m_anchorOffsetPosition;
  62. private float m_prevFlex;
  63. private Transform m_parentTransform;
  64. private Grabbable m_grabbedObj = null;
  65. private Dictionary<Grabbable, int> m_grabCandidates = new Dictionary<Grabbable, int>();
  66.  
  67. public void ForceRelease(Grabbable grabbable)
  68. {
  69. bool canRelease = (
  70. (m_grabbedObj != null) &&
  71. (m_grabbedObj == grabbable)
  72. );
  73. if (canRelease)
  74. {
  75. GrabEnd();
  76. }
  77. }
  78. private void Awake()
  79. {
  80. m_anchorOffsetPosition = transform.localPosition;
  81. m_anchorOffsetRotation = transform.localRotation;
  82. }
  83.  
  84. private void Start()
  85. {
  86. m_velocityTracker = this.GetComponent<VelocityTracker>();
  87. m_lastPos = transform.position;
  88. m_lastRot = transform.rotation;
  89. m_parentTransform = gameObject.transform.parent.transform;
  90. }
  91.  
  92. private void Update()
  93. {
  94. if (m_avatar != null && m_avatar.Driver != null)
  95. {
  96. float prevFlex = m_prevFlex;
  97.  
  98. OvrAvatarDriver.PoseFrame frame;
  99. m_avatar.Driver.GetCurrentPose(out frame);
  100. OvrAvatarDriver.ControllerPose pose = m_controller == OVRInput.Controller.LTouch ? frame.controllerLeftPose : frame.controllerRightPose;
  101. // Update values from inputs
  102. m_prevFlex = pose.handTrigger;
  103.  
  104. CheckForGrabOrRelease(prevFlex);
  105. }
  106. }
  107.  
  108. // Hands follow the touch anchors by calling MovePosition each frame to reach the anchor.
  109. // This is done instead of parenting to achieve workable physics. If you don't require physics on
  110. // your hands or held objects, you may wish to switch to parenting.
  111. //
  112. // BUG: currently (Unity 5.5.0f3.), there's an unavoidable cosmetic issue with
  113. // the hand. FixedUpdate must be used, or else physics behavior is wildly erratic.
  114. // However, FixedUpdate cannot be guaranteed to run every frame, even when at 90Hz.
  115. // On frames where FixedUpdate fails to run, the hand will fail to update its position, causing apparent
  116. // judder. A fix is in progress, but not fixable on the user side at this time.
  117. private void FixedUpdate()
  118. {
  119. Vector3 handPos = OVRInput.GetLocalControllerPosition(m_controller);
  120. Quaternion handRot = OVRInput.GetLocalControllerRotation(m_controller);
  121. GetComponent<Rigidbody>().MovePosition(m_anchorOffsetPosition + handPos + m_parentTransform.position);
  122. GetComponent<Rigidbody>().MoveRotation(handRot * m_anchorOffsetRotation * m_parentTransform.rotation);
  123.  
  124. if (!m_useFixedJointForGrabbedObject && !m_parentHeldObject)
  125. {
  126. MoveGrabbedObject();
  127. }
  128. m_lastPos = transform.position;
  129. m_lastRot = transform.rotation;
  130. }
  131.  
  132. private void OnDestroy()
  133. {
  134. if (m_grabbedObj != null)
  135. {
  136. GrabEnd();
  137. }
  138. }
  139.  
  140. private void OnTriggerEnter(Collider otherCollider)
  141. {
  142. // Get the grab trigger
  143. Grabbable grabbable = otherCollider.GetComponent<Grabbable>() ?? otherCollider.GetComponentInParent<Grabbable>();
  144. if (grabbable == null) return;
  145.  
  146. // Add the grabbable
  147. int refCount = 0;
  148. m_grabCandidates.TryGetValue(grabbable, out refCount);
  149. m_grabCandidates[grabbable] = refCount + 1;
  150. }
  151.  
  152. private void OnTriggerExit(Collider otherCollider)
  153. {
  154. Grabbable grabbable = otherCollider.GetComponent<Grabbable>() ?? otherCollider.GetComponentInParent<Grabbable>();
  155. if (grabbable == null) return;
  156.  
  157. // Remove the grabbable
  158. int refCount = 0;
  159. bool found = m_grabCandidates.TryGetValue(grabbable, out refCount);
  160. if (!found)
  161. {
  162. return;
  163. }
  164.  
  165. if (refCount > 1)
  166. {
  167. m_grabCandidates[grabbable] = refCount - 1;
  168. }
  169. else
  170. {
  171. m_grabCandidates.Remove(grabbable);
  172. }
  173. }
  174.  
  175. private void CheckForGrabOrRelease(float prevFlex)
  176. {
  177. if ((m_prevFlex >= THRESH_GRAB_BEGIN) && (prevFlex < THRESH_GRAB_BEGIN))
  178. {
  179. GrabBegin();
  180. }
  181. else if ((m_prevFlex <= THRESH_GRAB_END) && (prevFlex > THRESH_GRAB_END))
  182. {
  183. GrabEnd();
  184. }
  185. }
  186.  
  187. private void GrabBegin()
  188. {
  189. float closestMagSq = float.MaxValue;
  190. Grabbable closestGrabbable = null;
  191. Collider closestGrabbableCollider = null;
  192.  
  193. // Iterate grab candidates and find the closest grabbable candidate
  194. foreach (Grabbable grabbable in m_grabCandidates.Keys)
  195. {
  196. bool canGrab = !(grabbable.IsGrabbed && !grabbable.AllowOffhandGrab);
  197. if (!canGrab)
  198. {
  199. continue;
  200. }
  201.  
  202. for (int j = 0; j < grabbable.GrabPoints.Length; ++j)
  203. {
  204. Collider grabbableCollider = grabbable.GrabPoints[j];
  205. // Store the closest grabbable
  206. Vector3 closestPointOnBounds = grabbableCollider.ClosestPointOnBounds(m_gripTransform.position);
  207. float grabbableMagSq = (m_gripTransform.position - closestPointOnBounds).sqrMagnitude;
  208. if (grabbableMagSq < closestMagSq)
  209. {
  210. closestMagSq = grabbableMagSq;
  211. closestGrabbable = grabbable;
  212. closestGrabbableCollider = grabbableCollider;
  213. }
  214. }
  215. }
  216.  
  217. // Disable grab volumes to prevent overlaps
  218. GrabVolumeEnable(false);
  219.  
  220. if (closestGrabbable != null)
  221. {
  222. if (closestGrabbable.IsGrabbed)
  223. {
  224. closestGrabbable.GrabbedBy.OffhandGrabbed(closestGrabbable);
  225. }
  226.  
  227. m_grabbedObj = closestGrabbable;
  228. m_grabbedObj.GrabBegin(this, closestGrabbableCollider);
  229.  
  230. if(m_useFixedJointForGrabbedObject)
  231. {
  232. FixedJoint fj = gameObject.GetComponent<FixedJoint>() ?? gameObject.AddComponent<FixedJoint>();
  233. fj.connectedBody = m_grabbedObj.GetComponent<Rigidbody>();
  234. }
  235. else
  236. {
  237. // Teleport on grab, to avoid high-speed travel to dest which hits a lot of other objects at high
  238. // speed and sends them flying. The grabbed object may still teleport inside of other objects, but fixing that
  239. // is beyond the scope of this demo.
  240. m_lastPos = transform.position;
  241. m_lastRot = transform.rotation;
  242. MoveGrabbedObject(true);
  243. if(m_parentHeldObject)
  244. {
  245. m_grabbedObj.transform.parent = transform;
  246. }
  247. }
  248. }
  249. }
  250.  
  251. private void MoveGrabbedObject(bool forceTeleport = false)
  252. {
  253. if (m_grabbedObj == null)
  254. {
  255. return;
  256. }
  257.  
  258. Vector3 handInitialPosition = m_lastPos;
  259. Quaternion handInitialRotation = m_lastRot;
  260. Vector3 handFinalPosition = transform.position;
  261. Quaternion handFinalRotation = transform.rotation;
  262. Quaternion handDeltaRotation = handFinalRotation * Quaternion.Inverse(handInitialRotation);
  263.  
  264. bool snapPosition = m_grabbedObj.SnapPosition;
  265. bool snapRotation = m_grabbedObj.SnapOrientation;
  266. Vector3 snapOffset = Vector3.zero;
  267. Quaternion snapRot = Quaternion.identity;
  268. if (snapPosition && m_grabbedObj.SnapOffset)
  269. {
  270. snapOffset = m_grabbedObj.SnapOffset.position;
  271. if (m_controller == OVRInput.Controller.LTouch) snapOffset.x = -snapOffset.x;
  272. snapOffset = transform.rotation * snapOffset;
  273. }
  274. if (snapRotation && m_grabbedObj.SnapOffset)
  275. {
  276. snapRot = m_grabbedObj.SnapOffset.rotation;
  277. }
  278.  
  279. Rigidbody grabbedRigidbody = m_grabbedObj.GrabbedRigidbody;
  280. Transform grabbedTransform = grabbedRigidbody.transform;
  281. // snap uses: gripTransform.position, transform.position, m_lastpos
  282. // nosnap uses: m_lastPos, transform.position, grabbedTransform.position
  283. Vector3 grabbablePosition = snapPosition ?
  284. m_gripTransform.position + snapOffset + handDeltaRotation * (handFinalPosition - handInitialPosition) :
  285. handFinalPosition + handDeltaRotation * (grabbedTransform.position - handInitialPosition);
  286. Quaternion grabbableRotation = snapRotation ?
  287. handDeltaRotation * m_gripTransform.rotation :
  288. handDeltaRotation * grabbedTransform.rotation;
  289.  
  290. if(snapRotation && m_grabbedObj.SnapOffset)
  291. {
  292. grabbableRotation *= m_grabbedObj.SnapOffset.rotation;
  293. }
  294.  
  295. if (forceTeleport)
  296. {
  297. grabbedRigidbody.transform.position = grabbablePosition;
  298. grabbedRigidbody.transform.rotation = grabbableRotation;
  299. }
  300. else
  301. {
  302. grabbedRigidbody.MovePosition(grabbablePosition);
  303. grabbedRigidbody.MoveRotation(grabbableRotation);
  304. }
  305. }
  306.  
  307. private void GrabEnd()
  308. {
  309. if (m_grabbedObj != null)
  310. {
  311. // Determine if the grabbable was thrown, compute appropriate velocities.
  312. bool wasThrown = m_velocityTracker.TrackedLinearVelocity.magnitude >= THRESH_THROW_SPEED;
  313. Vector3 linearVelocity = Vector3.zero;
  314. Vector3 angularVelocity = Vector3.zero;
  315. if (wasThrown)
  316. {
  317. // Throw velocity
  318. linearVelocity = m_velocityTracker.TrackedLinearVelocity;
  319. angularVelocity = m_velocityTracker.TrackedAngularVelocity;
  320. }
  321. else
  322. {
  323. // Drop velocity
  324. linearVelocity = m_velocityTracker.FrameLinearVelocity;
  325. angularVelocity = m_velocityTracker.FrameAngularVelocity;
  326. }
  327.  
  328. GrabbableRelease(linearVelocity, angularVelocity);
  329. }
  330.  
  331. // Re-enable grab volumes to allow overlap events
  332. GrabVolumeEnable(true);
  333. }
  334.  
  335. private void GrabbableRelease(Vector3 linearVelocity, Vector3 angularVelocity)
  336. {
  337. Destroy(gameObject.GetComponent<FixedJoint>());
  338. m_grabbedObj.GrabEnd(linearVelocity, angularVelocity);
  339. if(m_parentHeldObject) m_grabbedObj.transform.parent = null;
  340. m_grabbedObj = null;
  341. }
  342.  
  343. private void GrabVolumeEnable(bool enabled)
  344. {
  345. if (m_grabVolumeEnabled == enabled)
  346. {
  347. return;
  348. }
  349.  
  350. m_grabVolumeEnabled = enabled;
  351. for (int i = 0; i < m_grabVolumes.Length; ++i)
  352. {
  353. Collider grabVolume = m_grabVolumes[i];
  354. grabVolume.enabled = m_grabVolumeEnabled;
  355. }
  356.  
  357. if (!m_grabVolumeEnabled)
  358. {
  359. m_grabCandidates.Clear();
  360. }
  361. }
  362.  
  363. private void OffhandGrabbed(Grabbable grabbable)
  364. {
  365. if (m_grabbedObj == grabbable)
  366. {
  367. GrabbableRelease(Vector3.zero, Vector3.zero);
  368. }
  369. }
  370. }
  371. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement