SteamVR_Action_Pose.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. using UnityEngine;
  3. using System.Collections;
  4. using System;
  5. using Valve.VR;
  6. using System.Runtime.InteropServices;
  7. using System.Collections.Generic;
  8. namespace Valve.VR
  9. {
  10. [Serializable]
  11. /// <summary>
  12. /// Pose actions represent a position, rotation, and velocities inside the tracked space.
  13. /// SteamVR keeps a log of past poses so you can retrieve old poses with GetPoseAtTimeOffset or GetVelocitiesAtTimeOffset.
  14. /// You can also pass in times in the future to these methods for SteamVR's best prediction of where the pose will be at that time.
  15. /// </summary>
  16. public class SteamVR_Action_Pose : SteamVR_Action_Pose_Base<SteamVR_Action_Pose_Source_Map<SteamVR_Action_Pose_Source>, SteamVR_Action_Pose_Source>, ISerializationCallbackReceiver
  17. {
  18. public delegate void ActiveChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource, bool active);
  19. public delegate void ChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource);
  20. public delegate void UpdateHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource);
  21. public delegate void TrackingChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource, ETrackingResult trackingState);
  22. public delegate void ValidPoseChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource, bool validPose);
  23. public delegate void DeviceConnectedChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource, bool deviceConnected);
  24. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> Event fires when the active state (ActionSet active and binding active) changes</summary>
  25. public event ActiveChangeHandler onActiveChange
  26. { add { sourceMap[SteamVR_Input_Sources.Any].onActiveChange += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onActiveChange -= value; } }
  27. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> Event fires when the active state of the binding changes</summary>
  28. public event ActiveChangeHandler onActiveBindingChange
  29. { add { sourceMap[SteamVR_Input_Sources.Any].onActiveBindingChange += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onActiveBindingChange -= value; } }
  30. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> Event fires when the orientation of the pose changes more than the changeTolerance</summary>
  31. public event ChangeHandler onChange
  32. { add { sourceMap[SteamVR_Input_Sources.Any].onChange += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onChange -= value; } }
  33. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> Event fires when the action is updated</summary>
  34. public event UpdateHandler onUpdate
  35. { add { sourceMap[SteamVR_Input_Sources.Any].onUpdate += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onUpdate -= value; } }
  36. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> Event fires when the state of the tracking has changed</summary>
  37. public event TrackingChangeHandler onTrackingChanged
  38. { add { sourceMap[SteamVR_Input_Sources.Any].onTrackingChanged += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onTrackingChanged -= value; } }
  39. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> Event fires when the validity of the pose has changed</summary>
  40. public event ValidPoseChangeHandler onValidPoseChanged
  41. { add { sourceMap[SteamVR_Input_Sources.Any].onValidPoseChanged += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onValidPoseChanged -= value; } }
  42. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> Event fires when the device bound to this pose is connected or disconnected</summary>
  43. public event DeviceConnectedChangeHandler onDeviceConnectedChanged
  44. { add { sourceMap[SteamVR_Input_Sources.Any].onDeviceConnectedChanged += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onDeviceConnectedChanged -= value; } }
  45. /// <summary>Fires an event when a device is connected or disconnected.</summary>
  46. /// <param name="inputSource">The device you would like to add an event to. Any if the action is not device specific.</param>
  47. /// <param name="functionToCall">The method you would like to be called when a device is connected. Should take a SteamVR_Action_Pose as a param</param>
  48. public void AddOnDeviceConnectedChanged(SteamVR_Input_Sources inputSource, DeviceConnectedChangeHandler functionToCall)
  49. {
  50. sourceMap[inputSource].onDeviceConnectedChanged += functionToCall;
  51. }
  52. /// <summary>Stops executing the function setup by the corresponding AddListener</summary>
  53. /// <param name="inputSource">The device you would like to remove an event from. Any if the action is not device specific.</param>
  54. /// <param name="functionToStopCalling">The method you would like to stop calling when a device is connected. Should take a SteamVR_Action_Pose as a param</param>
  55. public void RemoveOnDeviceConnectedChanged(SteamVR_Input_Sources inputSource, DeviceConnectedChangeHandler functionToStopCalling)
  56. {
  57. sourceMap[inputSource].onDeviceConnectedChanged -= functionToStopCalling;
  58. }
  59. /// <summary>Fires an event when the tracking of the device has changed</summary>
  60. /// <param name="inputSource">The device you would like to add an event to. Any if the action is not device specific.</param>
  61. /// <param name="functionToCall">The method you would like to be called when tracking has changed. Should take a SteamVR_Action_Pose as a param</param>
  62. public void AddOnTrackingChanged(SteamVR_Input_Sources inputSource, TrackingChangeHandler functionToCall)
  63. {
  64. sourceMap[inputSource].onTrackingChanged += functionToCall;
  65. }
  66. /// <summary>Stops executing the function setup by the corresponding AddListener</summary>
  67. /// <param name="inputSource">The device you would like to remove an event from. Any if the action is not device specific.</param>
  68. /// <param name="functionToStopCalling">The method you would like to stop calling when tracking has changed. Should take a SteamVR_Action_Pose as a param</param>
  69. public void RemoveOnTrackingChanged(SteamVR_Input_Sources inputSource, TrackingChangeHandler functionToStopCalling)
  70. {
  71. sourceMap[inputSource].onTrackingChanged -= functionToStopCalling;
  72. }
  73. /// <summary>Fires an event when the device now has a valid pose or no longer has a valid pose</summary>
  74. /// <param name="inputSource">The device you would like to add an event to. Any if the action is not device specific.</param>
  75. /// <param name="functionToCall">The method you would like to be called when the pose has become valid or invalid. Should take a SteamVR_Action_Pose as a param</param>
  76. public void AddOnValidPoseChanged(SteamVR_Input_Sources inputSource, ValidPoseChangeHandler functionToCall)
  77. {
  78. sourceMap[inputSource].onValidPoseChanged += functionToCall;
  79. }
  80. /// <summary>Stops executing the function setup by the corresponding AddListener</summary>
  81. /// <param name="inputSource">The device you would like to remove an event from. Any if the action is not device specific.</param>
  82. /// <param name="functionToStopCalling">The method you would like to stop calling when the pose has become valid or invalid. Should take a SteamVR_Action_Pose as a param</param>
  83. public void RemoveOnValidPoseChanged(SteamVR_Input_Sources inputSource, ValidPoseChangeHandler functionToStopCalling)
  84. {
  85. sourceMap[inputSource].onValidPoseChanged -= functionToStopCalling;
  86. }
  87. /// <summary>Executes a function when this action's bound state changes</summary>
  88. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  89. public void AddOnActiveChangeListener(SteamVR_Input_Sources inputSource, ActiveChangeHandler functionToCall)
  90. {
  91. sourceMap[inputSource].onActiveChange += functionToCall;
  92. }
  93. /// <summary>Stops executing the function setup by the corresponding AddListener</summary>
  94. /// <param name="functionToStopCalling">The local function that you've setup to receive update events</param>
  95. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  96. public void RemoveOnActiveChangeListener(SteamVR_Input_Sources inputSource, ActiveChangeHandler functionToStopCalling)
  97. {
  98. sourceMap[inputSource].onActiveChange -= functionToStopCalling;
  99. }
  100. /// <summary>Executes a function when the state of this action (with the specified inputSource) changes</summary>
  101. /// <param name="functionToCall">A local function that receives the boolean action who's state has changed, the corresponding input source, and the new value</param>
  102. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  103. public void AddOnChangeListener(SteamVR_Input_Sources inputSource, ChangeHandler functionToCall)
  104. {
  105. sourceMap[inputSource].onChange += functionToCall;
  106. }
  107. /// <summary>Stops executing the function setup by the corresponding AddListener</summary>
  108. /// <param name="functionToStopCalling">The local function that you've setup to receive on change events</param>
  109. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  110. public void RemoveOnChangeListener(SteamVR_Input_Sources inputSource, ChangeHandler functionToStopCalling)
  111. {
  112. sourceMap[inputSource].onChange -= functionToStopCalling;
  113. }
  114. /// <summary>Executes a function when the state of this action (with the specified inputSource) is updated.</summary>
  115. /// <param name="functionToCall">A local function that receives the boolean action who's state has changed, the corresponding input source, and the new value</param>
  116. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  117. public void AddOnUpdateListener(SteamVR_Input_Sources inputSource, UpdateHandler functionToCall)
  118. {
  119. sourceMap[inputSource].onUpdate += functionToCall;
  120. }
  121. /// <summary>Stops executing the function setup by the corresponding AddListener</summary>
  122. /// <param name="functionToStopCalling">The local function that you've setup to receive update events</param>
  123. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  124. public void RemoveOnUpdateListener(SteamVR_Input_Sources inputSource, UpdateHandler functionToStopCalling)
  125. {
  126. sourceMap[inputSource].onUpdate -= functionToStopCalling;
  127. }
  128. /// <summary>
  129. /// Removes all listeners, useful for dispose pattern
  130. /// </summary>
  131. public void RemoveAllListeners(SteamVR_Input_Sources input_Sources)
  132. {
  133. sourceMap[input_Sources].RemoveAllListeners();
  134. }
  135. void ISerializationCallbackReceiver.OnBeforeSerialize() { }
  136. void ISerializationCallbackReceiver.OnAfterDeserialize()
  137. {
  138. InitAfterDeserialize();
  139. }
  140. /// <summary>
  141. /// Sets all pose and skeleton actions to use the specified universe origin.
  142. /// </summary>
  143. public static void SetTrackingUniverseOrigin(ETrackingUniverseOrigin newOrigin)
  144. {
  145. SetUniverseOrigin(newOrigin);
  146. OpenVR.Compositor.SetTrackingSpace(newOrigin);
  147. }
  148. }
  149. [Serializable]
  150. /// <summary>
  151. /// The base pose action (pose and skeleton inherit from this)
  152. /// </summary>
  153. public abstract class SteamVR_Action_Pose_Base<SourceMap, SourceElement> : SteamVR_Action_In<SourceMap, SourceElement>, ISteamVR_Action_Pose
  154. where SourceMap : SteamVR_Action_Pose_Source_Map<SourceElement>, new()
  155. where SourceElement : SteamVR_Action_Pose_Source, new()
  156. {
  157. /// <summary>
  158. /// Sets all pose (and skeleton) actions to use the specified universe origin.
  159. /// </summary>
  160. protected static void SetUniverseOrigin(ETrackingUniverseOrigin newOrigin)
  161. {
  162. for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsPose.Length; actionIndex++)
  163. {
  164. SteamVR_Input.actionsPose[actionIndex].sourceMap.SetTrackingUniverseOrigin(newOrigin);
  165. }
  166. for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsSkeleton.Length; actionIndex++)
  167. {
  168. SteamVR_Input.actionsSkeleton[actionIndex].sourceMap.SetTrackingUniverseOrigin(newOrigin);
  169. }
  170. }
  171. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The local position of this action relative to the universe origin</summary>
  172. public Vector3 localPosition { get { return sourceMap[SteamVR_Input_Sources.Any].localPosition; } }
  173. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The local rotation of this action relative to the universe origin</summary>
  174. public Quaternion localRotation { get { return sourceMap[SteamVR_Input_Sources.Any].localRotation; } }
  175. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The state of the tracking system that is used to create pose data (position, rotation, etc)</summary>
  176. public ETrackingResult trackingState { get { return sourceMap[SteamVR_Input_Sources.Any].trackingState; } }
  177. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The local velocity of this pose relative to the universe origin</summary>
  178. public Vector3 velocity { get { return sourceMap[SteamVR_Input_Sources.Any].velocity; } }
  179. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The local angular velocity of this pose relative to the universe origin</summary>
  180. public Vector3 angularVelocity { get { return sourceMap[SteamVR_Input_Sources.Any].angularVelocity; } }
  181. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> True if the pose retrieved for this action and input source is valid (good data from the tracking source)</summary>
  182. public bool poseIsValid { get { return sourceMap[SteamVR_Input_Sources.Any].poseIsValid; } }
  183. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> True if the device bound to this action and input source is connected</summary>
  184. public bool deviceIsConnected { get { return sourceMap[SteamVR_Input_Sources.Any].deviceIsConnected; } }
  185. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The local position for this pose during the previous update</summary>
  186. public Vector3 lastLocalPosition { get { return sourceMap[SteamVR_Input_Sources.Any].lastLocalPosition; } }
  187. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The local rotation for this pose during the previous update</summary>
  188. public Quaternion lastLocalRotation { get { return sourceMap[SteamVR_Input_Sources.Any].lastLocalRotation; } }
  189. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The tracking state for this pose during the previous update</summary>
  190. public ETrackingResult lastTrackingState { get { return sourceMap[SteamVR_Input_Sources.Any].lastTrackingState; } }
  191. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The velocity for this pose during the previous update</summary>
  192. public Vector3 lastVelocity { get { return sourceMap[SteamVR_Input_Sources.Any].lastVelocity; } }
  193. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> The angular velocity for this pose during the previous update</summary>
  194. public Vector3 lastAngularVelocity { get { return sourceMap[SteamVR_Input_Sources.Any].lastAngularVelocity; } }
  195. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> True if the pose was valid during the previous update</summary>
  196. public bool lastPoseIsValid { get { return sourceMap[SteamVR_Input_Sources.Any].lastPoseIsValid; } }
  197. /// <summary><strong>[Shortcut to: SteamVR_Input_Sources.Any]</strong> True if the device bound to this action was connected during the previous update</summary>
  198. public bool lastDeviceIsConnected { get { return sourceMap[SteamVR_Input_Sources.Any].lastDeviceIsConnected; } }
  199. public SteamVR_Action_Pose_Base() { }
  200. /// <summary>
  201. /// <strong>[Should not be called by user code]</strong>
  202. /// Updates the data for all the input sources the system has detected need to be updated.
  203. /// </summary>
  204. public virtual void UpdateValues(bool skipStateAndEventUpdates)
  205. {
  206. sourceMap.UpdateValues(skipStateAndEventUpdates);
  207. }
  208. /// <summary>
  209. /// SteamVR keeps a log of past poses so you can retrieve old poses or estimated poses in the future by passing in a secondsFromNow value that is negative or positive.
  210. /// </summary>
  211. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  212. /// <param name="secondsFromNow">The time offset in the future (estimated) or in the past (previously recorded) you want to get data from</param>
  213. /// <returns>true if the call succeeded</returns>
  214. public bool GetVelocitiesAtTimeOffset(SteamVR_Input_Sources inputSource, float secondsFromNow, out Vector3 velocity, out Vector3 angularVelocity)
  215. {
  216. return sourceMap[inputSource].GetVelocitiesAtTimeOffset(secondsFromNow, out velocity, out angularVelocity);
  217. }
  218. /// <summary>
  219. /// SteamVR keeps a log of past poses so you can retrieve old poses or estimated poses in the future by passing in a secondsFromNow value that is negative or positive.
  220. /// </summary>
  221. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  222. /// <param name="secondsFromNow">The time offset in the future (estimated) or in the past (previously recorded) you want to get data from</param>
  223. /// <returns>true if the call succeeded</returns>
  224. public bool GetPoseAtTimeOffset(SteamVR_Input_Sources inputSource, float secondsFromNow, out Vector3 localPosition, out Quaternion localRotation, out Vector3 velocity, out Vector3 angularVelocity)
  225. {
  226. return sourceMap[inputSource].GetPoseAtTimeOffset(secondsFromNow, out localPosition, out localRotation, out velocity, out angularVelocity);
  227. }
  228. /// <summary>
  229. /// Update a transform's local position and local roation to match the pose from the most recent update
  230. /// </summary>
  231. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  232. /// <param name="transformToUpdate">The transform of the object to be updated</param>
  233. public virtual void UpdateTransform(SteamVR_Input_Sources inputSource, Transform transformToUpdate)
  234. {
  235. sourceMap[inputSource].UpdateTransform(transformToUpdate);
  236. }
  237. /// <summary>The local position of this action relative to the universe origin</summary>
  238. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  239. public Vector3 GetLocalPosition(SteamVR_Input_Sources inputSource)
  240. {
  241. return sourceMap[inputSource].localPosition;
  242. }
  243. /// <summary>The local rotation of this action relative to the universe origin</summary>
  244. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  245. public Quaternion GetLocalRotation(SteamVR_Input_Sources inputSource)
  246. {
  247. return sourceMap[inputSource].localRotation;
  248. }
  249. /// <summary>The local velocity of this pose relative to the universe origin</summary>
  250. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  251. public Vector3 GetVelocity(SteamVR_Input_Sources inputSource)
  252. {
  253. return sourceMap[inputSource].velocity;
  254. }
  255. /// <summary>The local angular velocity of this pose relative to the universe origin</summary>
  256. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  257. public Vector3 GetAngularVelocity(SteamVR_Input_Sources inputSource)
  258. {
  259. return sourceMap[inputSource].angularVelocity;
  260. }
  261. /// <summary>True if the device bound to this action and input source is connected</summary>
  262. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  263. public bool GetDeviceIsConnected(SteamVR_Input_Sources inputSource)
  264. {
  265. return sourceMap[inputSource].deviceIsConnected;
  266. }
  267. /// <summary>True if the pose retrieved for this action and input source is valid (good data from the tracking source)</summary>
  268. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  269. public bool GetPoseIsValid(SteamVR_Input_Sources inputSource)
  270. {
  271. return sourceMap[inputSource].poseIsValid;
  272. }
  273. /// <summary>The state of the tracking system that is used to create pose data (position, rotation, etc)</summary>
  274. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  275. public ETrackingResult GetTrackingResult(SteamVR_Input_Sources inputSource)
  276. {
  277. return sourceMap[inputSource].trackingState;
  278. }
  279. /// <summary>The local position for this pose during the previous update</summary>
  280. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  281. public Vector3 GetLastLocalPosition(SteamVR_Input_Sources inputSource)
  282. {
  283. return sourceMap[inputSource].lastLocalPosition;
  284. }
  285. /// <summary>The local rotation for this pose during the previous update</summary>
  286. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  287. public Quaternion GetLastLocalRotation(SteamVR_Input_Sources inputSource)
  288. {
  289. return sourceMap[inputSource].lastLocalRotation;
  290. }
  291. /// <summary>The velocity for this pose during the previous update</summary>
  292. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  293. public Vector3 GetLastVelocity(SteamVR_Input_Sources inputSource)
  294. {
  295. return sourceMap[inputSource].lastVelocity;
  296. }
  297. /// <summary>The angular velocity for this pose during the previous update</summary>
  298. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  299. public Vector3 GetLastAngularVelocity(SteamVR_Input_Sources inputSource)
  300. {
  301. return sourceMap[inputSource].lastAngularVelocity;
  302. }
  303. /// <summary>True if the device bound to this action was connected during the previous update</summary>
  304. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  305. public bool GetLastDeviceIsConnected(SteamVR_Input_Sources inputSource)
  306. {
  307. return sourceMap[inputSource].lastDeviceIsConnected;
  308. }
  309. /// <summary>True if the pose was valid during the previous update</summary>
  310. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  311. public bool GetLastPoseIsValid(SteamVR_Input_Sources inputSource)
  312. {
  313. return sourceMap[inputSource].lastPoseIsValid;
  314. }
  315. /// <summary>The tracking state for this pose during the previous update</summary>
  316. /// <param name="inputSource">The device you would like to get data from. Any if the action is not device specific.</param>
  317. public ETrackingResult GetLastTrackingResult(SteamVR_Input_Sources inputSource)
  318. {
  319. return sourceMap[inputSource].lastTrackingState;
  320. }
  321. }
  322. /// <summary>
  323. /// Boolean actions are either true or false. There is an onStateUp and onStateDown event for the rising and falling edge.
  324. /// </summary>
  325. public class SteamVR_Action_Pose_Source_Map<Source> : SteamVR_Action_In_Source_Map<Source>
  326. where Source : SteamVR_Action_Pose_Source, new()
  327. {
  328. /// <summary>
  329. /// Sets all pose (and skeleton) actions to use the specified universe origin without going through the sourcemap indexer
  330. /// </summary>
  331. public void SetTrackingUniverseOrigin(ETrackingUniverseOrigin newOrigin)
  332. {
  333. for (int sourceIndex = 0; sourceIndex < sources.Length; sourceIndex++)
  334. {
  335. if (sources[sourceIndex] != null)
  336. sources[sourceIndex].universeOrigin = newOrigin;
  337. }
  338. }
  339. public virtual void UpdateValues(bool skipStateAndEventUpdates)
  340. {
  341. for (int sourceIndex = 0; sourceIndex < updatingSources.Count; sourceIndex++)
  342. {
  343. sources[updatingSources[sourceIndex]].UpdateValue(skipStateAndEventUpdates);
  344. }
  345. }
  346. }
  347. public class SteamVR_Action_Pose_Source : SteamVR_Action_In_Source, ISteamVR_Action_Pose
  348. {
  349. public ETrackingUniverseOrigin universeOrigin = ETrackingUniverseOrigin.TrackingUniverseRawAndUncalibrated;
  350. protected static uint poseActionData_size = 0;
  351. /// <summary>The distance the pose needs to move/rotate before a change is detected</summary>
  352. public float changeTolerance = Mathf.Epsilon;
  353. /// <summary>Event fires when the active state (ActionSet active and binding active) changes</summary>
  354. public event SteamVR_Action_Pose.ActiveChangeHandler onActiveChange;
  355. /// <summary>Event fires when the active state of the binding changes</summary>
  356. public event SteamVR_Action_Pose.ActiveChangeHandler onActiveBindingChange;
  357. /// <summary>Event fires when the orientation of the pose changes more than the changeTolerance</summary>
  358. public event SteamVR_Action_Pose.ChangeHandler onChange;
  359. /// <summary>Event fires when the action is updated</summary>
  360. public event SteamVR_Action_Pose.UpdateHandler onUpdate;
  361. /// <summary>Event fires when the state of the tracking system that is used to create pose data (position, rotation, etc) changes</summary>
  362. public event SteamVR_Action_Pose.TrackingChangeHandler onTrackingChanged;
  363. /// <summary>Event fires when the state of the pose data retrieved for this action changes validity (good/bad data from the tracking source)</summary>
  364. public event SteamVR_Action_Pose.ValidPoseChangeHandler onValidPoseChanged;
  365. /// <summary>Event fires when the device bound to this action is connected or disconnected</summary>
  366. public event SteamVR_Action_Pose.DeviceConnectedChangeHandler onDeviceConnectedChanged;
  367. /// <summary>True when the orientation of the pose has changhed more than changeTolerance in the last update. Note: Will only return true if the action is also active.</summary>
  368. public override bool changed { get; protected set; }
  369. /// <summary>The value of the action's 'changed' during the previous update</summary>
  370. public override bool lastChanged { get; protected set; }
  371. /// <summary>The handle to the origin of the component that was used to update this pose</summary>
  372. public override ulong activeOrigin
  373. {
  374. get
  375. {
  376. if (active)
  377. return poseActionData.activeOrigin;
  378. return 0;
  379. }
  380. }
  381. /// <summary>The handle to the origin of the component that was used to update the value for this action (for the previous update)</summary>
  382. public override ulong lastActiveOrigin { get { return lastPoseActionData.activeOrigin; } }
  383. /// <summary>True if this action is bound and the ActionSet is active</summary>
  384. public override bool active { get { return activeBinding && action.actionSet.IsActive(inputSource); } }
  385. /// <summary>True if the action is bound</summary>
  386. public override bool activeBinding { get { return poseActionData.bActive; } }
  387. /// <summary>If the action was active (ActionSet active and binding active) during the last update</summary>
  388. public override bool lastActive { get; protected set; }
  389. /// <summary>If the action's binding was active during the previous update</summary>
  390. public override bool lastActiveBinding { get { return lastPoseActionData.bActive; } }
  391. /// <summary>The state of the tracking system that is used to create pose data (position, rotation, etc)</summary>
  392. public ETrackingResult trackingState { get { return poseActionData.pose.eTrackingResult; } }
  393. /// <summary>The tracking state for this pose during the previous update</summary>
  394. public ETrackingResult lastTrackingState { get { return lastPoseActionData.pose.eTrackingResult; } }
  395. /// <summary>True if the pose retrieved for this action and input source is valid (good data from the tracking source)</summary>
  396. public bool poseIsValid { get { return poseActionData.pose.bPoseIsValid; } }
  397. /// <summary>True if the pose was valid during the previous update</summary>
  398. public bool lastPoseIsValid { get { return lastPoseActionData.pose.bPoseIsValid; } }
  399. /// <summary>True if the device bound to this action and input source is connected</summary>
  400. public bool deviceIsConnected { get { return poseActionData.pose.bDeviceIsConnected; } }
  401. /// <summary>True if the device bound to this action was connected during the previous update</summary>
  402. public bool lastDeviceIsConnected { get { return lastPoseActionData.pose.bDeviceIsConnected; } }
  403. /// <summary>The local position of this action relative to the universe origin</summary>
  404. public Vector3 localPosition { get; protected set; }
  405. /// <summary>The local rotation of this action relative to the universe origin</summary>
  406. public Quaternion localRotation { get; protected set; }
  407. /// <summary>The local position for this pose during the previous update</summary>
  408. public Vector3 lastLocalPosition { get; protected set; }
  409. /// <summary>The local rotation for this pose during the previous update</summary>
  410. public Quaternion lastLocalRotation { get; protected set; }
  411. /// <summary>The local velocity of this pose relative to the universe origin</summary>
  412. public Vector3 velocity { get; protected set; }
  413. /// <summary>The velocity for this pose during the previous update</summary>
  414. public Vector3 lastVelocity { get; protected set; }
  415. /// <summary>The local angular velocity of this pose relative to the universe origin</summary>
  416. public Vector3 angularVelocity { get; protected set; }
  417. /// <summary>The angular velocity for this pose during the previous update</summary>
  418. public Vector3 lastAngularVelocity { get; protected set; }
  419. protected InputPoseActionData_t poseActionData = new InputPoseActionData_t();
  420. protected InputPoseActionData_t lastPoseActionData = new InputPoseActionData_t();
  421. protected InputPoseActionData_t tempPoseActionData = new InputPoseActionData_t();
  422. protected SteamVR_Action_Pose poseAction;
  423. /// <summary>
  424. /// <strong>[Should not be called by user code]</strong> Sets up the internals of the action source before SteamVR has been initialized.
  425. /// </summary>
  426. public override void Preinitialize(SteamVR_Action wrappingAction, SteamVR_Input_Sources forInputSource)
  427. {
  428. base.Preinitialize(wrappingAction, forInputSource);
  429. poseAction = wrappingAction as SteamVR_Action_Pose;
  430. }
  431. /// <summary>
  432. /// <strong>[Should not be called by user code]</strong>
  433. /// Initializes the handle for the inputSource, the pose action data size, and any other related SteamVR data.
  434. /// </summary>
  435. public override void Initialize()
  436. {
  437. base.Initialize();
  438. if (poseActionData_size == 0)
  439. poseActionData_size = (uint)Marshal.SizeOf(typeof(InputPoseActionData_t));
  440. }
  441. /// <summary>
  442. /// Removes all listeners, useful for dispose pattern
  443. /// </summary>
  444. public virtual void RemoveAllListeners()
  445. {
  446. Delegate[] delegates;
  447. if (onActiveChange != null)
  448. {
  449. delegates = onActiveChange.GetInvocationList();
  450. if (delegates != null)
  451. foreach (Delegate existingDelegate in delegates)
  452. onActiveChange -= (SteamVR_Action_Pose.ActiveChangeHandler)existingDelegate;
  453. }
  454. if (onChange != null)
  455. {
  456. delegates = onChange.GetInvocationList();
  457. if (delegates != null)
  458. foreach (Delegate existingDelegate in delegates)
  459. onChange -= (SteamVR_Action_Pose.ChangeHandler)existingDelegate;
  460. }
  461. if (onUpdate != null)
  462. {
  463. delegates = onUpdate.GetInvocationList();
  464. if (delegates != null)
  465. foreach (Delegate existingDelegate in delegates)
  466. onUpdate -= (SteamVR_Action_Pose.UpdateHandler)existingDelegate;
  467. }
  468. if (onTrackingChanged != null)
  469. {
  470. delegates = onTrackingChanged.GetInvocationList();
  471. if (delegates != null)
  472. foreach (Delegate existingDelegate in delegates)
  473. onTrackingChanged -= (SteamVR_Action_Pose.TrackingChangeHandler)existingDelegate;
  474. }
  475. if (onValidPoseChanged != null)
  476. {
  477. delegates = onValidPoseChanged.GetInvocationList();
  478. if (delegates != null)
  479. foreach (Delegate existingDelegate in delegates)
  480. onValidPoseChanged -= (SteamVR_Action_Pose.ValidPoseChangeHandler)existingDelegate;
  481. }
  482. if (onDeviceConnectedChanged != null)
  483. {
  484. delegates = onDeviceConnectedChanged.GetInvocationList();
  485. if (delegates != null)
  486. foreach (Delegate existingDelegate in delegates)
  487. onDeviceConnectedChanged -= (SteamVR_Action_Pose.DeviceConnectedChangeHandler)existingDelegate;
  488. }
  489. }
  490. /// <summary><strong>[Should not be called by user code]</strong>
  491. /// Updates the data for this action and this input source. Sends related events.
  492. /// </summary>
  493. public override void UpdateValue()
  494. {
  495. UpdateValue(false);
  496. }
  497. public static float framesAhead = 2;
  498. /// <summary><strong>[Should not be called by user code]</strong>
  499. /// Updates the data for this action and this input source. Sends related events.
  500. /// </summary>
  501. public virtual void UpdateValue(bool skipStateAndEventUpdates)
  502. {
  503. lastChanged = changed;
  504. lastPoseActionData = poseActionData;
  505. lastLocalPosition = localPosition;
  506. lastLocalRotation = localRotation;
  507. lastVelocity = velocity;
  508. lastAngularVelocity = angularVelocity;
  509. EVRInputError err;
  510. if (framesAhead == 0)
  511. err = OpenVR.Input.GetPoseActionDataForNextFrame(handle, universeOrigin, ref poseActionData, poseActionData_size, inputSourceHandle);
  512. else
  513. err = OpenVR.Input.GetPoseActionDataRelativeToNow(handle, universeOrigin, framesAhead * (Time.timeScale / SteamVR.instance.hmd_DisplayFrequency), ref poseActionData, poseActionData_size, inputSourceHandle);
  514. if (err != EVRInputError.None)
  515. {
  516. Debug.LogError("<b>[SteamVR]</b> GetPoseActionData error (" + fullPath + "): " + err.ToString() + " Handle: " + handle.ToString() + ". Input source: " + inputSource.ToString());
  517. }
  518. if (active)
  519. {
  520. SetCacheVariables();
  521. changed = GetChanged();
  522. }
  523. if (changed)
  524. changedTime = updateTime;
  525. if (skipStateAndEventUpdates == false)
  526. CheckAndSendEvents();
  527. }
  528. protected void SetCacheVariables()
  529. {
  530. localPosition = poseActionData.pose.mDeviceToAbsoluteTracking.GetPosition();
  531. localRotation = poseActionData.pose.mDeviceToAbsoluteTracking.GetRotation();
  532. velocity = GetUnityCoordinateVelocity(poseActionData.pose.vVelocity);
  533. angularVelocity = GetUnityCoordinateAngularVelocity(poseActionData.pose.vAngularVelocity);
  534. updateTime = Time.realtimeSinceStartup;
  535. }
  536. protected bool GetChanged()
  537. {
  538. if (Vector3.Distance(localPosition, lastLocalPosition) > changeTolerance)
  539. return true;
  540. else if (Mathf.Abs(Quaternion.Angle(localRotation, lastLocalRotation)) > changeTolerance)
  541. return true;
  542. else if (Vector3.Distance(velocity, lastVelocity) > changeTolerance)
  543. return true;
  544. else if (Vector3.Distance(angularVelocity, lastAngularVelocity) > changeTolerance)
  545. return true;
  546. return false;
  547. }
  548. /// <summary>
  549. /// SteamVR keeps a log of past poses so you can retrieve old poses or estimated poses in the future by passing in a secondsFromNow value that is negative or positive.
  550. /// </summary>
  551. /// <param name="secondsFromNow">The time offset in the future (estimated) or in the past (previously recorded) you want to get data from</param>
  552. /// <returns>true if we successfully returned a pose</returns>
  553. public bool GetVelocitiesAtTimeOffset(float secondsFromNow, out Vector3 velocityAtTime, out Vector3 angularVelocityAtTime)
  554. {
  555. EVRInputError err = OpenVR.Input.GetPoseActionDataRelativeToNow(handle, universeOrigin, secondsFromNow, ref tempPoseActionData, poseActionData_size, inputSourceHandle);
  556. if (err != EVRInputError.None)
  557. {
  558. Debug.LogError("<b>[SteamVR]</b> GetPoseActionData error (" + fullPath + "): " + err.ToString() + " handle: " + handle.ToString()); //todo: this should be an error
  559. velocityAtTime = Vector3.zero;
  560. angularVelocityAtTime = Vector3.zero;
  561. return false;
  562. }
  563. velocityAtTime = GetUnityCoordinateVelocity(tempPoseActionData.pose.vVelocity);
  564. angularVelocityAtTime = GetUnityCoordinateAngularVelocity(tempPoseActionData.pose.vAngularVelocity);
  565. return true;
  566. }
  567. /// <summary>
  568. /// SteamVR keeps a log of past poses so you can retrieve old poses or estimated poses in the future by passing in a secondsFromNow value that is negative or positive.
  569. /// </summary>
  570. /// <param name="secondsFromNow">The time offset in the future (estimated) or in the past (previously recorded) you want to get data from</param>
  571. /// <returns>true if we successfully returned a pose</returns>
  572. public bool GetPoseAtTimeOffset(float secondsFromNow, out Vector3 positionAtTime, out Quaternion rotationAtTime, out Vector3 velocityAtTime, out Vector3 angularVelocityAtTime)
  573. {
  574. EVRInputError err = OpenVR.Input.GetPoseActionDataRelativeToNow(handle, universeOrigin, secondsFromNow, ref tempPoseActionData, poseActionData_size, inputSourceHandle);
  575. if (err != EVRInputError.None)
  576. {
  577. Debug.LogError("<b>[SteamVR]</b> GetPoseActionData error (" + fullPath + "): " + err.ToString() + " handle: " + handle.ToString()); //todo: this should be an error
  578. velocityAtTime = Vector3.zero;
  579. angularVelocityAtTime = Vector3.zero;
  580. positionAtTime = Vector3.zero;
  581. rotationAtTime = Quaternion.identity;
  582. return false;
  583. }
  584. velocityAtTime = GetUnityCoordinateVelocity(tempPoseActionData.pose.vVelocity);
  585. angularVelocityAtTime = GetUnityCoordinateAngularVelocity(tempPoseActionData.pose.vAngularVelocity);
  586. positionAtTime = tempPoseActionData.pose.mDeviceToAbsoluteTracking.GetPosition();
  587. rotationAtTime = tempPoseActionData.pose.mDeviceToAbsoluteTracking.GetRotation();
  588. return true;
  589. }
  590. /// <summary>
  591. /// Update a transform's local position and local roation to match the pose.
  592. /// </summary>
  593. /// <param name="transformToUpdate">The transform of the object to be updated</param>
  594. public void UpdateTransform(Transform transformToUpdate)
  595. {
  596. transformToUpdate.localPosition = localPosition;
  597. transformToUpdate.localRotation = localRotation;
  598. }
  599. protected virtual void CheckAndSendEvents()
  600. {
  601. if (trackingState != lastTrackingState && onTrackingChanged != null)
  602. onTrackingChanged.Invoke(poseAction, inputSource, trackingState);
  603. if (poseIsValid != lastPoseIsValid && onValidPoseChanged != null)
  604. onValidPoseChanged.Invoke(poseAction, inputSource, poseIsValid);
  605. if (deviceIsConnected != lastDeviceIsConnected && onDeviceConnectedChanged != null)
  606. onDeviceConnectedChanged.Invoke(poseAction, inputSource, deviceIsConnected);
  607. if (changed && onChange != null)
  608. onChange.Invoke(poseAction, inputSource);
  609. if (active != lastActive && onActiveChange != null)
  610. onActiveChange.Invoke(poseAction, inputSource, active);
  611. if (activeBinding != lastActiveBinding && onActiveBindingChange != null)
  612. onActiveBindingChange.Invoke(poseAction, inputSource, activeBinding);
  613. if (onUpdate != null)
  614. onUpdate.Invoke(poseAction, inputSource);
  615. }
  616. protected Vector3 GetUnityCoordinateVelocity(HmdVector3_t vector)
  617. {
  618. return GetUnityCoordinateVelocity(vector.v0, vector.v1, vector.v2);
  619. }
  620. protected Vector3 GetUnityCoordinateAngularVelocity(HmdVector3_t vector)
  621. {
  622. return GetUnityCoordinateAngularVelocity(vector.v0, vector.v1, vector.v2);
  623. }
  624. protected Vector3 GetUnityCoordinateVelocity(float x, float y, float z)
  625. {
  626. Vector3 vector = new Vector3();
  627. vector.x = x;
  628. vector.y = y;
  629. vector.z = -z;
  630. return vector;
  631. }
  632. protected Vector3 GetUnityCoordinateAngularVelocity(float x, float y, float z)
  633. {
  634. Vector3 vector = new Vector3();
  635. vector.x = -x;
  636. vector.y = -y;
  637. vector.z = z;
  638. return vector;
  639. }
  640. }
  641. /// <summary>
  642. /// Boolean actions are either true or false. There is an onStateUp and onStateDown event for the rising and falling edge.
  643. /// </summary>
  644. public interface ISteamVR_Action_Pose : ISteamVR_Action_In_Source
  645. {
  646. /// <summary>The local position of this action relative to the universe origin</summary>
  647. Vector3 localPosition { get; }
  648. /// <summary>The local rotation of this action relative to the universe origin</summary>
  649. Quaternion localRotation { get; }
  650. /// <summary>The state of the tracking system that is used to create pose data (position, rotation, etc)</summary>
  651. ETrackingResult trackingState { get; }
  652. /// <summary>The local velocity of this pose relative to the universe origin</summary>
  653. Vector3 velocity { get; }
  654. /// <summary>The local angular velocity of this pose relative to the universe origin</summary>
  655. Vector3 angularVelocity { get; }
  656. /// <summary>True if the pose retrieved for this action and input source is valid (good data from the tracking source)</summary>
  657. bool poseIsValid { get; }
  658. /// <summary>True if the device bound to this action and input source is connected</summary>
  659. bool deviceIsConnected { get; }
  660. /// <summary>The local position for this pose during the previous update</summary>
  661. Vector3 lastLocalPosition { get; }
  662. /// <summary>The local rotation for this pose during the previous update</summary>
  663. Quaternion lastLocalRotation { get; }
  664. /// <summary>The tracking state for this pose during the previous update</summary>
  665. ETrackingResult lastTrackingState { get; }
  666. /// <summary>The velocity for this pose during the previous update</summary>
  667. Vector3 lastVelocity { get; }
  668. /// <summary>The angular velocity for this pose during the previous update</summary>
  669. Vector3 lastAngularVelocity { get; }
  670. /// <summary>True if the pose was valid during the previous update</summary>
  671. bool lastPoseIsValid { get; }
  672. /// <summary>True if the device bound to this action was connected during the previous update</summary>
  673. bool lastDeviceIsConnected { get; }
  674. }
  675. }