#if ENABLE_INPUT_SYSTEM using Assets.HurricaneVR.Framework.Shared.Utilities; using HurricaneVR.Framework.Shared; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.LowLevel; namespace HurricaneVR.Framework.ControllerInput.InputSystem { public class HVRTrackedPoseDriver : MonoBehaviour { public HVRHandSide Side; /// /// Options for which properties to update. /// /// public enum TrackingType { /// /// Update both rotation and position. /// RotationAndPosition, /// /// Update rotation only. /// RotationOnly, /// /// Update position only. /// PositionOnly, } [SerializeField] TrackingType m_TrackingType; /// /// The tracking type being used by the Tracked Pose Driver /// to control which properties to update. /// /// public TrackingType trackingType { get => m_TrackingType; set => m_TrackingType = value; } /// /// Options for which phases of the player loop will update properties. /// /// public enum UpdateType { /// /// Update after the Input System has completed an update and right before rendering. /// /// /// UpdateAndBeforeRender, /// /// Update after the Input System has completed an update. /// /// Update, /// /// Update right before rendering. /// /// BeforeRender, } [SerializeField] UpdateType m_UpdateType = UpdateType.UpdateAndBeforeRender; /// /// The update type being used by the Tracked Pose Driver /// to control which phases of the player loop will update properties. /// /// public UpdateType updateType { get => m_UpdateType; set => m_UpdateType = value; } [SerializeField] InputActionProperty m_PositionInput; /// /// The action to read the position value of a tracked device. /// Must support reading a value of type . /// public InputActionProperty positionInput { get => m_PositionInput; set { if (Application.isPlaying) UnbindPosition(); m_PositionInput = value; if (Application.isPlaying && isActiveAndEnabled) BindPosition(); } } [SerializeField] InputActionProperty m_RotationInput; /// /// The action to read the rotation value of a tracked device. /// Must support reading a value of type . /// public InputActionProperty rotationInput { get => m_RotationInput; set { if (Application.isPlaying) UnbindRotation(); m_RotationInput = value; if (Application.isPlaying && isActiveAndEnabled) BindRotation(); } } Vector3 m_CurrentPosition = Vector3.zero; Quaternion m_CurrentRotation = Quaternion.identity; bool m_RotationBound; bool m_PositionBound; void BindActions() { BindPosition(); BindRotation(); } void BindPosition() { if (m_PositionBound) return; var action = m_PositionInput.action; if (action == null || action.bindings.Count == 0) { if (Side == HVRHandSide.Left) action = HVRInputSystemController.InputActions.LeftHand.ControllerPosition; else action = HVRInputSystemController.InputActions.RightHand.ControllerPosition; } if (!action.enabled) action.Enable(); action.performed += OnPositionPerformed; action.canceled += OnPositionCanceled; m_PositionBound = true; _positionAction = action; } void BindRotation() { if (m_RotationBound) return; var action = m_RotationInput.action; if (action == null || action.bindings.Count == 0) { if (Side == HVRHandSide.Left) action = HVRInputSystemController.InputActions.LeftHand.ControllerRotation; else action = HVRInputSystemController.InputActions.RightHand.ControllerRotation; } if (!action.enabled) action.Enable(); action.performed += OnRotationPerformed; action.canceled += OnRotationCanceled; m_RotationBound = true; _rotationAction = action; } private InputAction _positionAction; private InputAction _rotationAction; void UnbindActions() { UnbindPosition(); UnbindRotation(); } void UnbindPosition() { if (!m_PositionBound) return; var action = _positionAction; if (action == null) return; if (m_PositionInput.action.bindings.Count > 0 && m_PositionInput.reference == null) action.Disable(); action.performed -= OnPositionPerformed; action.canceled -= OnPositionCanceled; m_PositionBound = false; _positionAction = null; } void UnbindRotation() { if (!m_RotationBound) return; var action = _rotationAction; if (action == null) return; if (m_RotationInput.action.bindings.Count > 0 && m_RotationInput.reference == null) action.Disable(); action.performed -= OnRotationPerformed; action.canceled -= OnRotationCanceled; m_RotationBound = false; _rotationAction = null; } void OnPositionPerformed(InputAction.CallbackContext context) { Debug.Assert(m_PositionBound, this); m_CurrentPosition = context.ReadValue(); } void OnPositionCanceled(InputAction.CallbackContext context) { Debug.Assert(m_PositionBound, this); m_CurrentPosition = Vector3.zero; } void OnRotationPerformed(InputAction.CallbackContext context) { Debug.Assert(m_RotationBound, this); m_CurrentRotation = context.ReadValue(); } void OnRotationCanceled(InputAction.CallbackContext context) { Debug.Assert(m_RotationBound, this); m_CurrentRotation = Quaternion.identity; } /// /// This function is called when the script instance is being loaded. /// protected virtual void Awake() { #if UNITY_INPUT_SYSTEM_ENABLE_VR && ENABLE_VR if (HasStereoCamera()) { UnityEngine.XR.XRDevice.DisableAutoXRCameraTracking(GetComponent(), true); } #endif } /// /// This function is called when the object becomes enabled and active. /// protected void OnEnable() { if (HVRInputManager.Instance.IsOpenXR) { UnityEngine.InputSystem.InputSystem.onAfterUpdate += UpdateCallback; HVRInputSystemController.Init(); this.ExecuteNextUpdate(BindActions); } } /// /// This function is called when the object becomes disabled or inactive. /// protected void OnDisable() { if (HVRInputManager.Instance.IsOpenXR) { UnbindActions(); UnityEngine.InputSystem.InputSystem.onAfterUpdate -= UpdateCallback; } } /// /// This function is called when the will be destroyed. /// protected virtual void OnDestroy() { #if UNITY_INPUT_SYSTEM_ENABLE_VR && ENABLE_VR if (HasStereoCamera()) { UnityEngine.XR.XRDevice.DisableAutoXRCameraTracking(GetComponent(), false); } #endif } protected void UpdateCallback() { if (InputState.currentUpdateType == InputUpdateType.BeforeRender) OnBeforeRender(); else OnUpdate(); } protected virtual void OnUpdate() { if (m_UpdateType == UpdateType.Update || m_UpdateType == UpdateType.UpdateAndBeforeRender) { PerformUpdate(); } } protected virtual void OnBeforeRender() { if (m_UpdateType == UpdateType.BeforeRender || m_UpdateType == UpdateType.UpdateAndBeforeRender) { PerformUpdate(); } } protected virtual void SetLocalTransform(Vector3 newPosition, Quaternion newRotation) { if (m_TrackingType == TrackingType.RotationAndPosition || m_TrackingType == TrackingType.RotationOnly) { transform.localRotation = newRotation; } if (m_TrackingType == TrackingType.RotationAndPosition || m_TrackingType == TrackingType.PositionOnly) { transform.localPosition = newPosition; } } bool HasStereoCamera() { var cameraComponent = GetComponent(); return cameraComponent != null && cameraComponent.stereoEnabled; } protected virtual void PerformUpdate() { SetLocalTransform(m_CurrentPosition, m_CurrentRotation); } } } #endif