123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619 |
- using System;
- using System.Collections.Generic;
- using System.Runtime.CompilerServices;
- #if ENABLE_VR || ENABLE_AR
- using UnityEngine.XR;
- using UnityEngine.Experimental.XR.Interaction;
- #endif
- #if ENABLE_AR
- using UnityEngine.XR.Tango;
- #endif
- [assembly: InternalsVisibleTo("UnityEditor.SpatialTracking")]
- namespace UnityEngine.SpatialTracking
- {
- internal class TrackedPoseDriverDataDescription
- {
- internal struct PoseData
- {
- public List<string> PoseNames;
- public List<TrackedPoseDriver.TrackedPose> Poses;
- }
-
- internal static List<PoseData> DeviceData = new List<PoseData>
- {
- // Generic XR Device
- new PoseData
- {
- PoseNames = new List<string>
- {
- "Left Eye", "Right Eye", "Center Eye - HMD Reference", "Head", "Color Camera"
- },
- Poses = new List<TrackedPoseDriver.TrackedPose>
- {
- TrackedPoseDriver.TrackedPose.LeftEye,
- TrackedPoseDriver.TrackedPose.RightEye,
- TrackedPoseDriver.TrackedPose.Center,
- TrackedPoseDriver.TrackedPose.Head,
- TrackedPoseDriver.TrackedPose.ColorCamera
- }
- },
- // generic controller
- new PoseData
- {
- PoseNames = new List<string>
- {
- "Left Controller", "Right Controller"
- },
- Poses = new List<TrackedPoseDriver.TrackedPose>
- {
- TrackedPoseDriver.TrackedPose.LeftPose,
- TrackedPoseDriver.TrackedPose.RightPose
- }
- },
- // generic remote
- new PoseData
- {
- PoseNames = new List<string>
- {
- "Device Pose"
- },
- Poses = new List<TrackedPoseDriver.TrackedPose>
- {
- TrackedPoseDriver.TrackedPose.RemotePose,
- }
- },
- };
- }
- /// <summary>
- /// Bitflag enum which represents what data was set on an associated Pose struct
- /// </summary>
- [Flags]
- public enum PoseDataFlags
- {
- /// <summary>
- /// No data was actually set on the pose
- /// </summary>
- NoData = 0,
- /// <summary>
- /// If this flag is set, position data was updated on the associated pose struct
- /// </summary>
- Position = 1 << 0,
- /// <summary>
- /// If this flag is set, rotation data was updated on the associated pose struct
- /// </summary>
- Rotation = 1 << 1,
- }
- /// <summary>
- /// The PoseDataSource class acts as a container for the GetDatafromSource method call that should be used by PoseProviders wanting to query data for a particular pose.
- /// </summary>
- static public class PoseDataSource
- {
- #if ENABLE_AR || ENABLE_VR
- static internal List<XR.XRNodeState> nodeStates = new List<XR.XRNodeState>();
- static internal PoseDataFlags GetNodePoseData(XR.XRNode node, out Pose resultPose)
- {
- PoseDataFlags retData = PoseDataFlags.NoData;
- XR.InputTracking.GetNodeStates(nodeStates);
- foreach (XR.XRNodeState nodeState in nodeStates)
- {
- if (nodeState.nodeType == node)
- {
- if(nodeState.TryGetPosition(out resultPose.position))
- {
- retData |= PoseDataFlags.Position;
- }
- if (nodeState.TryGetRotation(out resultPose.rotation))
- {
- retData |= PoseDataFlags.Rotation;
- }
- return retData;
- }
- }
- resultPose = Pose.identity;
- return retData;
- }
- #endif
- /// <summary>The GetDatafromSource method is used to query data from the XRNode subsystem based on the provided pose source.</summary>
- /// <param name = "poseSource" > The pose source to request data for.</param>
- /// <param name = "resultPose" > The resulting pose data.</param>
- /// <returns>True, if the pose source is valid, otherwise false.</returns>
- static public bool TryGetDataFromSource(TrackedPoseDriver.TrackedPose poseSource, out Pose resultPose)
- {
- return GetDataFromSource(poseSource, out resultPose) == (PoseDataFlags.Position | PoseDataFlags.Rotation);
- }
-
- /// <summary>The GetDatafromSource method is used to query data from the XRNode subsystem based on the provided pose source.</summary>
- /// <param name = "poseSource" > The pose source to request data for.</param>
- /// <param name = "resultPose" > The resulting pose data. This function will return the Center Eye pose if the Color Camera pose is not available. </param>
- /// <returns>Retuns a bitflag which represents which data has been retrieved from the provided pose source</returns>
- static public PoseDataFlags GetDataFromSource(TrackedPoseDriver.TrackedPose poseSource, out Pose resultPose)
- {
- #if ENABLE_AR || ENABLE_VR
- switch (poseSource)
- {
- case TrackedPoseDriver.TrackedPose.RemotePose:
- {
- PoseDataFlags retFlags = GetNodePoseData(XR.XRNode.RightHand, out resultPose);
- if (retFlags == PoseDataFlags.NoData)
- return GetNodePoseData(XR.XRNode.LeftHand, out resultPose);
- return retFlags;
- }
- case TrackedPoseDriver.TrackedPose.LeftEye:
- {
- return GetNodePoseData(XR.XRNode.LeftEye, out resultPose);
- }
- case TrackedPoseDriver.TrackedPose.RightEye:
- {
- return GetNodePoseData(XR.XRNode.RightEye, out resultPose);
- }
- case TrackedPoseDriver.TrackedPose.Head:
- {
- return GetNodePoseData(XR.XRNode.Head, out resultPose);
- }
- case TrackedPoseDriver.TrackedPose.Center:
- {
- return GetNodePoseData(XR.XRNode.CenterEye, out resultPose);
- }
- case TrackedPoseDriver.TrackedPose.LeftPose:
- {
- return GetNodePoseData(XR.XRNode.LeftHand, out resultPose);
- }
- case TrackedPoseDriver.TrackedPose.RightPose:
- {
- return GetNodePoseData(XR.XRNode.RightHand, out resultPose);
- }
- case TrackedPoseDriver.TrackedPose.ColorCamera:
- {
- PoseDataFlags retFlags = TryGetTangoPose(out resultPose);
- if(retFlags == PoseDataFlags.NoData)
- {
- // We fall back to CenterEye because we can't currently extend the XRNode structure, nor are we ready to replace it.
- return GetNodePoseData(XR.XRNode.CenterEye, out resultPose);
- }
- return retFlags;
- }
- default:
- {
- Debug.LogWarningFormat("Unable to retrieve pose data for poseSource: {0}", poseSource.ToString());
- break;
- }
- }
- #endif
- resultPose = Pose.identity;
- return PoseDataFlags.NoData;
- }
-
- static PoseDataFlags TryGetTangoPose(out Pose pose)
- {
- #if ENABLE_AR
- PoseData poseOut;
- if (TangoInputTracking.TryGetPoseAtTime(out poseOut) && poseOut.statusCode == PoseStatus.Valid)
- {
- pose.position = poseOut.position;
- pose.rotation = poseOut.rotation;
- return PoseDataFlags.Position | PoseDataFlags.Rotation; ;
- }
- #endif
- pose = Pose.identity;
- return PoseDataFlags.NoData;
- }
- }
- // The DefaultExecutionOrder is needed because TrackedPoseDriver does some
- // of its work in regular Update and FixedUpdate calls, but this needs to
- // be done before regular user scripts have their own Update and
- // FixedUpdate calls, in order that they correctly get the values for this
- // frame and not the previous.
- // -32000 is the minimal possible execution order value; -30000 makes it
- // is unlikely users chose lower values for their scripts by accident, but
- // still makes it possible.
- /// <summary>
- /// 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.
- /// </summary>
- [DefaultExecutionOrder(-30000)]
- [Serializable]
- [AddComponentMenu("XR/Tracked Pose Driver")]
- [HelpURL("https://docs.unity3d.com/Packages/com.unity.xr.legacyinputhelpers@2.1/manual/index.html")]
- public class TrackedPoseDriver : MonoBehaviour
- {
- /// <summary>
- /// The device being tracked by the tracked pose driver
- /// </summary>
- public enum DeviceType
- {
- /// <summary>
- /// An XR Controller, use this value for controllers
- /// </summary>
- GenericXRDevice = 0,
- /// <summary>
- /// An Generic XR Devices, use this value for HMD and AR Mobile device tracking
- /// </summary>
- GenericXRController = 1,
- /// <summary>
- /// An XR Remote, use this value for mobile remotes
- /// </summary>
- GenericXRRemote = 2
- }
- /// <summary>
- /// The list of endpoints that users can track with the <see cref="TrackedPoseDriver"/>
- /// </summary>
- public enum TrackedPose
- {
- /// <summary>
- /// The left eye of a HMD style device
- /// </summary>
- LeftEye = 0,
- /// <summary>
- /// The right eye of a HMD style device
- /// </summary>
- RightEye = 1,
- /// <summary>
- /// The center eye of a HMD style device, this is usually the default for most HMDs
- /// </summary>
- Center = 2,
- /// <summary>
- /// The head eye of a HMD style device
- /// </summary>
- Head = 3,
- /// <summary>
- /// The left hand controller pose
- /// </summary>
- LeftPose = 4,
- /// <summary>
- /// The right hand controller pose
- /// </summary>
- RightPose = 5,
- /// <summary>
- /// The color camera of a mobile device
- /// </summary>
- ColorCamera = 6,
- /// <summary>
- /// No Longer Used
- /// </summary>
- DepthCameraDeprecated = 7,
- /// <summary>
- /// No Longer Used
- /// </summary>
- FisheyeCameraDeprected = 8,
- /// <summary>
- /// No Longer Used
- /// </summary>
- DeviceDeprecated = 9,
- /// <summary>
- /// The pose of a mobile remote
- /// </summary>
- RemotePose = 10,
- }
- [SerializeField]
- DeviceType m_Device;
- /// <summary>
- /// This is used to indicate which pose the TrackedPoseDriver is currently tracking.
- /// </summary>
- public DeviceType deviceType
- {
- get { return m_Device; }
- internal set { m_Device = value; }
- }
- [SerializeField]
- TrackedPose m_PoseSource = TrackedPoseDriver.TrackedPose.Center;
- /// <summary>
- /// The pose being tracked by the tracked pose driver
- /// </summary>
- public TrackedPose poseSource
- {
- get { return m_PoseSource; }
- internal set { m_PoseSource = value; }
- }
- /// <summary>
- /// This method is used to set the device / pose pair for the SpatialTracking.TrackedPoseDriver. setting an invalid combination of these values will return false.
- /// </summary>
- /// <param name="deviceType">The device type that we wish to track </param>
- /// <param name="pose">The pose source that we wish to track</param>
- /// <returns>true if the values provided are sensible, otherwise false</returns>
- public bool SetPoseSource(DeviceType deviceType, TrackedPose pose)
- {
- if ((int)deviceType < TrackedPoseDriverDataDescription.DeviceData.Count)
- {
- TrackedPoseDriverDataDescription.PoseData val = TrackedPoseDriverDataDescription.DeviceData[(int)deviceType];
- for (int i = 0; i < val.Poses.Count; ++i)
- {
- if (val.Poses[i] == pose)
- {
- this.deviceType = deviceType;
- poseSource = pose;
- return true;
- }
- }
- }
- return false;
- }
- #if ENABLE_VR || ENABLE_AR
- [SerializeField]
- BasePoseProvider m_PoseProviderComponent = null;
- /// <summary>
- /// Optional: This field holds the reference to the PoseProvider instance that, if set, will be used to override the behavior of
- /// the TrackedPoseDriver. When this field is empty, the TrackedPoseDriver will operate as per usual, with pose data being
- /// retrieved from the device or pose settings of the TrackedPoseDriver. When this field is set, the pose data will be
- /// provided by the attached PoseProvider. The device or pose fields will be hidden as they are no longer used to
- /// control the parent GameObject Transform.
- /// </summary>
- public BasePoseProvider poseProviderComponent
- {
- get { return m_PoseProviderComponent; }
- set
- {
- m_PoseProviderComponent = value;
- }
- }
- #endif
- PoseDataFlags GetPoseData(DeviceType device, TrackedPose poseSource, out Pose resultPose)
- {
- #if ENABLE_VR || ENABLE_AR
- if (m_PoseProviderComponent != null)
- {
- return m_PoseProviderComponent.GetPoseFromProvider(out resultPose);
- }
- #endif
- return PoseDataSource.GetDataFromSource(poseSource, out resultPose);
- }
- /// <summary>
- /// This enum is used to indicate which parts of the pose will be applied to the parent transform
- /// </summary>
- public enum TrackingType
- {
- /// <summary>
- /// With this setting, both the pose's rotation and position will be applied to the parent transform
- /// </summary>
- RotationAndPosition,
- /// <summary>
- /// With this setting, only the pose's rotation will be applied to the parent transform
- /// </summary>
- RotationOnly,
- /// <summary>
- /// With this setting, only the pose's position will be applied to the parent transform
- /// </summary>
- PositionOnly
- }
- [SerializeField]
- TrackingType m_TrackingType;
- /// <summary>
- /// The tracking type being used by the tracked pose driver
- /// </summary>
- public TrackingType trackingType
- {
- get { return m_TrackingType; }
- set { m_TrackingType = value; }
- }
- /// <summary>
- /// The update type being used by the tracked pose driver
- /// </summary>
- public enum UpdateType
- {
- /// <summary>
- /// Sample input at both update, and directly before rendering. For smooth head pose tracking,
- /// we recommend using this value as it will provide the lowest input latency for the device.
- /// This is the default value for the UpdateType option
- /// </summary>
- UpdateAndBeforeRender,
- /// <summary>
- /// Only sample input during the update phase of the frame.
- /// </summary>
- Update,
- /// <summary>
- /// Only sample input directly before rendering
- /// </summary>
- BeforeRender,
- }
- [SerializeField]
- UpdateType m_UpdateType = UpdateType.UpdateAndBeforeRender;
- /// <summary>
- /// The update type being used by the tracked pose driver
- /// </summary>
- public UpdateType updateType
- {
- get { return m_UpdateType; }
- set { m_UpdateType = value; }
- }
- [SerializeField]
- bool m_UseRelativeTransform = false;
- /// <summary>
- /// This is used to indicate whether the TrackedPoseDriver will use the object's original transform as its basis.
- /// </summary>
- public bool UseRelativeTransform
- {
- get { return m_UseRelativeTransform; }
- set { m_UseRelativeTransform = value; }
- }
- /// <summary>
- /// The origin pose is the offset applied to any tracking data. This is only used when in legacy compatibility mode.
- /// </summary>
- protected Pose m_OriginPose;
- /// <summary>
- /// originPose is an offset applied to any tracking data read from this object.
- /// Setting this value should be reserved for dealing with edge-cases, such as
- /// achieving parity between room-scale (floor centered) and stationary (head centered)
- /// tracking - without having to alter the transform hierarchy.
- /// For user locomotion and gameplay purposes you are usually better off just
- /// moving the parent transform of this object.
- /// </summary>
- public Pose originPose
- {
- get { return m_OriginPose; }
- set { m_OriginPose = value; }
- }
- private void CacheLocalPosition()
- {
- m_OriginPose.position = transform.localPosition;
- m_OriginPose.rotation = transform.localRotation;
- }
- private void ResetToCachedLocalPosition()
- {
- SetLocalTransform(m_OriginPose.position, m_OriginPose.rotation, PoseDataFlags.Position | PoseDataFlags.Rotation);
- }
- /// <inheritdoc />
- protected virtual void Awake()
- {
- CacheLocalPosition();
- #if UNITY_2019_3_OR_NEWER
- // deprecated functionality in 2020.1
- #else
- if (HasStereoCamera())
- {
- #if ENABLE_AR || ENABLE_VR
- XRDevice.DisableAutoXRCameraTracking(GetComponent<Camera>(), true);
- #endif
- }
- #endif
- }
- /// <inheritdoc />
- protected virtual void OnDestroy()
- {
- #if UNITY_2019_3_OR_NEWER
- // deprecated functionality in 2020.1
- #else
- if (HasStereoCamera())
- {
- #if ENABLE_AR || ENABLE_VR
- XRDevice.DisableAutoXRCameraTracking(GetComponent<Camera>(), false);
- #endif
- }
- #endif
- }
- /// <inheritdoc />
- protected virtual void OnEnable()
- {
- Application.onBeforeRender += OnBeforeRender;
- }
- /// <inheritdoc />
- protected virtual void OnDisable()
- {
- // remove delegate registration
- ResetToCachedLocalPosition();
- Application.onBeforeRender -= OnBeforeRender;
- }
- /// <inheritdoc />
- protected virtual void FixedUpdate()
- {
- if (m_UpdateType == UpdateType.Update ||
- m_UpdateType == UpdateType.UpdateAndBeforeRender)
- {
- PerformUpdate();
- }
- }
- /// <inheritdoc />
- protected virtual void Update()
- {
- if (m_UpdateType == UpdateType.Update ||
- m_UpdateType == UpdateType.UpdateAndBeforeRender)
- {
- PerformUpdate();
- }
- }
- /// <inheritdoc />
- protected virtual void OnBeforeRender()
- {
- if (m_UpdateType == UpdateType.BeforeRender ||
- m_UpdateType == UpdateType.UpdateAndBeforeRender)
- {
- PerformUpdate();
- }
- }
- /// <summary>
- /// Sets the transform that is being driven by the <see cref="TrackedPoseDriver"/>. will only correct set the rotation or position depending on the <see cref="PoseDataFlags"/>
- /// </summary>
- /// <param name="newPosition">The position to apply.</param>
- /// <param name="newRotation">The rotation to apply.</param>
- /// <param name="poseFlags">The flags indiciating which of the position/rotation values are provided by the calling code.</param>
- protected virtual void SetLocalTransform(Vector3 newPosition, Quaternion newRotation, PoseDataFlags poseFlags)
- {
- if ((m_TrackingType == TrackingType.RotationAndPosition ||
- m_TrackingType == TrackingType.RotationOnly) &&
- (poseFlags & PoseDataFlags.Rotation) > 0)
- {
- transform.localRotation = newRotation;
- }
- if ((m_TrackingType == TrackingType.RotationAndPosition ||
- m_TrackingType == TrackingType.PositionOnly) &&
- (poseFlags & PoseDataFlags.Position) > 0)
- {
- transform.localPosition = newPosition;
- }
- }
- /// <summary>
- /// This is only used when running in legacy mode, and will fake the behavior of the old implicit camera tracking. This will transform by the origin pose if necessary.
- /// </summary>
- /// <param name="pose">Pose to transform by the origin if in relative transform mode.</param>
- /// <returns>The pose, with the applied transform if in Relative Transform mode.</returns>
- protected Pose TransformPoseByOriginIfNeeded(Pose pose)
- {
- if (m_UseRelativeTransform)
- {
- return pose.GetTransformedBy(m_OriginPose);
- }
- else
- {
- return pose;
- }
- }
- private bool HasStereoCamera()
- {
- Camera camera = GetComponent<Camera>();
- return camera != null && camera.stereoEnabled;
- }
- /// <summary>
- /// PerformUpdate queries the data from the selected pose source, and then calls <see cref="SetLocalTransform"/> to apply the pose.
- /// </summary>
- protected virtual void PerformUpdate()
- {
- if (!enabled)
- return;
- Pose currentPose = new Pose();
- currentPose = Pose.identity;
- PoseDataFlags poseFlags = GetPoseData(m_Device, m_PoseSource, out currentPose);
- if(poseFlags != PoseDataFlags.NoData)
- {
- Pose localPose = TransformPoseByOriginIfNeeded(currentPose);
- SetLocalTransform(localPose.position, localPose.rotation, poseFlags);
- }
- }
- }
- }
|