//======= Copyright (c) Valve Corporation, All rights reserved. =============== using UnityEngine; using System.Collections; using System; using Valve.VR; using System.Runtime.InteropServices; using System.Collections.Generic; namespace Valve.VR { [Serializable] /// /// Pose actions represent a position, rotation, and velocities inside the tracked space. /// SteamVR keeps a log of past poses so you can retrieve old poses with GetPoseAtTimeOffset or GetVelocitiesAtTimeOffset. /// 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. /// public class SteamVR_Action_Pose : SteamVR_Action_Pose_Base, SteamVR_Action_Pose_Source>, ISerializationCallbackReceiver { public delegate void ActiveChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource, bool active); public delegate void ChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource); public delegate void UpdateHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource); public delegate void TrackingChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource, ETrackingResult trackingState); public delegate void ValidPoseChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource, bool validPose); public delegate void DeviceConnectedChangeHandler(SteamVR_Action_Pose fromAction, SteamVR_Input_Sources fromSource, bool deviceConnected); /// [Shortcut to: SteamVR_Input_Sources.Any] Event fires when the active state (ActionSet active and binding active) changes public event ActiveChangeHandler onActiveChange { add { sourceMap[SteamVR_Input_Sources.Any].onActiveChange += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onActiveChange -= value; } } /// [Shortcut to: SteamVR_Input_Sources.Any] Event fires when the active state of the binding changes public event ActiveChangeHandler onActiveBindingChange { add { sourceMap[SteamVR_Input_Sources.Any].onActiveBindingChange += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onActiveBindingChange -= value; } } /// [Shortcut to: SteamVR_Input_Sources.Any] Event fires when the orientation of the pose changes more than the changeTolerance public event ChangeHandler onChange { add { sourceMap[SteamVR_Input_Sources.Any].onChange += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onChange -= value; } } /// [Shortcut to: SteamVR_Input_Sources.Any] Event fires when the action is updated public event UpdateHandler onUpdate { add { sourceMap[SteamVR_Input_Sources.Any].onUpdate += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onUpdate -= value; } } /// [Shortcut to: SteamVR_Input_Sources.Any] Event fires when the state of the tracking has changed public event TrackingChangeHandler onTrackingChanged { add { sourceMap[SteamVR_Input_Sources.Any].onTrackingChanged += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onTrackingChanged -= value; } } /// [Shortcut to: SteamVR_Input_Sources.Any] Event fires when the validity of the pose has changed public event ValidPoseChangeHandler onValidPoseChanged { add { sourceMap[SteamVR_Input_Sources.Any].onValidPoseChanged += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onValidPoseChanged -= value; } } /// [Shortcut to: SteamVR_Input_Sources.Any] Event fires when the device bound to this pose is connected or disconnected public event DeviceConnectedChangeHandler onDeviceConnectedChanged { add { sourceMap[SteamVR_Input_Sources.Any].onDeviceConnectedChanged += value; } remove { sourceMap[SteamVR_Input_Sources.Any].onDeviceConnectedChanged -= value; } } /// Fires an event when a device is connected or disconnected. /// The device you would like to add an event to. Any if the action is not device specific. /// The method you would like to be called when a device is connected. Should take a SteamVR_Action_Pose as a param public void AddOnDeviceConnectedChanged(SteamVR_Input_Sources inputSource, DeviceConnectedChangeHandler functionToCall) { sourceMap[inputSource].onDeviceConnectedChanged += functionToCall; } /// Stops executing the function setup by the corresponding AddListener /// The device you would like to remove an event from. Any if the action is not device specific. /// The method you would like to stop calling when a device is connected. Should take a SteamVR_Action_Pose as a param public void RemoveOnDeviceConnectedChanged(SteamVR_Input_Sources inputSource, DeviceConnectedChangeHandler functionToStopCalling) { sourceMap[inputSource].onDeviceConnectedChanged -= functionToStopCalling; } /// Fires an event when the tracking of the device has changed /// The device you would like to add an event to. Any if the action is not device specific. /// The method you would like to be called when tracking has changed. Should take a SteamVR_Action_Pose as a param public void AddOnTrackingChanged(SteamVR_Input_Sources inputSource, TrackingChangeHandler functionToCall) { sourceMap[inputSource].onTrackingChanged += functionToCall; } /// Stops executing the function setup by the corresponding AddListener /// The device you would like to remove an event from. Any if the action is not device specific. /// The method you would like to stop calling when tracking has changed. Should take a SteamVR_Action_Pose as a param public void RemoveOnTrackingChanged(SteamVR_Input_Sources inputSource, TrackingChangeHandler functionToStopCalling) { sourceMap[inputSource].onTrackingChanged -= functionToStopCalling; } /// Fires an event when the device now has a valid pose or no longer has a valid pose /// The device you would like to add an event to. Any if the action is not device specific. /// 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 public void AddOnValidPoseChanged(SteamVR_Input_Sources inputSource, ValidPoseChangeHandler functionToCall) { sourceMap[inputSource].onValidPoseChanged += functionToCall; } /// Stops executing the function setup by the corresponding AddListener /// The device you would like to remove an event from. Any if the action is not device specific. /// 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 public void RemoveOnValidPoseChanged(SteamVR_Input_Sources inputSource, ValidPoseChangeHandler functionToStopCalling) { sourceMap[inputSource].onValidPoseChanged -= functionToStopCalling; } /// Executes a function when this action's bound state changes /// The device you would like to get data from. Any if the action is not device specific. public void AddOnActiveChangeListener(SteamVR_Input_Sources inputSource, ActiveChangeHandler functionToCall) { sourceMap[inputSource].onActiveChange += functionToCall; } /// Stops executing the function setup by the corresponding AddListener /// The local function that you've setup to receive update events /// The device you would like to get data from. Any if the action is not device specific. public void RemoveOnActiveChangeListener(SteamVR_Input_Sources inputSource, ActiveChangeHandler functionToStopCalling) { sourceMap[inputSource].onActiveChange -= functionToStopCalling; } /// Executes a function when the state of this action (with the specified inputSource) changes /// A local function that receives the boolean action who's state has changed, the corresponding input source, and the new value /// The device you would like to get data from. Any if the action is not device specific. public void AddOnChangeListener(SteamVR_Input_Sources inputSource, ChangeHandler functionToCall) { sourceMap[inputSource].onChange += functionToCall; } /// Stops executing the function setup by the corresponding AddListener /// The local function that you've setup to receive on change events /// The device you would like to get data from. Any if the action is not device specific. public void RemoveOnChangeListener(SteamVR_Input_Sources inputSource, ChangeHandler functionToStopCalling) { sourceMap[inputSource].onChange -= functionToStopCalling; } /// Executes a function when the state of this action (with the specified inputSource) is updated. /// A local function that receives the boolean action who's state has changed, the corresponding input source, and the new value /// The device you would like to get data from. Any if the action is not device specific. public void AddOnUpdateListener(SteamVR_Input_Sources inputSource, UpdateHandler functionToCall) { sourceMap[inputSource].onUpdate += functionToCall; } /// Stops executing the function setup by the corresponding AddListener /// The local function that you've setup to receive update events /// The device you would like to get data from. Any if the action is not device specific. public void RemoveOnUpdateListener(SteamVR_Input_Sources inputSource, UpdateHandler functionToStopCalling) { sourceMap[inputSource].onUpdate -= functionToStopCalling; } void ISerializationCallbackReceiver.OnBeforeSerialize() { } void ISerializationCallbackReceiver.OnAfterDeserialize() { InitAfterDeserialize(); } /// /// Sets all pose and skeleton actions to use the specified universe origin. /// public static void SetTrackingUniverseOrigin(ETrackingUniverseOrigin newOrigin) { SetUniverseOrigin(newOrigin); } } [Serializable] /// /// The base pose action (pose and skeleton inherit from this) /// public abstract class SteamVR_Action_Pose_Base : SteamVR_Action_In, ISteamVR_Action_Pose where SourceMap : SteamVR_Action_Pose_Source_Map, new() where SourceElement : SteamVR_Action_Pose_Source, new() { /// /// Sets all pose (and skeleton) actions to use the specified universe origin. /// protected static void SetUniverseOrigin(ETrackingUniverseOrigin newOrigin) { for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsPose.Length; actionIndex++) { SteamVR_Input.actionsPose[actionIndex].sourceMap.SetTrackingUniverseOrigin(newOrigin); } for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsSkeleton.Length; actionIndex++) { SteamVR_Input.actionsSkeleton[actionIndex].sourceMap.SetTrackingUniverseOrigin(newOrigin); } } /// [Shortcut to: SteamVR_Input_Sources.Any] The local position of this action relative to the universe origin public Vector3 localPosition { get { return sourceMap[SteamVR_Input_Sources.Any].localPosition; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The local rotation of this action relative to the universe origin public Quaternion localRotation { get { return sourceMap[SteamVR_Input_Sources.Any].localRotation; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The state of the tracking system that is used to create pose data (position, rotation, etc) public ETrackingResult trackingState { get { return sourceMap[SteamVR_Input_Sources.Any].trackingState; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The local velocity of this pose relative to the universe origin public Vector3 velocity { get { return sourceMap[SteamVR_Input_Sources.Any].velocity; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The local angular velocity of this pose relative to the universe origin public Vector3 angularVelocity { get { return sourceMap[SteamVR_Input_Sources.Any].angularVelocity; } } /// [Shortcut to: SteamVR_Input_Sources.Any] True if the pose retrieved for this action and input source is valid (good data from the tracking source) public bool poseIsValid { get { return sourceMap[SteamVR_Input_Sources.Any].poseIsValid; } } /// [Shortcut to: SteamVR_Input_Sources.Any] True if the device bound to this action and input source is connected public bool deviceIsConnected { get { return sourceMap[SteamVR_Input_Sources.Any].deviceIsConnected; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The local position for this pose during the previous update public Vector3 lastLocalPosition { get { return sourceMap[SteamVR_Input_Sources.Any].lastLocalPosition; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The local rotation for this pose during the previous update public Quaternion lastLocalRotation { get { return sourceMap[SteamVR_Input_Sources.Any].lastLocalRotation; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The tracking state for this pose during the previous update public ETrackingResult lastTrackingState { get { return sourceMap[SteamVR_Input_Sources.Any].lastTrackingState; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The velocity for this pose during the previous update public Vector3 lastVelocity { get { return sourceMap[SteamVR_Input_Sources.Any].lastVelocity; } } /// [Shortcut to: SteamVR_Input_Sources.Any] The angular velocity for this pose during the previous update public Vector3 lastAngularVelocity { get { return sourceMap[SteamVR_Input_Sources.Any].lastAngularVelocity; } } /// [Shortcut to: SteamVR_Input_Sources.Any] True if the pose was valid during the previous update public bool lastPoseIsValid { get { return sourceMap[SteamVR_Input_Sources.Any].lastPoseIsValid; } } /// [Shortcut to: SteamVR_Input_Sources.Any] True if the device bound to this action was connected during the previous update public bool lastDeviceIsConnected { get { return sourceMap[SteamVR_Input_Sources.Any].lastDeviceIsConnected; } } public SteamVR_Action_Pose_Base() { } /// /// [Should not be called by user code] /// Updates the data for all the input sources the system has detected need to be updated. /// public virtual void UpdateValues(bool skipStateAndEventUpdates) { sourceMap.UpdateValues(skipStateAndEventUpdates); } /// /// 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. /// /// The device you would like to get data from. Any if the action is not device specific. /// The time offset in the future (estimated) or in the past (previously recorded) you want to get data from /// true if the call succeeded public bool GetVelocitiesAtTimeOffset(SteamVR_Input_Sources inputSource, float secondsFromNow, out Vector3 velocity, out Vector3 angularVelocity) { return sourceMap[inputSource].GetVelocitiesAtTimeOffset(secondsFromNow, out velocity, out angularVelocity); } /// /// 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. /// /// The device you would like to get data from. Any if the action is not device specific. /// The time offset in the future (estimated) or in the past (previously recorded) you want to get data from /// true if the call succeeded public bool GetPoseAtTimeOffset(SteamVR_Input_Sources inputSource, float secondsFromNow, out Vector3 localPosition, out Quaternion localRotation, out Vector3 velocity, out Vector3 angularVelocity) { return sourceMap[inputSource].GetPoseAtTimeOffset(secondsFromNow, out localPosition, out localRotation, out velocity, out angularVelocity); } /// /// Update a transform's local position and local roation to match the pose from the most recent update /// /// The device you would like to get data from. Any if the action is not device specific. /// The transform of the object to be updated public virtual void UpdateTransform(SteamVR_Input_Sources inputSource, Transform transformToUpdate) { sourceMap[inputSource].UpdateTransform(transformToUpdate); } /// The local position of this action relative to the universe origin /// The device you would like to get data from. Any if the action is not device specific. public Vector3 GetLocalPosition(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].localPosition; } /// The local rotation of this action relative to the universe origin /// The device you would like to get data from. Any if the action is not device specific. public Quaternion GetLocalRotation(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].localRotation; } /// The local velocity of this pose relative to the universe origin /// The device you would like to get data from. Any if the action is not device specific. public Vector3 GetVelocity(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].velocity; } /// The local angular velocity of this pose relative to the universe origin /// The device you would like to get data from. Any if the action is not device specific. public Vector3 GetAngularVelocity(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].angularVelocity; } /// True if the device bound to this action and input source is connected /// The device you would like to get data from. Any if the action is not device specific. public bool GetDeviceIsConnected(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].deviceIsConnected; } /// True if the pose retrieved for this action and input source is valid (good data from the tracking source) /// The device you would like to get data from. Any if the action is not device specific. public bool GetPoseIsValid(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].poseIsValid; } /// The state of the tracking system that is used to create pose data (position, rotation, etc) /// The device you would like to get data from. Any if the action is not device specific. public ETrackingResult GetTrackingResult(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].trackingState; } /// The local position for this pose during the previous update /// The device you would like to get data from. Any if the action is not device specific. public Vector3 GetLastLocalPosition(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].lastLocalPosition; } /// The local rotation for this pose during the previous update /// The device you would like to get data from. Any if the action is not device specific. public Quaternion GetLastLocalRotation(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].lastLocalRotation; } /// The velocity for this pose during the previous update /// The device you would like to get data from. Any if the action is not device specific. public Vector3 GetLastVelocity(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].lastVelocity; } /// The angular velocity for this pose during the previous update /// The device you would like to get data from. Any if the action is not device specific. public Vector3 GetLastAngularVelocity(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].lastAngularVelocity; } /// True if the device bound to this action was connected during the previous update /// The device you would like to get data from. Any if the action is not device specific. public bool GetLastDeviceIsConnected(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].lastDeviceIsConnected; } /// True if the pose was valid during the previous update /// The device you would like to get data from. Any if the action is not device specific. public bool GetLastPoseIsValid(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].lastPoseIsValid; } /// The tracking state for this pose during the previous update /// The device you would like to get data from. Any if the action is not device specific. public ETrackingResult GetLastTrackingResult(SteamVR_Input_Sources inputSource) { return sourceMap[inputSource].lastTrackingState; } } /// /// Boolean actions are either true or false. There is an onStateUp and onStateDown event for the rising and falling edge. /// public class SteamVR_Action_Pose_Source_Map : SteamVR_Action_In_Source_Map where Source : SteamVR_Action_Pose_Source, new() { /// /// Sets all pose (and skeleton) actions to use the specified universe origin without going through the sourcemap indexer /// public void SetTrackingUniverseOrigin(ETrackingUniverseOrigin newOrigin) { var sourceEnumerator = sources.GetEnumerator(); while (sourceEnumerator.MoveNext()) { var sourceElement = sourceEnumerator.Current; sourceElement.Value.universeOrigin = newOrigin; } } public virtual void UpdateValues(bool skipStateAndEventUpdates) { for (int sourceIndex = 0; sourceIndex < updatingSources.Count; sourceIndex++) { sources[updatingSources[sourceIndex]].UpdateValue(skipStateAndEventUpdates); } } } public class SteamVR_Action_Pose_Source : SteamVR_Action_In_Source, ISteamVR_Action_Pose { public ETrackingUniverseOrigin universeOrigin = ETrackingUniverseOrigin.TrackingUniverseRawAndUncalibrated; protected static uint poseActionData_size = 0; /// The amount of time in the future (or past!) the input system will predict poses for. Default is one frame forward (at 90hz) to account for render time. public float predictedSecondsFromNow = 0.011f; /// The distance the pose needs to move/rotate before a change is detected public float changeTolerance = Mathf.Epsilon; /// Event fires when the active state (ActionSet active and binding active) changes public event SteamVR_Action_Pose.ActiveChangeHandler onActiveChange; /// Event fires when the active state of the binding changes public event SteamVR_Action_Pose.ActiveChangeHandler onActiveBindingChange; /// Event fires when the orientation of the pose changes more than the changeTolerance public event SteamVR_Action_Pose.ChangeHandler onChange; /// Event fires when the action is updated public event SteamVR_Action_Pose.UpdateHandler onUpdate; /// Event fires when the state of the tracking system that is used to create pose data (position, rotation, etc) changes public event SteamVR_Action_Pose.TrackingChangeHandler onTrackingChanged; /// Event fires when the state of the pose data retrieved for this action changes validity (good/bad data from the tracking source) public event SteamVR_Action_Pose.ValidPoseChangeHandler onValidPoseChanged; /// Event fires when the device bound to this action is connected or disconnected public event SteamVR_Action_Pose.DeviceConnectedChangeHandler onDeviceConnectedChanged; /// 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. public override bool changed { get; protected set; } /// The value of the action's 'changed' during the previous update public override bool lastChanged { get; protected set; } /// The handle to the origin of the component that was used to update this pose public override ulong activeOrigin { get { if (active) return poseActionData.activeOrigin; return 0; } } /// The handle to the origin of the component that was used to update the value for this action (for the previous update) public override ulong lastActiveOrigin { get { return lastPoseActionData.activeOrigin; } } /// True if this action is bound and the ActionSet is active public override bool active { get { return activeBinding && action.actionSet.IsActive(inputSource); } } /// True if the action is bound public override bool activeBinding { get { return poseActionData.bActive; } } /// If the action was active (ActionSet active and binding active) during the last update public override bool lastActive { get; protected set; } /// If the action's binding was active during the previous update public override bool lastActiveBinding { get { return lastPoseActionData.bActive; } } /// The state of the tracking system that is used to create pose data (position, rotation, etc) public ETrackingResult trackingState { get { return poseActionData.pose.eTrackingResult; } } /// The tracking state for this pose during the previous update public ETrackingResult lastTrackingState { get { return lastPoseActionData.pose.eTrackingResult; } } /// True if the pose retrieved for this action and input source is valid (good data from the tracking source) public bool poseIsValid { get { return poseActionData.pose.bPoseIsValid; } } /// True if the pose was valid during the previous update public bool lastPoseIsValid { get { return lastPoseActionData.pose.bPoseIsValid; } } /// True if the device bound to this action and input source is connected public bool deviceIsConnected { get { return poseActionData.pose.bDeviceIsConnected; } } /// True if the device bound to this action was connected during the previous update public bool lastDeviceIsConnected { get { return lastPoseActionData.pose.bDeviceIsConnected; } } /// The local position of this action relative to the universe origin public Vector3 localPosition { get; protected set; } /// The local rotation of this action relative to the universe origin public Quaternion localRotation { get; protected set; } /// The local position for this pose during the previous update public Vector3 lastLocalPosition { get; protected set; } /// The local rotation for this pose during the previous update public Quaternion lastLocalRotation { get; protected set; } /// The local velocity of this pose relative to the universe origin public Vector3 velocity { get; protected set; } /// The velocity for this pose during the previous update public Vector3 lastVelocity { get; protected set; } /// The local angular velocity of this pose relative to the universe origin public Vector3 angularVelocity { get; protected set; } /// The angular velocity for this pose during the previous update public Vector3 lastAngularVelocity { get; protected set; } protected InputPoseActionData_t poseActionData = new InputPoseActionData_t(); protected InputPoseActionData_t lastPoseActionData = new InputPoseActionData_t(); protected InputPoseActionData_t tempPoseActionData = new InputPoseActionData_t(); protected SteamVR_Action_Pose poseAction; /// /// [Should not be called by user code] Sets up the internals of the action source before SteamVR has been initialized. /// public override void Preinitialize(SteamVR_Action wrappingAction, SteamVR_Input_Sources forInputSource) { base.Preinitialize(wrappingAction, forInputSource); poseAction = wrappingAction as SteamVR_Action_Pose; } /// /// [Should not be called by user code] /// Initializes the handle for the inputSource, the pose action data size, and any other related SteamVR data. /// public override void Initialize() { base.Initialize(); if (poseActionData_size == 0) poseActionData_size = (uint)Marshal.SizeOf(typeof(InputPoseActionData_t)); } /// [Should not be called by user code] /// Updates the data for this action and this input source. Sends related events. /// public override void UpdateValue() { UpdateValue(false); } /// [Should not be called by user code] /// Updates the data for this action and this input source. Sends related events. /// public virtual void UpdateValue(bool skipStateAndEventUpdates) { lastChanged = changed; lastPoseActionData = poseActionData; lastLocalPosition = localPosition; lastLocalRotation = localRotation; lastVelocity = velocity; lastAngularVelocity = angularVelocity; EVRInputError err = OpenVR.Input.GetPoseActionData(handle, universeOrigin, predictedSecondsFromNow, ref poseActionData, poseActionData_size, inputSourceHandle); if (err != EVRInputError.None) { Debug.LogError("[SteamVR] GetPoseActionData error (" + fullPath + "): " + err.ToString() + " Handle: " + handle.ToString() + ". Input source: " + inputSource.ToString()); } SetCacheVariables(); changed = GetChanged(); if (changed) changedTime = updateTime + predictedSecondsFromNow; if (skipStateAndEventUpdates == false) CheckAndSendEvents(); } protected void SetCacheVariables() { localPosition = SteamVR_Utils.GetPosition(poseActionData.pose.mDeviceToAbsoluteTracking); localRotation = SteamVR_Utils.GetRotation(poseActionData.pose.mDeviceToAbsoluteTracking); velocity = GetUnityCoordinateVelocity(poseActionData.pose.vVelocity); angularVelocity = GetUnityCoordinateAngularVelocity(poseActionData.pose.vAngularVelocity); updateTime = Time.realtimeSinceStartup; } protected bool GetChanged() { if (Vector3.Distance(localPosition, lastLocalPosition) > changeTolerance) return true; else if (Mathf.Abs(Quaternion.Angle(localRotation, lastLocalRotation)) > changeTolerance) return true; else if (Vector3.Distance(velocity, lastVelocity) > changeTolerance) return true; else if (Vector3.Distance(angularVelocity, lastAngularVelocity) > changeTolerance) return true; return false; } /// /// 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. /// /// The time offset in the future (estimated) or in the past (previously recorded) you want to get data from /// true if we successfully returned a pose public bool GetVelocitiesAtTimeOffset(float secondsFromNow, out Vector3 velocityAtTime, out Vector3 angularVelocityAtTime) { EVRInputError err = OpenVR.Input.GetPoseActionData(handle, universeOrigin, secondsFromNow, ref tempPoseActionData, poseActionData_size, inputSourceHandle); if (err != EVRInputError.None) { Debug.LogError("[SteamVR] GetPoseActionData error (" + fullPath + "): " + err.ToString() + " handle: " + handle.ToString()); //todo: this should be an error velocityAtTime = Vector3.zero; angularVelocityAtTime = Vector3.zero; return false; } velocityAtTime = GetUnityCoordinateVelocity(tempPoseActionData.pose.vVelocity); angularVelocityAtTime = GetUnityCoordinateAngularVelocity(tempPoseActionData.pose.vAngularVelocity); return true; } /// /// 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. /// /// The time offset in the future (estimated) or in the past (previously recorded) you want to get data from /// true if we successfully returned a pose public bool GetPoseAtTimeOffset(float secondsFromNow, out Vector3 positionAtTime, out Quaternion rotationAtTime, out Vector3 velocityAtTime, out Vector3 angularVelocityAtTime) { EVRInputError err = OpenVR.Input.GetPoseActionData(handle, universeOrigin, secondsFromNow, ref tempPoseActionData, poseActionData_size, inputSourceHandle); if (err != EVRInputError.None) { Debug.LogError("[SteamVR] GetPoseActionData error (" + fullPath + "): " + err.ToString() + " handle: " + handle.ToString()); //todo: this should be an error velocityAtTime = Vector3.zero; angularVelocityAtTime = Vector3.zero; positionAtTime = Vector3.zero; rotationAtTime = Quaternion.identity; return false; } velocityAtTime = GetUnityCoordinateVelocity(tempPoseActionData.pose.vVelocity); angularVelocityAtTime = GetUnityCoordinateAngularVelocity(tempPoseActionData.pose.vAngularVelocity); positionAtTime = SteamVR_Utils.GetPosition(tempPoseActionData.pose.mDeviceToAbsoluteTracking); rotationAtTime = SteamVR_Utils.GetRotation(tempPoseActionData.pose.mDeviceToAbsoluteTracking); return true; } /// /// Update a transform's local position and local roation to match the pose. /// /// The transform of the object to be updated public void UpdateTransform(Transform transformToUpdate) { transformToUpdate.localPosition = localPosition; transformToUpdate.localRotation = localRotation; } protected virtual void CheckAndSendEvents() { if (trackingState != lastTrackingState && onTrackingChanged != null) onTrackingChanged.Invoke(poseAction, inputSource, trackingState); if (poseIsValid != lastPoseIsValid && onValidPoseChanged != null) onValidPoseChanged.Invoke(poseAction, inputSource, poseIsValid); if (deviceIsConnected != lastDeviceIsConnected && onDeviceConnectedChanged != null) onDeviceConnectedChanged.Invoke(poseAction, inputSource, deviceIsConnected); if (changed && onChange != null) onChange.Invoke(poseAction, inputSource); if (active != lastActive && onActiveChange != null) onActiveChange.Invoke(poseAction, inputSource, active); if (activeBinding != lastActiveBinding && onActiveBindingChange != null) onActiveBindingChange.Invoke(poseAction, inputSource, activeBinding); if (onUpdate != null) onUpdate.Invoke(poseAction, inputSource); } protected Vector3 GetUnityCoordinateVelocity(HmdVector3_t vector) { return GetUnityCoordinateVelocity(vector.v0, vector.v1, vector.v2); } protected Vector3 GetUnityCoordinateAngularVelocity(HmdVector3_t vector) { return GetUnityCoordinateAngularVelocity(vector.v0, vector.v1, vector.v2); } protected Vector3 GetUnityCoordinateVelocity(float x, float y, float z) { Vector3 vector = new Vector3(); vector.x = x; vector.y = y; vector.z = -z; return vector; } protected Vector3 GetUnityCoordinateAngularVelocity(float x, float y, float z) { Vector3 vector = new Vector3(); vector.x = -x; vector.y = -y; vector.z = z; return vector; } } /// /// Boolean actions are either true or false. There is an onStateUp and onStateDown event for the rising and falling edge. /// public interface ISteamVR_Action_Pose : ISteamVR_Action_In_Source { /// The local position of this action relative to the universe origin Vector3 localPosition { get; } /// The local rotation of this action relative to the universe origin Quaternion localRotation { get; } /// The state of the tracking system that is used to create pose data (position, rotation, etc) ETrackingResult trackingState { get; } /// The local velocity of this pose relative to the universe origin Vector3 velocity { get; } /// The local angular velocity of this pose relative to the universe origin Vector3 angularVelocity { get; } /// True if the pose retrieved for this action and input source is valid (good data from the tracking source) bool poseIsValid { get; } /// True if the device bound to this action and input source is connected bool deviceIsConnected { get; } /// The local position for this pose during the previous update Vector3 lastLocalPosition { get; } /// The local rotation for this pose during the previous update Quaternion lastLocalRotation { get; } /// The tracking state for this pose during the previous update ETrackingResult lastTrackingState { get; } /// The velocity for this pose during the previous update Vector3 lastVelocity { get; } /// The angular velocity for this pose during the previous update Vector3 lastAngularVelocity { get; } /// True if the pose was valid during the previous update bool lastPoseIsValid { get; } /// True if the device bound to this action was connected during the previous update bool lastDeviceIsConnected { get; } } }