Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MRTK3] Adding support for unbounded tracking mode #11750

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions com.microsoft.mrtk.input/Assets/Prefabs/MRTK XR Rig.prefab
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ GameObject:
m_Component:
- component: {fileID: 2351505566903569412}
- component: {fileID: 3712792914886690938}
- component: {fileID: 2813607766961918107}
m_Layer: 0
m_Name: Camera Offset
m_TagString: Untagged
Expand Down Expand Up @@ -302,6 +303,18 @@ MonoBehaviour:
m_CameraFloorOffsetObject: {fileID: 2351505566903569413}
m_RequestedTrackingOriginMode: 0
m_CameraYOffset: 1.6
--- !u!114 &2813607766961918107
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2351505566903569413}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c4d642881628ba842b14068a50038965, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &2351505567455720334
GameObject:
m_ObjectHideFlags: 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Unity.XR.CoreUtils;
using UnityEditor;
using UnityEngine;
using UnityEngine.XR;

namespace Microsoft.MixedReality.Toolkit.Input.Editor
{
/// <summary>
/// A custom inspector for the <see cref="UnboundedTrackingMode"/> component.
/// </summary>
[CustomEditor(typeof(UnboundedTrackingMode))]
internal class UnboundedTrackingModeInspector : UnityEditor.Editor
{
/// <inheritdoc/>
public override void OnInspectorGUI()
{
#if UNITYXR_MANAGEMENT_PRESENT
EditorGUILayout.HelpBox("This MRTK component works along side XROrigin to ensure that the XRInputSubsystem " +
"has the TrackingOriginModeFlags.Unbounded flag set if this flag is supported.\n\nNote, the " +
"TrackingOriginModeFlags.Unbounded flag is only applied if the XROrigin.RequestedTrackingOriginMode is " +
"set to \"Not Specified\" and the device supports unbounded spaces.", MessageType.Info);

if (target is UnboundedTrackingMode unboundedTrackingMode)
{
XROrigin xrOrigin = unboundedTrackingMode.GetComponent<XROrigin>();
if (xrOrigin.RequestedTrackingOriginMode != XROrigin.TrackingOriginMode.NotSpecified)
{
EditorGUILayout.HelpBox("The XROrigin's tracking origin mode is not set to \"Not Specified\". This " +
"component will only put the XRInputSubsystem into unbounded mode if XROrigin's tracking mode is set " +
"\"Not Specified\"", MessageType.Warning);
}
}
#else
EditorGUILayout.HelpBox("This MRTK component is unable to put the XRInputSubsystem into unbounded mode, as the " +
"com.unity.xr.management package hasn't been included. Please include com.unity.xr.management version 4.2 " +
"for this component to function.", MessageType.Warning);
#endif
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions com.microsoft.mrtk.input/Editor/MRTK.Input.Editor.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
"references": [
"Microsoft.MixedReality.Toolkit.Core",
"Microsoft.MixedReality.Toolkit.Core.Editor",
"Microsoft.MixedReality.Toolkit.Input",
"Microsoft.MixedReality.Toolkit.Input",
"Unity.XR.CoreUtils",
"Unity.XR.CoreUtils.Editor",
"Unity.XR.Interaction.Toolkit",
"Unity.XR.Interaction.Toolkit.Editor"
"Unity.XR.Interaction.Toolkit.Editor",
"Unity.XR.Management"
],
"includePlatforms": [
"Editor"
Expand All @@ -28,6 +30,11 @@
"name": "com.atteneder.ktx",
"expression": "",
"define": "KTX_PRESENT"
},
{
"name": "com.unity.xr.management",
"expression": "4.2",
"define": "UNITYXR_MANAGEMENT_PRESENT"
}
],
"noEngineReferences": false
Expand Down
6 changes: 6 additions & 0 deletions com.microsoft.mrtk.input/MRTK.Input.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"Unity.InputSystem",
"Unity.XR.CoreUtils",
"Unity.XR.Interaction.Toolkit",
"Unity.XR.Management",
"glTFast",
"Ktx"
],
Expand Down Expand Up @@ -37,6 +38,11 @@
"name": "com.atteneder.ktx",
"expression": "",
"define": "KTX_PRESENT"
},
{
"name": "com.unity.xr.management",
"expression": "4.2",
"define": "UNITYXR_MANAGEMENT_PRESENT"
}
],
"noEngineReferences": false
Expand Down
8 changes: 8 additions & 0 deletions com.microsoft.mrtk.input/Tracking.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

178 changes: 178 additions & 0 deletions com.microsoft.mrtk.input/Tracking/UnboundedTrackingMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Unity.XR.CoreUtils;
using UnityEngine;
using UnityEngine.XR;

#if MROPENXR_PRESENT
using Microsoft.MixedReality.OpenXR.Remoting;
#endif

#if UNITYXR_MANAGEMENT_PRESENT
using UnityEngine.XR.Management;
#endif

namespace Microsoft.MixedReality.Toolkit.Input
{
/// <summary>
/// This component works along side Unity's <see cref="XROrigin"/> to ensure that the <see cref="XRInputSubsystem"/> has
/// the <see cref="TrackingOriginModeFlags.Unbounded"/> flag set on its tracking origin mode if this flag is supported.
/// </summary>
/// <remarks>
/// <para>
/// Devices like the HoloLens 2 should use unbounded reference space. This reference space enables the viewer to move
/// freely through a complex environment, often many meters from where they started, while always optimizing for coordinate
/// system stability near the viewer. For more information about unbounded space see the
/// <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_MSFT_unbounded_reference_space">OpenXR Specification</see>.
/// </para>
/// <para>
/// The <see cref="TrackingOriginModeFlags.Unbounded"/> flag is only applied if the <see cref="XROrigin.RequestedTrackingOriginMode"/>
/// is set to <see cref="XROrigin.TrackingOriginMode.NotSpecified"/>, the device supports unbounded spaces, and <see cref="XRInputSubsystem"/>
/// current tracking mode is set to <see cref="TrackingOriginModeFlags.Device"/>.
/// </para>
/// </remarks>
[RequireComponent(typeof(XROrigin))]
[AddComponentMenu("MRTK/Input/Unbounded Tracking Mode")]
public class UnboundedTrackingMode : MonoBehaviour
{
#if UNITYXR_MANAGEMENT_PRESENT
private XRInputSubsystem m_inputSubsystem;
private XROrigin.TrackingOriginMode m_requestedTrackingOriginMode = XROrigin.TrackingOriginMode.NotSpecified;

/// <summary>
/// A Unity event function that is called when the script component has been enabled.
/// </summary>
/// <remarks>
/// This will attempt to set <see cref="XRInputSubsystem"/> tracking mode to <see cref="TrackingOriginModeFlags.Unbounded"/>.
/// </remarks>
private void OnEnable()
{
XRGeneralSettings xrSettings = XRGeneralSettings.Instance;
if (xrSettings == null)
{
Debug.LogWarning($"EyeLevelSceneOrigin: XRGeneralSettings is null.");
return;
}

XRManagerSettings xrManager = xrSettings.Manager;
if (xrManager == null)
{
Debug.LogWarning($"EyeLevelSceneOrigin: XRManagerSettings is null.");
return;
}

XRLoader xrLoader = xrManager.activeLoader;
if (xrLoader == null)
{
Debug.LogWarning($"EyeLevelSceneOrigin: XRLoader is null.");
return;
}

m_inputSubsystem = xrLoader.GetLoadedSubsystem<XRInputSubsystem>();
AMollis marked this conversation as resolved.
Show resolved Hide resolved
if (m_inputSubsystem == null)
{
Debug.LogWarning($"EyeLevelSceneOrigin: XRInputSubsystem is null.");
return;
}

XROrigin xrOrigin = gameObject.GetComponent<XROrigin>();
if (xrOrigin != null)
{
m_requestedTrackingOriginMode = xrOrigin.RequestedTrackingOriginMode;
}

m_inputSubsystem.trackingOriginUpdated += XrInput_trackingOriginUpdated;

EnsureUnboundedModeSetIfSupported();
}

/// <summary>
/// A Unity event function that is called when the script component has been disabled.
/// </summary>
private void OnDisable()
{
if (m_inputSubsystem != null)
{
m_inputSubsystem.trackingOriginUpdated -= XrInput_trackingOriginUpdated;
m_inputSubsystem = null;
}
}

private void XrInput_trackingOriginUpdated(XRInputSubsystem obj)
{
if (isActiveAndEnabled)
{
EnsureUnboundedModeSetIfSupported();
}
}

private void EnsureUnboundedModeSetIfSupported()
{
TrackingOriginModeFlags currentMode = m_inputSubsystem.GetTrackingOriginMode();
TrackingOriginModeFlags desiredMode = GetDesiredTrackingOriginMode(m_inputSubsystem);

if (m_requestedTrackingOriginMode == XROrigin.TrackingOriginMode.NotSpecified &&
(currentMode == TrackingOriginModeFlags.Device || currentMode == TrackingOriginModeFlags.Unbounded) &&
currentMode != desiredMode)
{
Debug.Log($"UnboundedTrackingMode: TrySetTrackingOriginMode to {desiredMode}");
if (!m_inputSubsystem.TrySetTrackingOriginMode(desiredMode))
{
Debug.LogWarning($"UnboundedTrackingMode: Failed to set tracking origin to {desiredMode}.");
}
else if (desiredMode == TrackingOriginModeFlags.Unbounded)
{
ApplyUnboundedCameraOffset();
}
}
}

/// <summary>
/// Apply the <see cref="XROrigin.CameraYOffset"/> to the transform.
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="XROrigin"/> class does not yet support "unbounded" devices, which results in
/// <see cref="XROrigin"/> failing to correctly apply the specified camera height offset for
/// "unbounded" device. This function addresses this limitation that is typically seen during
/// remoting scenarios.
/// </para>
/// <para>
/// Note, problems with the camera height offset are typically seen when using holographic
/// remoting on HoloLens.
/// </para>
/// </remarks>
private void ApplyUnboundedCameraOffset()
{
if (!Application.isPlaying)
{
return;
}

XROrigin xrOrigin = gameObject.GetComponent<XROrigin>();
if (xrOrigin != null &&
xrOrigin.CameraFloorOffsetObject != null)
{
var offsetTransform = xrOrigin.CameraFloorOffsetObject.transform;
var desiredPosition = offsetTransform.localPosition;
desiredPosition.y = xrOrigin.CameraYOffset;
offsetTransform.localPosition = desiredPosition;
}
}

private static TrackingOriginModeFlags GetDesiredTrackingOriginMode(XRInputSubsystem xrInput)
{
TrackingOriginModeFlags supportedFlags = xrInput.GetSupportedTrackingOriginModes();
TrackingOriginModeFlags targetFlag = TrackingOriginModeFlags.Device; // All OpenXR runtime must support LOCAL space

if (supportedFlags.HasFlag(TrackingOriginModeFlags.Unbounded))
{
targetFlag = TrackingOriginModeFlags.Unbounded;
}

return targetFlag;
}
#endif
}
}
11 changes: 11 additions & 0 deletions com.microsoft.mrtk.input/Tracking/UnboundedTrackingMode.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.