SteamVR_Behaviour_Pose.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. using System;
  3. using System.Threading;
  4. using UnityEngine;
  5. using UnityEngine.Events;
  6. using Valve.VR;
  7. namespace Valve.VR
  8. {
  9. /// <summary>
  10. /// This component simplifies the use of Pose actions. Adding it to a gameobject will auto set that transform's position and rotation every update to match the pose.
  11. /// Advanced velocity estimation is handled through a buffer of the last 30 updates.
  12. /// </summary>
  13. public class SteamVR_Behaviour_Pose : MonoBehaviour
  14. {
  15. public SteamVR_Action_Pose poseAction = SteamVR_Input.GetAction<SteamVR_Action_Pose>("Pose");
  16. [Tooltip("The device this action should apply to. Any if the action is not device specific.")]
  17. public SteamVR_Input_Sources inputSource;
  18. [Tooltip("If not set, relative to parent")]
  19. public Transform origin;
  20. /// <summary>Returns whether or not the current pose is in a valid state</summary>
  21. public bool isValid { get { return poseAction[inputSource].poseIsValid; } }
  22. /// <summary>Returns whether or not the pose action is bound and able to be updated</summary>
  23. public bool isActive { get { return poseAction[inputSource].active; } }
  24. /// <summary>This Unity event will fire whenever the position or rotation of this transform is updated.</summary>
  25. public SteamVR_Behaviour_PoseEvent onTransformUpdated;
  26. /// <summary>This Unity event will fire whenever the position or rotation of this transform is changed.</summary>
  27. public SteamVR_Behaviour_PoseEvent onTransformChanged;
  28. /// <summary>This Unity event will fire whenever the device is connected or disconnected</summary>
  29. public SteamVR_Behaviour_Pose_ConnectedChangedEvent onConnectedChanged;
  30. /// <summary>This Unity event will fire whenever the device's tracking state changes</summary>
  31. public SteamVR_Behaviour_Pose_TrackingChangedEvent onTrackingChanged;
  32. /// <summary>This Unity event will fire whenever the device's deviceIndex changes</summary>
  33. public SteamVR_Behaviour_Pose_DeviceIndexChangedEvent onDeviceIndexChanged;
  34. /// <summary>This C# event will fire whenever the position or rotation of this transform is updated.</summary>
  35. public UpdateHandler onTransformUpdatedEvent;
  36. /// <summary>This C# event will fire whenever the position or rotation of this transform is changed.</summary>
  37. public ChangeHandler onTransformChangedEvent;
  38. /// <summary>This C# event will fire whenever the device is connected or disconnected</summary>
  39. public DeviceConnectedChangeHandler onConnectedChangedEvent;
  40. /// <summary>This C# event will fire whenever the device's tracking state changes</summary>
  41. public TrackingChangeHandler onTrackingChangedEvent;
  42. /// <summary>This C# event will fire whenever the device's deviceIndex changes</summary>
  43. public DeviceIndexChangedHandler onDeviceIndexChangedEvent;
  44. [Tooltip("Can be disabled to stop broadcasting bound device status changes")]
  45. public bool broadcastDeviceChanges = true;
  46. protected int deviceIndex = -1;
  47. protected SteamVR_HistoryBuffer historyBuffer = new SteamVR_HistoryBuffer(30);
  48. protected virtual void Start()
  49. {
  50. if (poseAction == null)
  51. {
  52. Debug.LogError("<b>[SteamVR]</b> No pose action set for this component", this);
  53. return;
  54. }
  55. CheckDeviceIndex();
  56. if (origin == null)
  57. origin = this.transform.parent;
  58. }
  59. protected virtual void OnEnable()
  60. {
  61. SteamVR.Initialize();
  62. if (poseAction != null)
  63. {
  64. poseAction[inputSource].onUpdate += SteamVR_Behaviour_Pose_OnUpdate;
  65. poseAction[inputSource].onDeviceConnectedChanged += OnDeviceConnectedChanged;
  66. poseAction[inputSource].onTrackingChanged += OnTrackingChanged;
  67. poseAction[inputSource].onChange += SteamVR_Behaviour_Pose_OnChange;
  68. }
  69. }
  70. protected virtual void OnDisable()
  71. {
  72. if (poseAction != null)
  73. {
  74. poseAction[inputSource].onUpdate -= SteamVR_Behaviour_Pose_OnUpdate;
  75. poseAction[inputSource].onDeviceConnectedChanged -= OnDeviceConnectedChanged;
  76. poseAction[inputSource].onTrackingChanged -= OnTrackingChanged;
  77. poseAction[inputSource].onChange -= SteamVR_Behaviour_Pose_OnChange;
  78. }
  79. historyBuffer.Clear();
  80. }
  81. private void SteamVR_Behaviour_Pose_OnUpdate(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource)
  82. {
  83. UpdateHistoryBuffer();
  84. UpdateTransform();
  85. if (onTransformUpdated != null)
  86. onTransformUpdated.Invoke(this, inputSource);
  87. if (onTransformUpdatedEvent != null)
  88. onTransformUpdatedEvent.Invoke(this, inputSource);
  89. }
  90. protected virtual void UpdateTransform()
  91. {
  92. CheckDeviceIndex();
  93. if (origin != null)
  94. {
  95. transform.position = origin.transform.TransformPoint(poseAction[inputSource].localPosition);
  96. transform.rotation = origin.rotation * poseAction[inputSource].localRotation;
  97. }
  98. else
  99. {
  100. transform.localPosition = poseAction[inputSource].localPosition;
  101. transform.localRotation = poseAction[inputSource].localRotation;
  102. }
  103. }
  104. private void SteamVR_Behaviour_Pose_OnChange(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource)
  105. {
  106. if (onTransformChanged != null)
  107. onTransformChanged.Invoke(this, fromSource);
  108. if (onTransformChangedEvent != null)
  109. onTransformChangedEvent.Invoke(this, fromSource);
  110. }
  111. protected virtual void OnDeviceConnectedChanged(SteamVR_Action_Pose changedAction, SteamVR_Input_Sources changedSource, bool connected)
  112. {
  113. CheckDeviceIndex();
  114. if (onConnectedChanged != null)
  115. onConnectedChanged.Invoke(this, inputSource, connected);
  116. if (onConnectedChangedEvent != null)
  117. onConnectedChangedEvent.Invoke(this, inputSource, connected);
  118. }
  119. protected virtual void OnTrackingChanged(SteamVR_Action_Pose changedAction, SteamVR_Input_Sources changedSource, ETrackingResult trackingChanged)
  120. {
  121. if (onTrackingChanged != null)
  122. onTrackingChanged.Invoke(this, inputSource, trackingChanged);
  123. if (onTrackingChangedEvent != null)
  124. onTrackingChangedEvent.Invoke(this, inputSource, trackingChanged);
  125. }
  126. protected virtual void CheckDeviceIndex()
  127. {
  128. if (poseAction[inputSource].active && poseAction[inputSource].deviceIsConnected)
  129. {
  130. int currentDeviceIndex = (int)poseAction[inputSource].trackedDeviceIndex;
  131. if (deviceIndex != currentDeviceIndex)
  132. {
  133. deviceIndex = currentDeviceIndex;
  134. if (broadcastDeviceChanges)
  135. {
  136. this.gameObject.BroadcastMessage("SetInputSource", inputSource, SendMessageOptions.DontRequireReceiver);
  137. this.gameObject.BroadcastMessage("SetDeviceIndex", deviceIndex, SendMessageOptions.DontRequireReceiver);
  138. }
  139. if (onDeviceIndexChanged != null)
  140. onDeviceIndexChanged.Invoke(this, inputSource, deviceIndex);
  141. if (onDeviceIndexChangedEvent != null)
  142. onDeviceIndexChangedEvent.Invoke(this, inputSource, deviceIndex);
  143. }
  144. }
  145. }
  146. /// <summary>
  147. /// Returns the device index for the device bound to the pose.
  148. /// </summary>
  149. public int GetDeviceIndex()
  150. {
  151. if (deviceIndex == -1)
  152. CheckDeviceIndex();
  153. return deviceIndex;
  154. }
  155. /// <summary>Returns the current velocity of the pose (as of the last update)</summary>
  156. public Vector3 GetVelocity()
  157. {
  158. return poseAction[inputSource].velocity;
  159. }
  160. /// <summary>Returns the current angular velocity of the pose (as of the last update)</summary>
  161. public Vector3 GetAngularVelocity()
  162. {
  163. return poseAction[inputSource].angularVelocity;
  164. }
  165. /// <summary>Returns the velocities of the pose at the time specified. Can predict in the future or return past values.</summary>
  166. public bool GetVelocitiesAtTimeOffset(float secondsFromNow, out Vector3 velocity, out Vector3 angularVelocity)
  167. {
  168. return poseAction[inputSource].GetVelocitiesAtTimeOffset(secondsFromNow, out velocity, out angularVelocity);
  169. }
  170. /// <summary>Uses previously recorded values to find the peak speed of the pose and returns the corresponding velocity and angular velocity</summary>
  171. public void GetEstimatedPeakVelocities(out Vector3 velocity, out Vector3 angularVelocity)
  172. {
  173. int top = historyBuffer.GetTopVelocity(10, 1);
  174. historyBuffer.GetAverageVelocities(out velocity, out angularVelocity, 2, top);
  175. }
  176. protected int lastFrameUpdated;
  177. protected void UpdateHistoryBuffer()
  178. {
  179. int currentFrame = Time.frameCount;
  180. if (lastFrameUpdated != currentFrame)
  181. {
  182. historyBuffer.Update(poseAction[inputSource].localPosition, poseAction[inputSource].localRotation, poseAction[inputSource].velocity, poseAction[inputSource].angularVelocity);
  183. lastFrameUpdated = currentFrame;
  184. }
  185. }
  186. /// <summary>
  187. /// Gets the localized name of the device that the action corresponds to.
  188. /// </summary>
  189. /// <param name="localizedParts">
  190. /// <list type="bullet">
  191. /// <item><description>VRInputString_Hand - Which hand the origin is in. E.g. "Left Hand"</description></item>
  192. /// <item><description>VRInputString_ControllerType - What kind of controller the user has in that hand.E.g. "Vive Controller"</description></item>
  193. /// <item><description>VRInputString_InputSource - What part of that controller is the origin. E.g. "Trackpad"</description></item>
  194. /// <item><description>VRInputString_All - All of the above. E.g. "Left Hand Vive Controller Trackpad"</description></item>
  195. /// </list>
  196. /// </param>
  197. public string GetLocalizedName(params EVRInputStringBits[] localizedParts)
  198. {
  199. if (poseAction != null)
  200. return poseAction.GetLocalizedOriginPart(inputSource, localizedParts);
  201. return null;
  202. }
  203. public delegate void ActiveChangeHandler(SteamVR_Behaviour_Pose fromAction, SteamVR_Input_Sources fromSource, bool active);
  204. public delegate void ChangeHandler(SteamVR_Behaviour_Pose fromAction, SteamVR_Input_Sources fromSource);
  205. public delegate void UpdateHandler(SteamVR_Behaviour_Pose fromAction, SteamVR_Input_Sources fromSource);
  206. public delegate void TrackingChangeHandler(SteamVR_Behaviour_Pose fromAction, SteamVR_Input_Sources fromSource, ETrackingResult trackingState);
  207. public delegate void ValidPoseChangeHandler(SteamVR_Behaviour_Pose fromAction, SteamVR_Input_Sources fromSource, bool validPose);
  208. public delegate void DeviceConnectedChangeHandler(SteamVR_Behaviour_Pose fromAction, SteamVR_Input_Sources fromSource, bool deviceConnected);
  209. public delegate void DeviceIndexChangedHandler(SteamVR_Behaviour_Pose fromAction, SteamVR_Input_Sources fromSource, int newDeviceIndex);
  210. }
  211. }