Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

514 lines
20 KiB

  1. namespace VRTK
  2. {
  3. using UnityEngine;
  4. #if VRTK_DEFINE_SDK_WINDOWSMR && UNITY_2017_2_OR_NEWER
  5. using System.Collections;
  6. using UnityEngine.XR.WSA.Input;
  7. using VRTK.WindowsMixedReality.Utilities;
  8. #endif
  9. #if VRTK_DEFINE_WINDOWSMR_CONTROLLER_VISUALIZATION
  10. using VRTK.WindowsMixedReality;
  11. #endif
  12. public class WindowsMR_TrackedObject : MonoBehaviour
  13. {
  14. #if VRTK_DEFINE_SDK_WINDOWSMR && UNITY_2017_2_OR_NEWER
  15. private struct ButtonState
  16. {
  17. //
  18. // Summary:
  19. // ///
  20. // Normalized amount ([0, 1]) representing how much select is pressed.
  21. // ///
  22. public float SelectPressedAmount { get; set; }
  23. //
  24. // Summary:
  25. // ///
  26. // Depending on the InteractionSourceType of the interaction source, this returning
  27. // true could represent a number of equivalent things: main button on a blicker,
  28. // air-tap on a hand, and the trigger on a motion controller.
  29. // ///
  30. public bool SelectPressed { get; set; }
  31. //
  32. // Summary:
  33. // ///
  34. // Whether or not the menu button is pressed.
  35. // ///
  36. public bool MenuPressed { get; set; }
  37. //
  38. // Summary:
  39. // ///
  40. // Whether the controller is grasped.
  41. // ///
  42. public bool Grasped { get; set; }
  43. //
  44. // Summary:
  45. // ///
  46. // Whether or not the touchpad is touched.
  47. // ///
  48. public bool TouchpadTouched { get; set; }
  49. //
  50. // Summary:
  51. // ///
  52. // Whether or not the touchpad is pressed, as if a button.
  53. // ///
  54. public bool TouchpadPressed { get; set; }
  55. //
  56. // Summary:
  57. // ///
  58. // Normalized coordinates for the position of a touchpad interaction.
  59. // ///
  60. public Vector2 TouchpadPosition { get; set; }
  61. //
  62. // Summary:
  63. // ///
  64. // Normalized coordinates for the position of a thumbstick.
  65. // ///
  66. public Vector2 ThumbstickPosition { get; set; }
  67. //
  68. // Summary:
  69. // ///
  70. // Whether or not the thumbstick is pressed.
  71. // ///
  72. public bool ThumbstickPressed { get; set; }
  73. }
  74. [SerializeField]
  75. [Tooltip("Defines the controllers hand.")]
  76. private InteractionSourceHandedness handedness;
  77. public Vector3 AngularVelocity { get { return angularVelocity; } }
  78. public InteractionSourceHandedness Handedness { get { return handedness; } }
  79. public uint Index { get { return index; } }
  80. private uint index = uint.MaxValue;
  81. private ButtonState currentButtonState;
  82. private ButtonState prevButtonState;
  83. private Vector3 angularVelocity;
  84. private float hairTriggerDelta = 0.1f; // amount trigger must be pulled or released to change state
  85. private float hairTriggerLimit;
  86. private bool hairTriggerState;
  87. private bool hairTriggerPrevState;
  88. private bool isDetected;
  89. public float GetPressAmount(InteractionSourcePressType button)
  90. {
  91. switch (button)
  92. {
  93. case InteractionSourcePressType.Select:
  94. return currentButtonState.SelectPressedAmount;
  95. }
  96. return 0;
  97. }
  98. public bool GetPress(InteractionSourcePressType button)
  99. {
  100. switch (button)
  101. {
  102. case InteractionSourcePressType.Select:
  103. return currentButtonState.SelectPressed;
  104. case InteractionSourcePressType.Grasp:
  105. return currentButtonState.Grasped;
  106. case InteractionSourcePressType.Menu:
  107. return currentButtonState.MenuPressed;
  108. case InteractionSourcePressType.Touchpad:
  109. return currentButtonState.TouchpadPressed;
  110. case InteractionSourcePressType.Thumbstick:
  111. return currentButtonState.ThumbstickPressed;
  112. }
  113. return false;
  114. }
  115. public bool GetPressDown(InteractionSourcePressType button)
  116. {
  117. switch (button)
  118. {
  119. case InteractionSourcePressType.Select:
  120. return (prevButtonState.SelectPressed == false && currentButtonState.SelectPressed == true);
  121. case InteractionSourcePressType.Grasp:
  122. return (prevButtonState.Grasped == false && currentButtonState.Grasped == true);
  123. case InteractionSourcePressType.Menu:
  124. return (prevButtonState.MenuPressed == false && currentButtonState.MenuPressed == true);
  125. case InteractionSourcePressType.Touchpad:
  126. return (prevButtonState.TouchpadPressed == false && currentButtonState.TouchpadPressed == true);
  127. case InteractionSourcePressType.Thumbstick:
  128. return (prevButtonState.ThumbstickPressed == false && currentButtonState.ThumbstickPressed == true);
  129. }
  130. return false;
  131. }
  132. public bool GetPressUp(InteractionSourcePressType button)
  133. {
  134. switch (button)
  135. {
  136. case InteractionSourcePressType.Select:
  137. return (prevButtonState.SelectPressed == true && currentButtonState.SelectPressed == false);
  138. case InteractionSourcePressType.Grasp:
  139. return (prevButtonState.Grasped == true && currentButtonState.Grasped == false);
  140. case InteractionSourcePressType.Menu:
  141. return (prevButtonState.MenuPressed == true && currentButtonState.MenuPressed == false);
  142. case InteractionSourcePressType.Touchpad:
  143. return (prevButtonState.TouchpadPressed == true && currentButtonState.TouchpadPressed == false);
  144. case InteractionSourcePressType.Thumbstick:
  145. return (prevButtonState.ThumbstickPressed == true && currentButtonState.ThumbstickPressed == false);
  146. }
  147. return false;
  148. }
  149. public bool GetTouch(InteractionSourcePressType button)
  150. {
  151. switch (button)
  152. {
  153. case InteractionSourcePressType.Touchpad:
  154. return currentButtonState.TouchpadTouched;
  155. }
  156. return false;
  157. }
  158. public bool GetTouchDown(InteractionSourcePressType button)
  159. {
  160. switch (button)
  161. {
  162. case InteractionSourcePressType.Touchpad:
  163. return (prevButtonState.TouchpadTouched == false && currentButtonState.TouchpadTouched == true);
  164. }
  165. return false;
  166. }
  167. public bool GetTouchUp(InteractionSourcePressType button)
  168. {
  169. switch (button)
  170. {
  171. case InteractionSourcePressType.Touchpad:
  172. return (prevButtonState.TouchpadTouched == true && currentButtonState.TouchpadTouched == false);
  173. }
  174. return false;
  175. }
  176. public Vector2 GetAxis(InteractionSourcePressType button)
  177. {
  178. switch (button)
  179. {
  180. case InteractionSourcePressType.Select:
  181. return new Vector2(currentButtonState.SelectPressedAmount, 0f);
  182. case InteractionSourcePressType.Touchpad:
  183. return currentButtonState.TouchpadPosition;
  184. case InteractionSourcePressType.Thumbstick:
  185. return currentButtonState.ThumbstickPosition;
  186. }
  187. return Vector2.zero;
  188. }
  189. public bool GetHairTrigger()
  190. {
  191. return hairTriggerState;
  192. }
  193. public bool GetHairTriggerDown()
  194. {
  195. return (hairTriggerState && !hairTriggerPrevState);
  196. }
  197. public bool GetHairTriggerUp()
  198. {
  199. return !hairTriggerState && hairTriggerPrevState;
  200. }
  201. public void StartHaptics(float intensity = 0.5f, float duration = 0.4f)
  202. {
  203. InteractionSourceState[] states = InteractionManager.GetCurrentReading();
  204. foreach (InteractionSourceState state in states)
  205. {
  206. if (state.source.kind == InteractionSourceKind.Controller && state.source.handedness == handedness)
  207. {
  208. state.source.StartHaptics(intensity, duration);
  209. }
  210. }
  211. }
  212. protected virtual void OnEnable()
  213. {
  214. switch (handedness)
  215. {
  216. case InteractionSourceHandedness.Left:
  217. index = 1;
  218. break;
  219. case InteractionSourceHandedness.Right:
  220. index = 2;
  221. break;
  222. case InteractionSourceHandedness.Unknown:
  223. Debug.LogError("Handedness of " + gameObject.name + " is not set.");
  224. break;
  225. }
  226. InitController();
  227. }
  228. protected virtual void OnDisable()
  229. {
  230. InteractionManager.InteractionSourceDetected -= InteractionManager_InteractionSourceDetected;
  231. InteractionManager.InteractionSourceLost -= InteractionManager_InteractionSourceLost;
  232. InteractionManager.InteractionSourceUpdated -= InteractionManager_InteractionSourceUpdated;
  233. InteractionManager.InteractionSourcePressed -= InteractionManager_InteractionSourcePressed;
  234. InteractionManager.InteractionSourceReleased -= InteractionManager_InteractionSourceReleased;
  235. }
  236. protected virtual void Update()
  237. {
  238. if (isDetected)
  239. {
  240. InteractionSourceState[] states = InteractionManager.GetCurrentReading();
  241. foreach (InteractionSourceState state in states)
  242. {
  243. if (state.source.kind == InteractionSourceKind.Controller && state.source.handedness == handedness)
  244. {
  245. // Necessary to update Select Button State in Update Loop since it causes issues with PressDown and PressUp
  246. // Will be changed in a future iteration (probably VRTK 4)
  247. UpdateSelectButton(state);
  248. UpdateTouchpadTouch(state);
  249. }
  250. }
  251. }
  252. }
  253. protected virtual void InitController()
  254. {
  255. InteractionManager.InteractionSourceDetected += InteractionManager_InteractionSourceDetected;
  256. InteractionManager.InteractionSourceLost += InteractionManager_InteractionSourceLost;
  257. InteractionManager.InteractionSourceUpdated += InteractionManager_InteractionSourceUpdated;
  258. InteractionManager.InteractionSourcePressed += InteractionManager_InteractionSourcePressed;
  259. InteractionManager.InteractionSourceReleased += InteractionManager_InteractionSourceReleased;
  260. #if VRTK_DEFINE_WINDOWSMR_CONTROLLER_VISUALIZATION
  261. if (MotionControllerVisualizer.Instance != null)
  262. {
  263. MotionControllerVisualizer.Instance.OnControllerModelLoaded += AttachControllerModel;
  264. }
  265. #endif
  266. }
  267. protected virtual void SetupController(InteractionSource source)
  268. {
  269. index = source.id;
  270. currentButtonState = new ButtonState();
  271. prevButtonState = new ButtonState();
  272. isDetected = true;
  273. }
  274. #if VRTK_DEFINE_WINDOWSMR_CONTROLLER_VISUALIZATION
  275. protected virtual void AttachControllerModel(MotionControllerInfo controllerInfo)
  276. {
  277. if (controllerInfo.Handedness == Handedness)
  278. {
  279. Transform controllerTransform = controllerInfo.ControllerParent.transform;
  280. controllerTransform.SetParent(transform);
  281. controllerTransform.localPosition = Vector3.zero;
  282. controllerTransform.localRotation = Quaternion.identity;
  283. controllerTransform.localScale = Vector3.one;
  284. }
  285. }
  286. #endif
  287. protected virtual void InteractionManager_InteractionSourceDetected(InteractionSourceDetectedEventArgs args)
  288. {
  289. InteractionSourceState state = args.state;
  290. InteractionSource source = state.source;
  291. if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
  292. {
  293. SetupController(source);
  294. }
  295. }
  296. protected virtual void InteractionManager_InteractionSourceLost(InteractionSourceLostEventArgs args)
  297. {
  298. InteractionSourceState state = args.state;
  299. InteractionSource source = state.source;
  300. if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
  301. {
  302. index = uint.MaxValue;
  303. currentButtonState = new ButtonState();
  304. isDetected = false;
  305. }
  306. }
  307. protected virtual void InteractionManager_InteractionSourceUpdated(InteractionSourceUpdatedEventArgs args)
  308. {
  309. InteractionSourceState state = args.state;
  310. InteractionSource source = state.source;
  311. if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
  312. {
  313. if (!isDetected)
  314. {
  315. SetupController(source);
  316. }
  317. UpdateAxis(state);
  318. UpdatePose(state);
  319. }
  320. }
  321. protected virtual void InteractionManager_InteractionSourcePressed(InteractionSourcePressedEventArgs args)
  322. {
  323. InteractionSourceState state = args.state;
  324. InteractionSource source = state.source;
  325. if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
  326. {
  327. UpdateButtonState(args.pressType, state);
  328. }
  329. }
  330. protected virtual void InteractionManager_InteractionSourceReleased(InteractionSourceReleasedEventArgs args)
  331. {
  332. InteractionSourceState state = args.state;
  333. InteractionSource source = state.source;
  334. if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
  335. {
  336. UpdateButtonState(args.pressType, state);
  337. }
  338. }
  339. protected virtual void UpdatePose(InteractionSourceState state)
  340. {
  341. UpdateAngularVelocity(state.sourcePose);
  342. UpdateControllerPose(state.sourcePose);
  343. }
  344. // Workaround for Select Button
  345. // Issue: Pressed and Released event only recognize Select once and Select is pressed when selectPressedAmount==1,
  346. // so on press Select State is not always true and therefore not 'pressed'.
  347. // Updating SelectPressed in UpdateEvent of WSA.XR causes issues because the event and Unity Update are not synched
  348. // and therefore VRTK's polling of GetPressDown and GetPressUp might already been overwritten.
  349. protected virtual void UpdateSelectButton(InteractionSourceState state)
  350. {
  351. prevButtonState.SelectPressed = currentButtonState.SelectPressed;
  352. currentButtonState.SelectPressed = state.selectPressed;
  353. }
  354. protected virtual void UpdateTouchpadTouch(InteractionSourceState state)
  355. {
  356. if (state.source.supportsTouchpad)
  357. {
  358. prevButtonState.TouchpadTouched = currentButtonState.TouchpadTouched;
  359. currentButtonState.TouchpadTouched = state.touchpadTouched;
  360. }
  361. }
  362. protected virtual void UpdateButtonState(InteractionSourcePressType button, InteractionSourceState state)
  363. {
  364. switch (button)
  365. {
  366. case InteractionSourcePressType.Grasp:
  367. prevButtonState.Grasped = currentButtonState.Grasped;
  368. currentButtonState.Grasped = state.grasped;
  369. break;
  370. case InteractionSourcePressType.Menu:
  371. prevButtonState.MenuPressed = currentButtonState.MenuPressed;
  372. currentButtonState.MenuPressed = state.menuPressed;
  373. break;
  374. case InteractionSourcePressType.Touchpad:
  375. prevButtonState.TouchpadPressed = currentButtonState.TouchpadPressed;
  376. currentButtonState.TouchpadPressed = state.touchpadPressed;
  377. break;
  378. case InteractionSourcePressType.Thumbstick:
  379. prevButtonState.ThumbstickPressed = currentButtonState.ThumbstickPressed;
  380. currentButtonState.ThumbstickPressed = state.thumbstickPressed;
  381. break;
  382. }
  383. StartCoroutine(UpdateButtonStateAfterNextFrame(button));
  384. }
  385. protected virtual IEnumerator UpdateButtonStateAfterNextFrame(InteractionSourcePressType button)
  386. {
  387. yield return new WaitForEndOfFrame();
  388. switch (button)
  389. {
  390. case InteractionSourcePressType.Grasp:
  391. prevButtonState.Grasped = currentButtonState.Grasped;
  392. break;
  393. case InteractionSourcePressType.Menu:
  394. prevButtonState.MenuPressed = currentButtonState.MenuPressed;
  395. break;
  396. case InteractionSourcePressType.Touchpad:
  397. prevButtonState.TouchpadPressed = currentButtonState.TouchpadPressed;
  398. break;
  399. case InteractionSourcePressType.Thumbstick:
  400. prevButtonState.ThumbstickPressed = currentButtonState.ThumbstickPressed;
  401. break;
  402. }
  403. }
  404. protected virtual void UpdateControllerPose(InteractionSourcePose pose)
  405. {
  406. Quaternion newRotation;
  407. if (pose.TryGetRotation(out newRotation, InteractionSourceNode.Grip))
  408. {
  409. transform.localRotation = newRotation;
  410. }
  411. Vector3 newPosition;
  412. if (pose.TryGetPosition(out newPosition, InteractionSourceNode.Grip))
  413. {
  414. transform.localPosition = newPosition;
  415. }
  416. }
  417. protected virtual void UpdateAxis(InteractionSourceState state)
  418. {
  419. InteractionSource source = state.source;
  420. prevButtonState.SelectPressedAmount = currentButtonState.SelectPressedAmount;
  421. currentButtonState.SelectPressedAmount = state.selectPressedAmount;
  422. UpdateHairTrigger();
  423. if (source.supportsTouchpad)
  424. {
  425. currentButtonState.TouchpadPosition = state.touchpadPosition;
  426. }
  427. if (source.supportsThumbstick)
  428. {
  429. currentButtonState.ThumbstickPosition = state.thumbstickPosition;
  430. }
  431. }
  432. protected virtual void UpdateAngularVelocity(InteractionSourcePose pose)
  433. {
  434. Vector3 newAngularVelocity;
  435. if (pose.TryGetAngularVelocity(out newAngularVelocity))
  436. {
  437. angularVelocity = newAngularVelocity;
  438. }
  439. }
  440. protected virtual void UpdateHairTrigger()
  441. {
  442. hairTriggerPrevState = hairTriggerState;
  443. float value = currentButtonState.SelectPressedAmount;
  444. if (hairTriggerState)
  445. {
  446. if (value < hairTriggerLimit - hairTriggerDelta || value <= 0.0f)
  447. hairTriggerState = false;
  448. }
  449. else
  450. {
  451. if (value > hairTriggerLimit + hairTriggerDelta || value >= 1.0f)
  452. hairTriggerState = true;
  453. }
  454. hairTriggerLimit = hairTriggerState ? Mathf.Max(hairTriggerLimit, value) : Mathf.Min(hairTriggerLimit, value);
  455. }
  456. #endif
  457. }
  458. }