Search Unity

  1. Unity wants to learn about your experiences working on a Unity project today. We'd like to hear from you via this survey.
    Dismiss Notice
  2. Read here for Unity's latest plans on OpenXR.
    Dismiss Notice

XR Floor Position Native Unity

Discussion in 'AR/VR (XR) Discussion' started by plmx, May 9, 2019.

  1. plmx

    plmx

    Joined:
    Sep 10, 2015
    Posts:
    268
    Hi,

    when not using any plug-ins, but just the native Unity XR support, I can't seem to get the floor Y position to be consistent across the Oculus and OpenVR SDKs. If I do nothing to the camera (except enabling XR), the Y coordinate of the Oculus Rift is at 0 at headset height, while the Vive (OpenVR) one is at 0 at floor height.

    Adding a Tracked Pose Driver with "Generic XR Device / Head" does not change this.

    This question seems to pop up now and then in the forums but I have not found an authoritative answer from Unity regarding this. The question is simply: What must I do to set the camera to a consistent Y reference (floor or headset) across all supported XR platforms (NOT using any plugins).

    Is this possible at all without the OVR plugin? (@StayTalm_Unity?)

    Thanks.

    Philip
     
    Last edited: May 10, 2019
    ROBYER1 likes this.
  2. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    164
    Helllooooo,
    This has to do with default behaviour if each platform. We have a couple APIs in XRDevice that we are still in the process of migrating up to our InputDevice API level, called [XR.XRDevice.SetTrackingSpaceType] and [XR.XRDevice.GetTrackingSpaceType]. These adjust what we report devices relative to, namely whether it's relative to the floor, or relative to the device at it's initial position. In your case Oculus is defaulting to using the Stationary tracking space type, which is device starting point relative. If you call SetTrackingSpaceType with the RoomScale type, it will bump it upwards to be floor relative. I believe OpenVR defaults to highest available, so RoomScale if a proper bounds were set.

    That should work for now, once we move that logic to the InputDevice APIs you will get a clear, concise obsolescence warning of the new API to use.

    Edit: Just reread the final question again. You should be able to set it to either mode on application start to enforce some consistency. More platforms support the Stationary mode (tracked devices reported relative to the device on startup mode) than roomscale, so if that works for you, then I'd suggest it.
     
    ROBYER1, just_gos and plmx like this.
  3. plmx

    plmx

    Joined:
    Sep 10, 2015
    Posts:
    268
    Hi,

    Ah gawd. That explains so much and was exactly the info I was missing. Thank you so much! And yes, adding a no-questions-asked call to [XR.XRDevice.SetTrackingSpaceType] fixed the issue. Perfect.

    I was under the impression that the default behavior was/should be always the setting on the machine where you'd start the software, i.e. if I set the Rift to Roomscale mode in the Oculus software (not that there is an explicit setting, but a guardian of 3x3 meters should be considered room scale I guess), it should start every application in room scale mode. That is why I never checked the tracking mode.

    Do you think there is some merit in having Unity check for the machine's setting and use that by default? (although I will definitely set it explicitly anyway in the future :) ).

    Philip
     
  4. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    164
    Looking into it.
    It was actually a bit of surprise, some of my colleagues was convinced that Oculus would start with the highest level available (i.e. floor-relative if available). We are going over this for Input Device, and hopefully can find a good cross-platform way to always start with positions local to floor if that mode is available.
     
    Wim-Wouters, ROBYER1 and plmx like this.
  5. unitylepi

    unitylepi

    Joined:
    May 21, 2018
    Posts:
    34
    I'm really confused. I'm using a tracked pose driver on the camera to get its unity world position, then I can place/teleport the player by adjusting the camera's parent, but which call do I use to get the physical offset from the HMD to the floor? I want to teleport the player up a flight of stairs while keeping him at the correct height from the colliders on the steps.

    (btw, the XR.XRDevice.SetTrackingSpaceType documention states this is already obsolete and it has NO link to any kind of replacement :( Same for the tracked pose driver)
     
    Last edited: Feb 3, 2020
  6. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    164
    Hi
    Just noticed the Scripting Reference doesn't pick up the in-code ObsoleteAttribute tags I added. Will work to get those added to the scripting reference, since that is the first places users may look.

    You are on the right track: In order to get the floor height, you need to set the device's origin to the floor. That way the 0,0,0 point of the device is no longer wherever the device was at the last Recenter or on App Start, but is located somewhere on the floor.

    Once set, you can deduce the player's height by asking them to stand and getting the device's Y-height. At least that is the height of his eyes.

    As we are moving to the new Plugin Architecture, we now use a concept of Subsystems. In this case, the XRInputSubsystem has a concept of TrackingOriginMode. Someone just linked a quick example of setting the XRInputSubsystem's TrackingOriginMode: https://forum.unity.com/threads/any...-1-xr-input-system.629824/page-2#post-5438118

    Rewritten for Floor:

    Code (CSharp):
    1. List<XRInputSubsystem> subsystems = new List<XRInputSubsystem>();
    2. SubsystemManager.GetInstances<XRInputSubsystem>(subsystems);
    3. for (int i = 0; i < subsystems.Count; i++)
    4. {
    5.    subsystems[i].TrySetTrackingOriginMode(TrackingOriginModeFlags.Floor);
    6. }
    7.  
    TrackingOriginModeFlags has 3 settings:
    Device places the origin at scene start position and Yaw.
    Floor picks a spot on the floor, SDK set but normally the center of the tracking boundary as the Origin. Recenter may change the Yaw or position, but the Y=0 will always be the floor.
    TrackingReference uses a fixed tracking object as the origin, think tracking sensor. Probably not something you need to worry about at this time.

    Let me know if this gets you back on track!
     
    throzen likes this.
  7. unitylepi

    unitylepi

    Joined:
    May 21, 2018
    Posts:
    34
    Got this working for the tracked pose driver (still can't find an equivalent that is not obsolete)

    /*On start:*/
    XRDevice.SetTrackingSpaceType(TrackingSpaceType.RoomScale)

    //On Main Camera: Add Tracked Pose Driver script

    /*Unity Global HMD position:*/ Camera.transform.position/rotation
    /*HMD floor offset in Unity units:*/ Camera.transform.localPosition.y
     
  8. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    164
    @unitylepi
    Which XR Platforms are you targeting? (e.g. WMR, Oculus, OpenVR)
     
  9. unitylepi

    unitylepi

    Joined:
    May 21, 2018
    Posts:
    34
    I've enabled only the OpenVR plugin and am targeting wmr, oculus rift, vive, index. However, when setting the legacy room scale fails, I use a user defined preset for the rig to floor height. By the way, the speed with which perfectly working Unity vr stuff is suddenly becoming legacy anyway is more than a little dizzying...
     
    Deleted User likes this.
  10. unitylepi

    unitylepi

    Joined:
    May 21, 2018
    Posts:
    34
    According to the manual unity automatically sets the correct v-sync for vr, but my vr appilcation easily hits 245fps, causing all kinds of jitter and half rendered objects during vr rig rotation. Is there a way to force unity to sync with the headset? I'm using OpenVR, doublewide-single pass,

    Untitled.jpg

    "https://docs.unity3d.com/Manual/VRFrameTiming.html
    Frame timing in VR mode works exactly like it does in VSync-enabled non-VR mode. The only difference is that Unity does not depend on the underlying 3D SDK’s VSync, but instead whichever VR SDK it currently renders with."
     
  11. AbsurdAndy

    AbsurdAndy

    Joined:
    Dec 6, 2019
    Posts:
    23
    hessex likes this.
  12. AbsurdAndy

    AbsurdAndy

    Joined:
    Dec 6, 2019
    Posts:
    23
    FWIW Oculus Quest works fine with the link cable, it's the android build of quests that is failing.
     
  13. hawken

    hawken

    Joined:
    Aug 22, 2013
    Posts:
    606
    @StayTalm_Unity

    Having this issue on webxr, on Quest.

    The code above is marked as obsolete. Is there a work around? The floor starts at the hmd height.
     
  14. Htrom14

    Htrom14

    Joined:
    Mar 4, 2021
    Posts:
    1
    Hi! I've been trying to tackle this problem for a while now, but Im most curious how I can modify the tracking origin based off an April Tag to alter the orientation. Basically, if anyone has any experience updating the origin tracking pose origin at runtime I'd be super grateful to hear how you do it!
     
  15. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    164
    Hello, the replacement is in the XRInputSubsystem. Here is a short snippet. Each platform sets it's own default, but if you want a floor height tracking, here is a quick example:

    Code (CSharp):
    1. // Use a cache to be heap efficient, not necessary if you only call on startup.
    2. static List<XRInputSubsystem> k_CachedSubsystems = new List<XRInputSubsystem>();
    3. XRInputSubsystem m_InputSubsystem;
    4.  
    5. public void SetTrackingOriginMode()
    6. {
    7.     if (m_InputSubsystem == null)
    8.     {
    9.         SubsystemManager.GetInstances(k_CachedSubsystems);
    10.         if (k_CachedSubsystems.Count != 0)
    11.             m_InputSubsystem = k_CachedSubsystems[0];
    12.     }
    13.  
    14.     Debug.Log($"Tracking Origin Mode is [{m_InputSubsystem.GetTrackingOriginMode()}]");
    15.     if (m_InputSubsystem.TrySetTrackingOriginMode(TrackingOriginModeFlags.Floor))
    16.         Debug.Log($"Successfully set tracking origin mode to [{m_InputSubsystem.GetTrackingOriginMode()}]");
    17.     else
    18.         Debug.Log("Failed to set tracking origin mode");
    19. }
    Keep in mind not all platforms support all tracking modes. We have packages such as the XR Interaction Toolkit that comes with a rig that is able to set to floor mode, but if not available use a simulated player height, to keep the view up off the floor.
     
  16. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,335
    this is driving me crazy. I have a game where you are sit on a car driver seat. Depending on which VR I plug in, sometimes I begin the game 3 meters away from my seat. Flying above or all the way to the left.
    I'm using OpenXR already. Is there a way to make all VR sets to be sitting down on my driver's seat?

    I'm thinking based on the documentation that TrackingOriginModeFlags.Unbounded may help since it would relocate my positions to world position, but I don't see a single example on the web or the samples.

    The idea is that you just grab the glasses, put them on, and by default you are on the drivers seat. Right now I appear at random positions because the glasses may have initiated weirdly.
     
    Last edited: May 1, 2021
  17. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,335
    Ok so what I did and so far seems to work... I placed all VR Camera and Hands and everything inside a Holder gameobject. Then created a Pivot gameobject, which is where I want my eyes to be. I move that Pivot wherever I want to.

    Then I created this method
    public void ResetPosition()
    {
    // Debug.LogWarning("current campos:" + leftEyeCamera.transform.position + " pivot is:" + pivot.position + " diff:" + (leftEyeCamera.transform.position - pivot.position));
    holder.position=holder.position- (leftEyeCamera.transform.position - pivot.position);
    // Debug.LogWarning("moving holder to:" + holder.position);
    }


    Basically what it does is move the Holder position (which has all the camera and hands), to the world position of the Pivot so that the eyes are in that position. I call this after one second in the game. So far seems to work. Not sure whether there is a better way.
     
  18. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    164
    This is because the default tracking origin for different platforms is different.
    The origin represents a fixed point in the real world. All tracking values, like the position or rotation of a headset are reported relative to this fixed point. So when a controller's position in Unity is [0.0, 1.5, 1.0], that controller is physically 1.5 meters above, and 1 meter in front of this invisible, fixed point. Depending on the SDK, that fixed point can be the location of the headset when the application started (Device tracking origin), a location on the floor that is either at the center of a tracking boundary, or directly below the headset on application start if no boundary is set (Floor tracking origin), or it can be a nearby point in space selected by the SDK and updated based on distance from previous origin (Unbounded tracking origin). It sounds like sometimes you are using an SDK set to use the 'Floor' tracking origin. This puts the 0,0,0 point where you'd expect the headset to be, and then places the actual headset way above that, up to 2m if you are tall (and standing). Sometimes it can be off to the left or right, especially if your setup is like mine and the actual space that I sit down is often far from the center of the tracking boundary. It sounds like you are expecting it to be in Device tracking origin mode, where the headset starts at that 0,0,0 point.

    I would suggest setting the tracking origin to Device on startup (using the sample above). As well, what you are doing with the Holder object is a good practice. In the XR Interaction Toolkit the same 'holder' object is called a player rig. It let's you treat the entire real world tracking space as a single game object. Want to move the real world tracked objects? Just move the holder! This type of movement, where you move the rig or holder object in such a way that you have the tracked headset in the *actual* desired location, is a common technique, and how the XR Interaction Toolkit, and other locomotion systems handle VR teleportation.

    If you want to go a little further than that, you can listen for a change in user presence. Something like this:
    Code (CSharp):
    1. bool userWasPresent;
    2.        
    3.         void Update()
    4.         {
    5.             // First we get a headset
    6.             var device = InputDevices.GetDeviceAtXRNode(XRNode.Head);
    7.             if (!device.isValid)
    8.             {
    9.                 userWasPresent = false;
    10.                 return;
    11.             }
    12.            
    13.             // Then we see if this device has a user presence sensor. If not, we assume the user is always present.
    14.             var userPresent = true;
    15.             if (device.TryGetFeatureValue(CommonUsages.userPresence, out bool featureValue))
    16.                 userPresent = featureValue;
    17.  
    18.             // Headset JUST put on this frame. Also triggered the first frame
    19.             if (!userWasPresent & userPresent)
    20.                 ResetPosition();
    21.            
    22.             userWasPresent = userPresent;
    23.         }
    This should perform a reset the first frame that a headset is available. As well, if the device supports user presence, will also perform a reset for the first frame that the headset is put on. This means if they remove the headset, put it down for a moment, and put it back on, you can detect that and make sure the scene is right in front of the user on that first frame he's back in the world.
     
    MichaelJWilliams and creat327 like this.
unityunity