Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Question How do I get the floor level from a quest headset to use as a camera y offset for the XRorigin?

Discussion in 'VR' started by unity_BB69C5BE5C71C96019D1, May 12, 2024.

  1. unity_BB69C5BE5C71C96019D1

    unity_BB69C5BE5C71C96019D1

    Joined:
    Apr 11, 2024
    Posts:
    4
    How do I get the floor level from a quest headset to use as a camera y offset for the XRorigin?
    If you don't know what the XRorigin is here's the script

    Code (CSharp):
    1. // ENABLE_VR is not defined on Game Core but the assembly is available with limited features when the XR module is enabled.
    2. #if ENABLE_VR || UNITY_GAMECORE
    3. #define XR_MODULE_AVAILABLE
    4. #endif
    5.  
    6. using System;
    7. using System.Collections;
    8. using System.Collections.Generic;
    9. using UnityEngine;
    10. using UnityEngine.Assertions;
    11. using UnityEngine.Serialization;
    12. using UnityEngine.XR;
    13.  
    14. namespace Unity.XR.CoreUtils
    15. {
    16.     /// <summary>
    17.     /// The XR Origin represents the session-space origin (0, 0, 0) in an XR scene.
    18.     /// </summary>
    19.     /// <remarks>
    20.     /// The XR Origin component is typically attached to the base object of the XR Origin,
    21.     /// and stores the <see cref="GameObject"/> that will be manipulated via locomotion.
    22.     /// It is also used for offsetting the camera.
    23.     /// </remarks>
    24.     [AddComponentMenu("XR/XR Origin")]
    25.     [DisallowMultipleComponent]
    26.     [HelpURL("https://docs.unity3d.com/Packages/com.unity.xr.core-utils@2.0/api/Unity.XR.CoreUtils.XROrigin.html")]
    27.     public class XROrigin : MonoBehaviour
    28.     {
    29.         [SerializeField]
    30.         [Tooltip("The Camera to associate with the XR device.")]
    31.         Camera m_Camera;
    32.  
    33.         /// <summary>
    34.         /// The <see cref="Camera"/> used to render the scene from the point of view of the XR device. Must be a child of
    35.         /// the <see cref="GameObject"/> containing this <c>XROrigin</c> component.
    36.         /// </summary>
    37.         /// <remarks>
    38.         /// You can add a <see cref="UnityEngine.InputSystem.XR.TrackedPoseDriver"/> component to the <see cref="Camera"/>
    39.         /// GameObject to update its position and rotation using tracking data from the XR device.
    40.         /// You must update the <see cref="Camera"/> position and rotation using tracking data from the XR device.
    41.         /// </remarks>
    42.         public Camera Camera
    43.         {
    44.             get => m_Camera;
    45.             set => m_Camera = value;
    46.         }
    47.  
    48.         /// <summary>
    49.         /// The parent <c>Transform</c> for all "trackables" (for example, planes and feature points).
    50.         /// </summary>
    51.         /// <remarks>
    52.         /// See [Trackables](xref:arfoundation-managers) for more information.
    53.         /// </remarks>
    54.         public Transform TrackablesParent { get; private set; }
    55.  
    56.         /// <summary>
    57.         /// Invoked during
    58.         /// [Application.onBeforeRender](xref:UnityEngine.Application.onBeforeRender(UnityEngine.Events.UnityAction))
    59.         /// whenever the <see cref="TrackablesParent"/> [transform](xref:UnityEngine.Transform) changes.
    60.         /// </summary>
    61.         public event Action<ARTrackablesParentTransformChangedEventArgs> TrackablesParentTransformChanged;
    62.  
    63.         /// <summary>
    64.         /// Sets which Tracking Origin Mode to use when initializing the input device.
    65.         /// </summary>
    66.         /// <seealso cref="RequestedTrackingOriginMode"/>
    67.         /// <seealso cref="TrackingOriginModeFlags"/>
    68.         /// <seealso cref="XRInputSubsystem.TrySetTrackingOriginMode"/>
    69.         public enum TrackingOriginMode
    70.         {
    71.             /// <summary>
    72.             /// Uses the default Tracking Origin Mode of the input device.
    73.             /// </summary>
    74.             /// <remarks>
    75.             /// When changing to this value after startup, the Tracking Origin Mode will not be changed.
    76.             /// </remarks>
    77.             NotSpecified,
    78.  
    79.             /// <summary>
    80.             /// Sets the Tracking Origin Mode to <see cref="TrackingOriginModeFlags.Device"/>.
    81.             /// Input devices will be tracked relative to the first known location.
    82.             /// </summary>
    83.             /// <remarks>
    84.             /// Represents a device-relative tracking origin. A device-relative tracking origin defines a local origin
    85.             /// at the position of the device in space at some previous point in time, usually at a recenter event,
    86.             /// power-on, or AR/VR session start. Pose data provided by the device will be in this space relative to
    87.             /// the local origin. This means that poses returned in this mode will not include the user height (for VR)
    88.             /// or the device height (for AR) and any camera tracking from the XR device will need to be manually offset accordingly.
    89.             /// </remarks>
    90.             /// <seealso cref="TrackingOriginModeFlags.Device"/>
    91.             Device,
    92.  
    93.             /// <summary>
    94.             /// Sets the Tracking Origin Mode to <see cref="TrackingOriginModeFlags.Floor"/>.
    95.             /// Input devices will be tracked relative to a location on the floor.
    96.             /// </summary>
    97.             /// <remarks>
    98.             /// Represents the tracking origin whereby (0, 0, 0) is on the "floor" or other surface determined by the
    99.             /// XR device being used. The pose values reported by an XR device in this mode will include the height
    100.             /// of the XR device above this surface, removing the need to offset the position of the camera tracking
    101.             /// the XR device by the height of the user (VR) or the height of the device above the floor (AR).
    102.             /// </remarks>
    103.             /// <seealso cref="TrackingOriginModeFlags.Floor"/>
    104.             Floor,
    105.         }
    106.  
    107.         //This is the average seated height in meters (which equals 44 inches).
    108.         const float k_DefaultCameraYOffset = 1.1176f;
    109.  
    110.         [SerializeField, FormerlySerializedAs("m_RigBaseGameObject")]
    111.         GameObject m_OriginBaseGameObject;
    112.  
    113.         /// <summary>
    114.         /// The "Origin" <see cref="GameObject"/> is used to refer to the base of the XR Origin, by default it is this <see cref="GameObject"/>.
    115.         /// This is the <see cref="GameObject"/> that will be manipulated via locomotion.
    116.         /// </summary>
    117.         public GameObject Origin
    118.         {
    119.             get => m_OriginBaseGameObject;
    120.             set => m_OriginBaseGameObject = value;
    121.         }
    122.  
    123.         [SerializeField]
    124.         GameObject m_CameraFloorOffsetObject;
    125.  
    126.         /// <summary>
    127.         /// The <see cref="GameObject"/> to move to desired height off the floor (defaults to this object if none provided).
    128.         /// This is used to transform the XR device from camera space to XR Origin space.
    129.         /// </summary>
    130.         public GameObject CameraFloorOffsetObject
    131.         {
    132.             get => m_CameraFloorOffsetObject;
    133.             set
    134.             {
    135.                 m_CameraFloorOffsetObject = value;
    136.                 MoveOffsetHeight();
    137.             }
    138.         }
    139.  
    140.         [SerializeField]
    141.         TrackingOriginMode m_RequestedTrackingOriginMode = TrackingOriginMode.NotSpecified;
    142.  
    143.         /// <summary>
    144.         /// The type of tracking origin to use for this XROrigin. Tracking origins identify where (0, 0, 0) is in the world
    145.         /// of tracking. Not all devices support all tracking origin modes.
    146.         /// </summary>
    147.         /// <seealso cref="TrackingOriginMode"/>
    148.         public TrackingOriginMode RequestedTrackingOriginMode
    149.         {
    150.             get => m_RequestedTrackingOriginMode;
    151.             set
    152.             {
    153.                 m_RequestedTrackingOriginMode = value;
    154.                 TryInitializeCamera();
    155.             }
    156.         }
    157.  
    158.         [SerializeField]
    159.         float m_CameraYOffset = k_DefaultCameraYOffset;
    160.  
    161.         /// <summary>
    162.         /// Camera height to be used when in <c>Device</c> Tracking Origin Mode to define the height of the user from the floor.
    163.         /// This is the amount that the camera is offset from the floor when moving the <see cref="CameraFloorOffsetObject"/>.
    164.         /// </summary>
    165.         public float CameraYOffset
    166.         {
    167.             get => m_CameraYOffset;
    168.             set
    169.             {
    170.                 m_CameraYOffset = value;
    171.                 MoveOffsetHeight();
    172.             }
    173.         }
    174.  
    175. #if XR_MODULE_AVAILABLE || PACKAGE_DOCS_GENERATION
    176.         /// <summary>
    177.         /// (Read Only) The Tracking Origin Mode of this XR Origin.
    178.         /// </summary>
    179.         /// <seealso cref="RequestedTrackingOriginMode"/>
    180.         public TrackingOriginModeFlags CurrentTrackingOriginMode { get; private set; }
    181. #endif
    182.  
    183.         /// <summary>
    184.         /// (Read Only) The origin's local position in camera space.
    185.         /// </summary>
    186.         public Vector3 OriginInCameraSpacePos => m_Camera.transform.InverseTransformPoint(m_OriginBaseGameObject.transform.position);
    187.  
    188.         /// <summary>
    189.         /// (Read Only) The camera's local position in origin space.
    190.         /// </summary>
    191.         public Vector3 CameraInOriginSpacePos => m_OriginBaseGameObject.transform.InverseTransformPoint(m_Camera.transform.position);
    192.  
    193.         /// <summary>
    194.         /// (Read Only) The camera's height relative to the origin.
    195.         /// </summary>
    196.         public float CameraInOriginSpaceHeight => CameraInOriginSpacePos.y;
    197.  
    198. #if XR_MODULE_AVAILABLE
    199.         /// <summary>
    200.         /// Used to cache the input subsystems without creating additional GC allocations.
    201.         /// </summary>
    202.         static readonly List<XRInputSubsystem> s_InputSubsystems = new List<XRInputSubsystem>();
    203. #endif
    204.  
    205.         // Bookkeeping to track lazy initialization of the tracking origin mode type.
    206.         bool m_CameraInitialized;
    207.         bool m_CameraInitializing;
    208.  
    209.         /// <summary>
    210.         /// Sets the height of the camera based on the current tracking origin mode by updating the <see cref="CameraFloorOffsetObject"/>.
    211.         /// </summary>
    212.         void MoveOffsetHeight()
    213.         {
    214. #if XR_MODULE_AVAILABLE
    215.             if (!Application.isPlaying)
    216.                 return;
    217.  
    218.             switch (CurrentTrackingOriginMode)
    219.             {
    220.                 case TrackingOriginModeFlags.Floor:
    221.                     MoveOffsetHeight(0f);
    222.                     break;
    223.                 case TrackingOriginModeFlags.Device:
    224.                     MoveOffsetHeight(m_CameraYOffset);
    225.                     break;
    226.                 default:
    227.                     return;
    228.             }
    229. #endif
    230.         }
    231.  
    232.         /// <summary>
    233.         /// Sets the height of the camera to the given <paramref name="y"/> value by updating the <see cref="CameraFloorOffsetObject"/>.
    234.         /// </summary>
    235.         /// <param name="y">The local y-position to set.</param>
    236.         void MoveOffsetHeight(float y)
    237.         {
    238.             if (m_CameraFloorOffsetObject != null)
    239.             {
    240.                 var offsetTransform = m_CameraFloorOffsetObject.transform;
    241.                 var desiredPosition = offsetTransform.localPosition;
    242.                 desiredPosition.y = y;
    243.                 offsetTransform.localPosition = desiredPosition;
    244.             }
    245.         }
    246.  
    247.         /// <summary>
    248.         /// Repeatedly attempt to initialize the camera.
    249.         /// </summary>
    250.         void TryInitializeCamera()
    251.         {
    252.             if (!Application.isPlaying)
    253.                 return;
    254.  
    255.             m_CameraInitialized = SetupCamera();
    256.             if (!m_CameraInitialized & !m_CameraInitializing)
    257.                 StartCoroutine(RepeatInitializeCamera());
    258.         }
    259.  
    260.         /// <summary>
    261.         /// Handles re-centering and off-setting the camera in space depending on which tracking origin mode it is setup in.
    262.         /// </summary>
    263.         bool SetupCamera()
    264.         {
    265.             var initialized = true;
    266.  
    267. #if XR_MODULE_AVAILABLE
    268. #if UNITY_2023_2_OR_NEWER
    269.             SubsystemManager.GetSubsystems(s_InputSubsystems);
    270. #else
    271.             SubsystemManager.GetInstances(s_InputSubsystems);
    272. #endif
    273.             if (s_InputSubsystems.Count > 0)
    274.             {
    275.                 foreach (var inputSubsystem in s_InputSubsystems)
    276.                 {
    277.                     if (SetupCamera(inputSubsystem))
    278.                     {
    279.                         // It is possible this could happen more than
    280.                         // once so unregister the callback first just in case.
    281.                         inputSubsystem.trackingOriginUpdated -= OnInputSubsystemTrackingOriginUpdated;
    282.                         inputSubsystem.trackingOriginUpdated += OnInputSubsystemTrackingOriginUpdated;
    283.                     }
    284.                     else
    285.                     {
    286.                         initialized = false;
    287.                     }
    288.                 }
    289.             }
    290. #endif
    291.  
    292.             return initialized;
    293.         }
    294.  
    295. #if XR_MODULE_AVAILABLE
    296.         bool SetupCamera(XRInputSubsystem inputSubsystem)
    297.         {
    298.             if (inputSubsystem == null)
    299.                 return false;
    300.  
    301.             var successful = true;
    302.  
    303.             switch (m_RequestedTrackingOriginMode)
    304.             {
    305.                 case TrackingOriginMode.NotSpecified:
    306.                     CurrentTrackingOriginMode = inputSubsystem.GetTrackingOriginMode();
    307.                     break;
    308.                 case TrackingOriginMode.Device:
    309.                 case TrackingOriginMode.Floor:
    310.                 {
    311.                     var supportedModes = inputSubsystem.GetSupportedTrackingOriginModes();
    312.  
    313.                     // We need to check for Unknown because we may not be in a state where we can read this data yet.
    314.                     if (supportedModes == TrackingOriginModeFlags.Unknown)
    315.                         return false;
    316.  
    317.                     // Convert from the request enum to the flags enum that is used by the subsystem
    318.                     var equivalentFlagsMode = m_RequestedTrackingOriginMode == TrackingOriginMode.Device
    319.                         ? TrackingOriginModeFlags.Device
    320.                         : TrackingOriginModeFlags.Floor;
    321.  
    322.                     // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags -- Treated like Flags enum when querying supported modes
    323.                     if ((supportedModes & equivalentFlagsMode) == 0)
    324.                     {
    325.                         m_RequestedTrackingOriginMode = TrackingOriginMode.NotSpecified;
    326.                         CurrentTrackingOriginMode = inputSubsystem.GetTrackingOriginMode();
    327.                         Debug.LogWarning($"Attempting to set the tracking origin mode to {equivalentFlagsMode}, but that is not supported by the SDK." +
    328.                             $" Supported types: {supportedModes:F}. Using the current mode of {CurrentTrackingOriginMode} instead.", this);
    329.                     }
    330.                     else
    331.                     {
    332.                         successful = inputSubsystem.TrySetTrackingOriginMode(equivalentFlagsMode);
    333.                     }
    334.                 }
    335.                 break;
    336.                 default:
    337.                     Assert.IsTrue(false, $"Unhandled {nameof(TrackingOriginMode)}={m_RequestedTrackingOriginMode}");
    338.                     return false;
    339.             }
    340.  
    341.             if (successful)
    342.                 MoveOffsetHeight();
    343.  
    344.             if (CurrentTrackingOriginMode == TrackingOriginModeFlags.Device || m_RequestedTrackingOriginMode == TrackingOriginMode.Device)
    345.                 successful = inputSubsystem.TryRecenter();
    346.  
    347.             return successful;
    348.         }
    349.  
    350.         void OnInputSubsystemTrackingOriginUpdated(XRInputSubsystem inputSubsystem)
    351.         {
    352.             CurrentTrackingOriginMode = inputSubsystem.GetTrackingOriginMode();
    353.             MoveOffsetHeight();
    354.         }
    355. #endif
    356.  
    357.         IEnumerator RepeatInitializeCamera()
    358.         {
    359.             m_CameraInitializing = true;
    360.             while (!m_CameraInitialized)
    361.             {
    362.                 yield return null;
    363.                 if (!m_CameraInitialized)
    364.                     m_CameraInitialized = SetupCamera();
    365.             }
    366.             m_CameraInitializing = false;
    367.         }
    368.  
    369.         /// <summary>
    370.         /// Rotates the XR origin object around the camera object by the provided <paramref name="angleDegrees"/>.
    371.         /// This rotation only occurs around the origin's Up vector
    372.         /// </summary>
    373.         /// <param name="angleDegrees">The amount of rotation in degrees.</param>
    374.         /// <returns>Returns <see langword="true"/> if the rotation is performed. Otherwise, returns <see langword="false"/>.</returns>
    375.         public bool RotateAroundCameraUsingOriginUp(float angleDegrees)
    376.         {
    377.             return RotateAroundCameraPosition(m_OriginBaseGameObject.transform.up, angleDegrees);
    378.         }
    379.  
    380.         /// <summary>
    381.         /// Rotates the XR origin object around the camera object's position in world space using the provided <paramref name="vector"/>
    382.         /// as the rotation axis. The XR Origin object is rotated by the amount of degrees provided in <paramref name="angleDegrees"/>.
    383.         /// </summary>
    384.         /// <param name="vector">The axis of the rotation.</param>
    385.         /// <param name="angleDegrees">The amount of rotation in degrees.</param>
    386.         /// <returns>Returns <see langword="true"/> if the rotation is performed. Otherwise, returns <see langword="false"/>.</returns>
    387.         public bool RotateAroundCameraPosition(Vector3 vector, float angleDegrees)
    388.         {
    389.             if (m_Camera == null || m_OriginBaseGameObject == null)
    390.             {
    391.                 return false;
    392.             }
    393.  
    394.             // Rotate around the camera position
    395.             m_OriginBaseGameObject.transform.RotateAround(m_Camera.transform.position, vector, angleDegrees);
    396.  
    397.             return true;
    398.         }
    399.  
    400.         /// <summary>
    401.         /// This function will rotate the XR Origin object such that the XR Origin's up vector will match the provided vector.
    402.         /// </summary>
    403.         /// <param name="destinationUp">the vector to which the XR Origin object's up vector will be matched.</param>
    404.         /// <returns>Returns <see langword="true"/> if the rotation is performed or the vectors have already been matched.
    405.         /// Otherwise, returns <see langword="false"/>.</returns>
    406.         public bool MatchOriginUp(Vector3 destinationUp)
    407.         {
    408.             if (m_OriginBaseGameObject == null)
    409.             {
    410.                 return false;
    411.             }
    412.  
    413.             if (m_OriginBaseGameObject.transform.up == destinationUp)
    414.                 return true;
    415.  
    416.             var rigUp = Quaternion.FromToRotation(m_OriginBaseGameObject.transform.up, destinationUp);
    417.             m_OriginBaseGameObject.transform.rotation = rigUp * transform.rotation;
    418.  
    419.             return true;
    420.         }
    421.  
    422.         /// <summary>
    423.         /// This function will rotate the XR Origin object around the camera object using the <paramref name="destinationUp"/> vector such that:
    424.         /// <list type="bullet">
    425.         /// <item>
    426.         /// <description>The camera will look at the area in the direction of the <paramref name="destinationForward"/></description>
    427.         /// </item>
    428.         /// <item>
    429.         /// <description>The projection of camera's forward vector on the plane with the normal <paramref name="destinationUp"/> will be in the direction of <paramref name="destinationForward"/></description>
    430.         /// </item>
    431.         /// <item>
    432.         /// <description>The up vector of the XR Origin object will match the provided <paramref name="destinationUp"/> vector (note that the camera's Up vector can not be manipulated)</description>
    433.         /// </item>
    434.         /// </list>
    435.         /// </summary>
    436.         /// <param name="destinationUp">The up vector that the origin's up vector will be matched to.</param>
    437.         /// <param name="destinationForward">The forward vector that will be matched to the projection of the camera's forward vector on the plane with the normal <paramref name="destinationUp"/>.</param>
    438.         /// <returns>Returns <see langword="true"/> if the rotation is performed. Otherwise, returns <see langword="false"/>.</returns>
    439.         public bool MatchOriginUpCameraForward(Vector3 destinationUp, Vector3 destinationForward)
    440.         {
    441.             if (m_Camera != null && MatchOriginUp(destinationUp))
    442.             {
    443.                 // Project current camera's forward vector on the destination plane, whose normal vector is destinationUp.
    444.                 var projectedCamForward = Vector3.ProjectOnPlane(m_Camera.transform.forward, destinationUp).normalized;
    445.  
    446.                 // The angle that we want the XROrigin to rotate is the signed angle between projectedCamForward and destinationForward, after the up vectors are matched.
    447.                 var signedAngle = Vector3.SignedAngle(projectedCamForward, destinationForward, destinationUp);
    448.  
    449.                 RotateAroundCameraPosition(destinationUp, signedAngle);
    450.  
    451.                 return true;
    452.             }
    453.  
    454.             return false;
    455.         }
    456.  
    457.         /// <summary>
    458.         /// This function will rotate the XR Origin object around the camera object using the <paramref name="destinationUp"/> vector such that:
    459.         /// <list type="bullet">
    460.         /// <item>
    461.         /// <description>The forward vector of the XR Origin object, which is the direction the player moves in Unity when walking forward in the physical world, will match the provided <paramref name="destinationUp"/> vector</description>
    462.         /// </item>
    463.         /// <item>
    464.         /// <description>The up vector of the XR Origin object will match the provided <paramref name="destinationUp"/> vector</description>
    465.         /// </item>
    466.         /// </list>
    467.         /// </summary>
    468.         /// <param name="destinationUp">The up vector that the origin's up vector will be matched to.</param>
    469.         /// <param name="destinationForward">The forward vector that will be matched to the forward vector of the XR Origin object,
    470.         /// which is the direction the player moves in Unity when walking forward in the physical world.</param>
    471.         /// <returns>Returns <see langword="true"/> if the rotation is performed. Otherwise, returns <see langword="false"/>.</returns>
    472.         public bool MatchOriginUpOriginForward(Vector3 destinationUp, Vector3 destinationForward)
    473.         {
    474.             if (m_OriginBaseGameObject != null && MatchOriginUp(destinationUp))
    475.             {
    476.                 // The angle that we want the XR Origin to rotate is the signed angle between the origin's forward and destinationForward, after the up vectors are matched.
    477.                 var signedAngle = Vector3.SignedAngle(m_OriginBaseGameObject.transform.forward, destinationForward, destinationUp);
    478.  
    479.                 RotateAroundCameraPosition(destinationUp, signedAngle);
    480.  
    481.                 return true;
    482.             }
    483.  
    484.             return false;
    485.         }
    486.  
    487.         /// <summary>
    488.         /// This function moves the camera to the world location provided by <paramref name="desiredWorldLocation"/>.
    489.         /// It does this by moving the XR Origin object so that the camera's world location matches the desiredWorldLocation
    490.         /// </summary>
    491.         /// <param name="desiredWorldLocation">the position in world space that the camera should be moved to</param>
    492.         /// <returns>Returns <see langword="true"/> if the move is performed. Otherwise, returns <see langword="false"/>.</returns>
    493.         public bool MoveCameraToWorldLocation(Vector3 desiredWorldLocation)
    494.         {
    495.             if (m_Camera == null)
    496.             {
    497.                 return false;
    498.             }
    499.  
    500.             var rot = Matrix4x4.Rotate(m_Camera.transform.rotation);
    501.             var delta = rot.MultiplyPoint3x4(OriginInCameraSpacePos);
    502.             m_OriginBaseGameObject.transform.position = delta + desiredWorldLocation;
    503.  
    504.             return true;
    505.         }
    506.  
    507.         /// <summary>
    508.         /// See <see cref="MonoBehaviour"/>.
    509.         /// </summary>
    510.         protected void Awake()
    511.         {
    512.             if (m_CameraFloorOffsetObject == null)
    513.             {
    514.                 Debug.LogWarning("No Camera Floor Offset GameObject specified for XR Origin, using attached GameObject.", this);
    515.                 m_CameraFloorOffsetObject = gameObject;
    516.             }
    517.  
    518.             if (m_Camera == null)
    519.             {
    520.                 var mainCamera = Camera.main;
    521.                 if (mainCamera != null)
    522.                     m_Camera = mainCamera;
    523.                 else
    524.                     Debug.LogWarning("No Main Camera is found for XR Origin, please assign the Camera field manually.", this);
    525.             }
    526.  
    527.             // This will be the parent GameObject for any trackables (such as planes) for which
    528.             // we want a corresponding GameObject.
    529.             TrackablesParent = new GameObject("Trackables").transform;
    530.             TrackablesParent.SetParent(transform, false);
    531.             TrackablesParent.SetLocalPose(Pose.identity);
    532.             TrackablesParent.localScale = Vector3.one;
    533.  
    534.             if (m_Camera)
    535.             {
    536. #if INCLUDE_INPUT_SYSTEM && INCLUDE_LEGACY_INPUT_HELPERS
    537.                 var trackedPoseDriver = m_Camera.GetComponent<UnityEngine.InputSystem.XR.TrackedPoseDriver>();
    538.                 var trackedPoseDriverOld = m_Camera.GetComponent<UnityEngine.SpatialTracking.TrackedPoseDriver>();
    539.                 if (trackedPoseDriver == null && trackedPoseDriverOld == null)
    540.                 {
    541.                     Debug.LogWarning(
    542.                         $"Camera \"{m_Camera.name}\" does not use a Tracked Pose Driver (Input System), " +
    543.                         "so its transform will not be updated by an XR device.  In order for this to be " +
    544.                         "updated, please add a Tracked Pose Driver (Input System) with bindings for position and rotation of the center eye.", this);
    545.                 }
    546. #elif !INCLUDE_INPUT_SYSTEM && INCLUDE_LEGACY_INPUT_HELPERS
    547.                 var trackedPoseDriverOld = m_Camera.GetComponent<UnityEngine.SpatialTracking.TrackedPoseDriver>();
    548.                 if (trackedPoseDriverOld == null)
    549.                 {
    550.                     Debug.LogWarning(
    551.                         $"Camera \"{m_Camera.name}\" does not use a Tracked Pose Driver, and com.unity.xr.legacyinputhelpers is installed. " +
    552.                         "Although the Tracked Pose Driver from Legacy Input Helpers can be used, it is recommended to " +
    553.                         "install com.unity.inputsystem instead and add a Tracked Pose Driver (Input System) with bindings for position and rotation of the center eye.", this);
    554.                 }
    555. #elif INCLUDE_INPUT_SYSTEM && !INCLUDE_LEGACY_INPUT_HELPERS
    556.                 var trackedPoseDriver = m_Camera.GetComponent<UnityEngine.InputSystem.XR.TrackedPoseDriver>();
    557.                 if (trackedPoseDriver == null)
    558.                 {
    559.                     Debug.LogWarning(
    560.                         $"Camera \"{m_Camera.name}\" does not use a Tracked Pose Driver (Input System), " +
    561.                         "so its transform will not be updated by an XR device.  In order for this to be " +
    562.                         "updated, please add a Tracked Pose Driver (Input System) with bindings for position and rotation of the center eye.", this);
    563.                 }
    564. #elif !INCLUDE_INPUT_SYSTEM && !INCLUDE_LEGACY_INPUT_HELPERS
    565.                 Debug.LogWarning(
    566.                     $"Camera \"{m_Camera.name}\" does not use a Tracked Pose Driver and com.unity.inputsystem is not installed, " +
    567.                     "so its transform will not be updated by an XR device.  In order for this to be " +
    568.                     "updated, please install com.unity.inputsystem and add a Tracked Pose Driver (Input System) with bindings for position and rotation of the center eye.", this);
    569. #endif
    570.             }
    571.         }
    572.  
    573.         Pose GetCameraOriginPose()
    574.         {
    575.             var localOriginPose = Pose.identity;
    576.             var parent = m_Camera.transform.parent;
    577.  
    578.             return parent
    579.                 ? parent.TransformPose(localOriginPose)
    580.                 : localOriginPose;
    581.         }
    582.  
    583.         /// <summary>
    584.         /// See <see cref="MonoBehaviour"/>.
    585.         /// </summary>
    586.         protected void OnEnable() => Application.onBeforeRender += OnBeforeRender;
    587.  
    588.         /// <summary>
    589.         /// See <see cref="MonoBehaviour"/>.
    590.         /// </summary>
    591.         protected void OnDisable() => Application.onBeforeRender -= OnBeforeRender;
    592.  
    593.         void OnBeforeRender()
    594.         {
    595.             if (m_Camera)
    596.             {
    597.                 var pose = GetCameraOriginPose();
    598.                 TrackablesParent.position = pose.position;
    599.                 TrackablesParent.rotation = pose.rotation;
    600.             }
    601.  
    602.             if (TrackablesParent.hasChanged)
    603.             {
    604.                 TrackablesParentTransformChanged?.Invoke(
    605.                     new ARTrackablesParentTransformChangedEventArgs(this, TrackablesParent));
    606.                 TrackablesParent.hasChanged = false;
    607.             }
    608.         }
    609.  
    610.         /// <summary>
    611.         /// See <see cref="MonoBehaviour"/>.
    612.         /// </summary>
    613.         protected void OnValidate()
    614.         {
    615.             if (m_OriginBaseGameObject == null)
    616.                 m_OriginBaseGameObject = gameObject;
    617.  
    618.             if (Application.isPlaying && isActiveAndEnabled)
    619.             {
    620.                 // Respond to the mode changing by re-initializing the camera,
    621.                 // or just update the offset height in order to avoid recentering.
    622.                 if (IsModeStale())
    623.                     TryInitializeCamera();
    624.                 else
    625.                     MoveOffsetHeight();
    626.             }
    627.  
    628.             bool IsModeStale()
    629.             {
    630. #if XR_MODULE_AVAILABLE
    631.                 if (s_InputSubsystems.Count > 0)
    632.                 {
    633.                     foreach (var inputSubsystem in s_InputSubsystems)
    634.                     {
    635.                         // Convert from the request enum to the flags enum that is used by the subsystem
    636.                         TrackingOriginModeFlags equivalentFlagsMode;
    637.                         switch (m_RequestedTrackingOriginMode)
    638.                         {
    639.                             case TrackingOriginMode.NotSpecified:
    640.                                 // Don't need to initialize the camera since we don't set the mode when NotSpecified (we just keep the current value)
    641.                                 return false;
    642.                             case TrackingOriginMode.Device:
    643.                                 equivalentFlagsMode = TrackingOriginModeFlags.Device;
    644.                                 break;
    645.                             case TrackingOriginMode.Floor:
    646.                                 equivalentFlagsMode = TrackingOriginModeFlags.Floor;
    647.                                 break;
    648.                             default:
    649.                                 Assert.IsTrue(false, $"Unhandled {nameof(TrackingOriginMode)}={m_RequestedTrackingOriginMode}");
    650.                                 return false;
    651.                         }
    652.  
    653.                         if (inputSubsystem != null && inputSubsystem.GetTrackingOriginMode() != equivalentFlagsMode)
    654.                         {
    655.                             return true;
    656.                         }
    657.                     }
    658.                 }
    659. #endif
    660.                 return false;
    661.             }
    662.         }
    663.  
    664.         /// <summary>
    665.         /// See <see cref="MonoBehaviour"/>.
    666.         /// </summary>
    667.         protected void Start()
    668.         {
    669.             TryInitializeCamera();
    670.         }
    671.  
    672.         /// <summary>
    673.         /// See <see cref="MonoBehaviour"/>.
    674.         /// </summary>
    675.         protected void OnDestroy()
    676.         {
    677. #if XR_MODULE_AVAILABLE
    678.             foreach (var inputSubsystem in s_InputSubsystems)
    679.             {
    680.                 if (inputSubsystem != null)
    681.                     inputSubsystem.trackingOriginUpdated -= OnInputSubsystemTrackingOriginUpdated;
    682.             }
    683. #endif
    684.         }
    685.     }
    686. }
     
  2. DevDunk

    DevDunk

    Joined:
    Feb 13, 2020
    Posts:
    5,224
    Maybe set the tracking type to camera instead of floor?
     
  3. unity_andrewc

    unity_andrewc

    Unity Technologies

    Joined:
    Dec 14, 2015
    Posts:
    228
    Using floor as the tracking type will set the floor to y=0, which sounds like it would avoid the problem of getting the height of it