CurvedUIViveController.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace CurvedUI
  4. {
  5. /// <summary>
  6. /// Contains a bunch of events you can subscribe to and bools to ask for current state of the controller. Can also trigger haptic feedback if you ask nicely.
  7. /// </summary>
  8. public class CurvedUIViveController : MonoBehaviour
  9. {
  10. #if CURVEDUI_STEAMVR_LEGACY
  11. #region settings
  12. public int axisFidelity = 1;
  13. #endregion
  14. #region internal variables
  15. private uint controllerIndex;
  16. private Type controllerType = Type.UNDEFINED;
  17. private SteamVR_TrackedObject trackedController;
  18. private SteamVR_Controller.Device device;
  19. private Vector2 touchpadAxis = Vector2.zero;
  20. private Vector2 triggerAxis = Vector2.zero;
  21. private bool controllerVisible = true;
  22. private ushort hapticPulseStrength;
  23. private int hapticPulseCountdown;
  24. private ushort maxHapticVibration = 3999;
  25. private Vector3 oculusTouchPoitingOriginOffset = new Vector3(0, -0.0258f, -0.033f);
  26. private Vector3 oculusTouchPoitingRotationOffset = new Vector3(38, 0, 0);
  27. public enum Type
  28. {
  29. UNDEFINED = 0,
  30. VIVE = 1,
  31. OCULUS_TOUCH = 2,
  32. }
  33. #endregion
  34. #region EVENTS
  35. public event ViveInputEvent TriggerClicked;
  36. public event ViveInputEvent TriggerUnclicked;
  37. public event ViveInputEvent TriggerAxisChanged;
  38. public event ViveInputEvent ApplicationMenuClicked;
  39. public event ViveInputEvent ApplicationMenuUnclicked;
  40. public event ViveInputEvent GripClicked;
  41. public event ViveInputEvent GripUnclicked;
  42. public event ViveInputEvent TouchpadClicked;
  43. public event ViveInputEvent TouchpadUnclicked;
  44. public event ViveInputEvent TouchpadTouched;
  45. public event ViveInputEvent TouchpadUntouched;
  46. public event ViveInputEvent TouchpadAxisChanged;
  47. public event ViveEvent ModelLoaded;
  48. public virtual void OnTriggerClicked(ViveInputArgs e)
  49. {
  50. if (TriggerClicked != null)
  51. TriggerClicked(this, e);
  52. }
  53. public virtual void OnTriggerUnclicked(ViveInputArgs e)
  54. {
  55. if (TriggerUnclicked != null)
  56. TriggerUnclicked(this, e);
  57. }
  58. public virtual void OnTriggerAxisChanged(ViveInputArgs e)
  59. {
  60. if (TriggerAxisChanged != null)
  61. TriggerAxisChanged(this, e);
  62. }
  63. public virtual void OnApplicationMenuClicked(ViveInputArgs e)
  64. {
  65. if (ApplicationMenuClicked != null)
  66. ApplicationMenuClicked(this, e);
  67. }
  68. public virtual void OnApplicationMenuUnclicked(ViveInputArgs e)
  69. {
  70. if (ApplicationMenuUnclicked != null)
  71. ApplicationMenuUnclicked(this, e);
  72. }
  73. public virtual void OnGripClicked(ViveInputArgs e)
  74. {
  75. if (GripClicked != null)
  76. GripClicked(this, e);
  77. }
  78. public virtual void OnGripUnclicked(ViveInputArgs e)
  79. {
  80. if (GripUnclicked != null)
  81. GripUnclicked(this, e);
  82. }
  83. public virtual void OnTouchpadClicked(ViveInputArgs e)
  84. {
  85. if (TouchpadClicked != null)
  86. TouchpadClicked(this, e);
  87. }
  88. public virtual void OnTouchpadUnclicked(ViveInputArgs e)
  89. {
  90. if (TouchpadUnclicked != null)
  91. TouchpadUnclicked(this, e);
  92. }
  93. public virtual void OnTouchpadTouched(ViveInputArgs e)
  94. {
  95. if (TouchpadTouched != null)
  96. TouchpadTouched(this, e);
  97. }
  98. public virtual void OnTouchpadUntouched(ViveInputArgs e)
  99. {
  100. if (TouchpadUntouched != null)
  101. TouchpadUntouched(this, e);
  102. }
  103. public virtual void OnTouchpadAxisChanged(ViveInputArgs e)
  104. {
  105. if (TouchpadAxisChanged != null)
  106. TouchpadAxisChanged(this, e);
  107. }
  108. #endregion
  109. #region LIFECYCLE
  110. void Awake()
  111. {
  112. trackedController = GetComponent<SteamVR_TrackedObject>();
  113. SteamVR_Events.RenderModelLoaded.AddListener(SteamVRModelLoaded);
  114. }
  115. void Update()
  116. {
  117. controllerIndex = (uint)trackedController.index;
  118. //this device is not tracked right now - it has no device index - skip it.
  119. if (controllerIndex < 0 || controllerIndex >= Valve.VR.OpenVR.k_unMaxTrackedDeviceCount) return;
  120. device = SteamVR_Controller.Input((int)controllerIndex);
  121. //get axis inputfrom debice
  122. Vector2 currentTriggerAxis = device.GetAxis(Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger);
  123. Vector2 currentTouchpadAxis = device.GetAxis();
  124. //haptic feedback
  125. if (hapticPulseCountdown > 0)
  126. {
  127. device.TriggerHapticPulse(hapticPulseStrength);
  128. hapticPulseCountdown -= 1;
  129. }
  130. //check for changes in trigger press
  131. if (Vector2ShallowEquals(triggerAxis, currentTriggerAxis))
  132. {
  133. triggerAxisChanged = false;
  134. }
  135. else
  136. {
  137. OnTriggerAxisChanged(SetButtonEvent(ref triggerPressed, true, currentTriggerAxis.x));
  138. triggerAxisChanged = true;
  139. }
  140. //check for changes in finger pos on touchpad
  141. if (Vector2ShallowEquals(touchpadAxis, currentTouchpadAxis))
  142. {
  143. touchpadAxisChanged = false;
  144. }
  145. else
  146. {
  147. OnTouchpadAxisChanged(SetButtonEvent(ref touchpadTouched, true, 1f));
  148. touchpadAxisChanged = true;
  149. }
  150. touchpadAxis = new Vector2(currentTouchpadAxis.x, currentTouchpadAxis.y);
  151. triggerAxis = new Vector2(currentTriggerAxis.x, currentTriggerAxis.y);
  152. //Trigger
  153. if (device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger))
  154. {
  155. OnTriggerClicked(SetButtonEvent(ref triggerPressed, true, currentTriggerAxis.x));
  156. triggerDown = true;
  157. }
  158. else {
  159. triggerDown = false;
  160. }
  161. if (device.GetPressUp(SteamVR_Controller.ButtonMask.Trigger))
  162. {
  163. OnTriggerUnclicked(SetButtonEvent(ref triggerPressed, false, 0f));
  164. triggerUp = true;
  165. }
  166. else {
  167. triggerUp = false;
  168. }
  169. //ApplicationMenu
  170. if (device.GetPressDown(SteamVR_Controller.ButtonMask.ApplicationMenu))
  171. {
  172. OnApplicationMenuClicked(SetButtonEvent(ref applicationMenuPressed, true, 1f));
  173. }
  174. else if (device.GetPressUp(SteamVR_Controller.ButtonMask.ApplicationMenu))
  175. {
  176. OnApplicationMenuUnclicked(SetButtonEvent(ref applicationMenuPressed, false, 0f));
  177. }
  178. //Grip
  179. if (device.GetPressDown(SteamVR_Controller.ButtonMask.Grip))
  180. {
  181. OnGripClicked(SetButtonEvent(ref gripPressed, true, 1f));
  182. }
  183. else if (device.GetPressUp(SteamVR_Controller.ButtonMask.Grip))
  184. {
  185. OnGripUnclicked(SetButtonEvent(ref gripPressed, false, 0f));
  186. }
  187. //Touchpad Clicked
  188. if (device.GetPressDown(SteamVR_Controller.ButtonMask.Touchpad))
  189. {
  190. OnTouchpadClicked(SetButtonEvent(ref touchpadPressed, true, 1f));
  191. }
  192. else if (device.GetPressUp(SteamVR_Controller.ButtonMask.Touchpad))
  193. {
  194. OnTouchpadUnclicked(SetButtonEvent(ref touchpadPressed, false, 0f));
  195. }
  196. //Touchpad Touched
  197. if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Touchpad))
  198. {
  199. OnTouchpadTouched(SetButtonEvent(ref touchpadTouched, true, 1f));
  200. }
  201. else if (device.GetTouchUp(SteamVR_Controller.ButtonMask.Touchpad))
  202. {
  203. OnTouchpadUntouched(SetButtonEvent(ref touchpadTouched, false, 0f));
  204. }
  205. }
  206. #endregion
  207. #region PRIVATE
  208. /// <summary>
  209. /// Compare two vectors if there are about equal.
  210. /// </summary>
  211. bool Vector2ShallowEquals(Vector2 vectorA, Vector2 vectorB)
  212. {
  213. return (vectorA.x.ToString("F" + axisFidelity) == vectorB.x.ToString("F" + axisFidelity) &&
  214. vectorA.y.ToString("F" + axisFidelity) == vectorB.y.ToString("F" + axisFidelity));
  215. }
  216. void SteamVRModelLoaded(SteamVR_RenderModel model, bool loaded)
  217. {
  218. //find if the controller is touch or vive by the type of its trackpad
  219. Valve.VR.ETrackedPropertyError pError = new Valve.VR.ETrackedPropertyError();
  220. int axisprop = Valve.VR.OpenVR.System.GetInt32TrackedDeviceProperty((uint)trackedController.index, Valve.VR.ETrackedDeviceProperty.Prop_Axis0Type_Int32, ref pError);
  221. controllerType = axisprop == (int)Valve.VR.EVRControllerAxisType.k_eControllerAxis_Joystick ? Type.OCULUS_TOUCH : Type.VIVE;
  222. //call evenets
  223. if (ModelLoaded != null) ModelLoaded(this);
  224. }
  225. #endregion
  226. #region PUBLIC
  227. public void ToggleControllerVisible(bool on)
  228. {
  229. foreach (MeshRenderer renderer in this.GetComponentsInChildren<MeshRenderer>())
  230. {
  231. renderer.enabled = on;
  232. }
  233. foreach (SkinnedMeshRenderer renderer in this.GetComponentsInChildren<SkinnedMeshRenderer>())
  234. {
  235. renderer.enabled = on;
  236. }
  237. controllerVisible = on;
  238. }
  239. /// <summary>
  240. /// Triggers the haptic pulse.
  241. /// </summary>
  242. /// <param name="duration">Duration in frames.</param>
  243. /// <param name="strength">Strength of the pulse. 100 is barely noticable, 300-500 seems about right for most uses. </param>
  244. public void TriggerHapticPulse(int duration, ushort strength)
  245. {
  246. hapticPulseCountdown = duration;
  247. hapticPulseStrength = (strength <= maxHapticVibration ? strength : maxHapticVibration);
  248. }
  249. #endregion
  250. #region SETTERS AND GETTERS
  251. /// <summary>
  252. /// Is this controller a Vive Controller, Oculush Touch, or other?
  253. /// </summary>
  254. public Type ControllerType {
  255. get { return controllerType; }
  256. }
  257. /// <summary>
  258. /// Returns the pointing direction, based on controller type. Oculus touch controllers point in a slighlty different way than Vive controllers.
  259. /// </summary>
  260. public Vector3 PointingDirection {
  261. get { return controllerType == Type.OCULUS_TOUCH ? transform.localToWorldMatrix.MultiplyVector(Quaternion.Euler(oculusTouchPoitingRotationOffset) * Vector3.forward) : transform.forward; }
  262. }
  263. /// <summary>
  264. /// Returns the pointing origin, based on controller type. Oculus touch controllers point in a slighlty different way than Vive controllers.
  265. /// </summary>
  266. public Vector3 PointingOrigin {
  267. get { return transform.TransformPoint(controllerType == Type.OCULUS_TOUCH ? oculusTouchPoitingOriginOffset : Vector3.zero); }
  268. }
  269. /// <summary>
  270. /// Are the render components of the Controller enabled?
  271. /// </summary>
  272. /// <returns><c>true</c> if this instance is controller visible; otherwise, <c>false</c>.</returns>
  273. public bool IsControllerVisible() { return controllerVisible; }
  274. /// <summary>
  275. /// Has trigger been pressed down this frame?
  276. /// </summary>
  277. public bool IsTriggerDown { get { return triggerDown; } }
  278. bool triggerDown = false;
  279. /// <summary>
  280. /// Has trigger been released this frame?
  281. /// </summary>
  282. public bool IsTriggerUp { get { return triggerUp; } }
  283. bool triggerUp = false;
  284. /// <summary>
  285. /// Is trigger pressed during this frame?
  286. /// </summary>
  287. public bool IsTriggerPressed { get { return triggerAxis.x > 0.5f; } }
  288. bool triggerPressed = false;
  289. /// <summary>
  290. /// Has trigger axis (how hard trigger is pressed) changed this frame?
  291. /// </summary>
  292. public bool IsTriggerAxisChanged { get { return triggerAxisChanged; } }
  293. bool triggerAxisChanged = false;
  294. /// <summary>
  295. /// Has user's finger position changed on touchpad this grame?
  296. /// </summary>
  297. public bool IsTouchpadAxisChanged { get { return touchpadAxisChanged; } }
  298. bool touchpadAxisChanged = false;
  299. /// <summary>
  300. /// Is Application menu pressed right now?
  301. /// </summary>
  302. public bool IsApplicationMenuPressed { get { return applicationMenuPressed; } }
  303. bool applicationMenuPressed = false;
  304. /// <summary>
  305. /// Is touchpad pressed this frame?
  306. /// </summary>
  307. public bool IsTouchpadPressed { get { return touchpadPressed; } }
  308. bool touchpadPressed = false;
  309. /// <summary>
  310. /// Is user's finger resting on the touchpad?
  311. /// </summary>
  312. public bool IsTouchpadTouched { get { return touchpadTouched; } }
  313. bool touchpadTouched = false;
  314. /// <summary>
  315. /// Is user holding the grip button?
  316. /// </summary>
  317. public bool IsGripPressed { get { return gripPressed; } }
  318. bool gripPressed = false;
  319. /// <summary>
  320. /// FingerPosition on touchpad?
  321. /// </summary>
  322. public Vector2 TouchPadAxis { get { return touchpadAxis; } }
  323. #endregion
  324. ViveInputArgs SetButtonEvent(ref bool buttonBool, bool value, float buttonPressure)
  325. {
  326. buttonBool = value;
  327. ViveInputArgs e;
  328. e.controllerIndex = controllerIndex;
  329. e.buttonPressure = buttonPressure;
  330. e.touchpadAxis = device.GetAxis();
  331. return e;
  332. }
  333. #endif
  334. }
  335. public struct ViveInputArgs
  336. {
  337. public uint controllerIndex;
  338. public float buttonPressure;
  339. public Vector2 touchpadAxis;
  340. }
  341. public delegate void ViveInputEvent(object sender, ViveInputArgs e);
  342. public delegate void ViveEvent(object sender);
  343. }