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 && 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 && 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);
}
}
}