using System; using UnityEngine.InputSystem.LowLevel; namespace UnityEngine.InputSystem.XR { /// /// The TrackedPoseDriver component applies the current Pose value of a tracked device to the transform of the GameObject. /// TrackedPoseDriver can track multiple types of devices including XR HMDs, controllers, and remotes. /// [Serializable] [AddComponentMenu("XR/Tracked Pose Driver (New Input System)")] public class TrackedPoseDriver : MonoBehaviour { public enum TrackingType { RotationAndPosition, RotationOnly, PositionOnly } [SerializeField] TrackingType m_TrackingType; /// /// The tracking type being used by the tracked pose driver /// public TrackingType trackingType { get { return m_TrackingType; } set { m_TrackingType = value; } } public enum UpdateType { UpdateAndBeforeRender, Update, BeforeRender, } [SerializeField] UpdateType m_UpdateType = UpdateType.UpdateAndBeforeRender; /// /// The update type being used by the tracked pose driver /// public UpdateType updateType { get { return m_UpdateType; } set { m_UpdateType = value; } } [SerializeField] InputAction m_PositionAction; public InputAction positionAction { get { return m_PositionAction; } set { UnbindPosition(); m_PositionAction = value; BindActions(); } } [SerializeField] InputAction m_RotationAction; public InputAction rotationAction { get { return m_RotationAction; } set { UnbindRotation(); m_RotationAction = value; BindActions(); } } Vector3 m_CurrentPosition = Vector3.zero; Quaternion m_CurrentRotation = Quaternion.identity; bool m_RotationBound = false; bool m_PositionBound = false; void BindActions() { BindPosition(); BindRotation(); } void BindPosition() { if (!m_PositionBound && m_PositionAction != null) { m_PositionAction.Rename($"{gameObject.name} - TPD - Position"); m_PositionAction.performed += OnPositionUpdate; m_PositionBound = true; m_PositionAction.Enable(); } } void BindRotation() { if (!m_RotationBound && m_RotationAction != null) { m_RotationAction.Rename($"{gameObject.name} - TPD - Rotation"); m_RotationAction.performed += OnRotationUpdate; m_RotationBound = true; m_RotationAction.Enable(); } } void UnbindActions() { UnbindPosition(); UnbindRotation(); } void UnbindPosition() { if (m_PositionAction != null && m_PositionBound) { m_PositionAction.Disable(); m_PositionAction.performed -= OnPositionUpdate; m_PositionBound = false; } } void UnbindRotation() { if (m_RotationAction != null && m_RotationBound) { m_RotationAction.Disable(); m_RotationAction.performed -= OnRotationUpdate; m_RotationBound = false; } } void OnPositionUpdate(InputAction.CallbackContext context) { Debug.Assert(m_PositionBound); m_CurrentPosition = context.ReadValue(); } void OnRotationUpdate(InputAction.CallbackContext context) { Debug.Assert(m_RotationBound); m_CurrentRotation = context.ReadValue(); } protected virtual void Awake() { #if UNITY_INPUT_SYSTEM_ENABLE_VR if (HasStereoCamera()) { UnityEngine.XR.XRDevice.DisableAutoXRCameraTracking(GetComponent(), true); } #endif } protected void OnEnable() { InputSystem.onAfterUpdate += UpdateCallback; BindActions(); } void OnDisable() { UnbindActions(); InputSystem.onAfterUpdate -= UpdateCallback; } protected virtual void OnDestroy() { #if UNITY_INPUT_SYSTEM_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; } } private bool HasStereoCamera() { var camera = GetComponent(); return camera != null && camera.stereoEnabled; } protected virtual void PerformUpdate() { SetLocalTransform(m_CurrentPosition, m_CurrentRotation); } } }