// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Boundary;
using Microsoft.MixedReality.Toolkit.Utilities;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
namespace Microsoft.MixedReality.Toolkit.XRSDK
{
///
/// The Boundary system controls the presentation and display of the users boundary in a scene.
///
[HelpURL("https://docs.microsoft.com/windows/mixed-reality/mrtk-unity/features/boundary/boundary-system-getting-started")]
public class XRSDKBoundarySystem : BaseBoundarySystem
{
///
/// Constructor.
///
/// The configuration profile for the service.
/// The application's configured .
public XRSDKBoundarySystem(
MixedRealityBoundaryVisualizationProfile profile,
ExperienceScale scale) : base(profile, scale)
{
}
#if UNITY_2019_3_OR_NEWER
private static readonly List XRInputSubsystems = new List();
#endif // UNITY_2019_3_OR_NEWER
#region IMixedRealityService Implementation
///
public override string Name { get; protected set; } = "XR SDK Boundary System";
#endregion IMixedRealityService Implementation
///
protected override List GetBoundaryGeometry()
{
// Get the boundary geometry.
var boundaryGeometry = new List(0);
if (XRSubsystemHelpers.InputSubsystem?.GetTrackingOriginMode() != TrackingOriginModeFlags.Floor
|| !XRSubsystemHelpers.InputSubsystem.TryGetBoundaryPoints(boundaryGeometry)
|| boundaryGeometry.Count == 0)
{
#if UNITY_2019_3_OR_NEWER
// If the "main" input subsystem doesn't have an available boundary, check the rest of them
SubsystemManager.GetInstances(XRInputSubsystems);
foreach (XRInputSubsystem xrInputSubsystem in XRInputSubsystems)
{
if (xrInputSubsystem.running
&& xrInputSubsystem.GetTrackingOriginMode() == TrackingOriginModeFlags.Floor
&& xrInputSubsystem.TryGetBoundaryPoints(boundaryGeometry)
&& boundaryGeometry.Count > 0)
{
break;
}
}
#endif // UNITY_2019_3_OR_NEWER
}
return boundaryGeometry;
}
///
/// Updates the TrackingOriginModeFlags on the XR device.
///
protected override void SetTrackingSpace()
{
TrackingOriginModeFlags trackingOriginMode;
// In current versions of Unity, there are two types of tracking spaces. For boundaries, if the scale
// is not Room or Standing, it currently maps to TrackingOriginModeFlags.Device or TrackingOriginModeFlags.Unbounded.
switch (Scale)
{
case ExperienceScale.Standing:
case ExperienceScale.Room:
trackingOriginMode = TrackingOriginModeFlags.Floor;
break;
case ExperienceScale.OrientationOnly:
case ExperienceScale.Seated:
trackingOriginMode = TrackingOriginModeFlags.Device;
break;
case ExperienceScale.World:
#if UNITY_2020_2_OR_NEWER
trackingOriginMode = TrackingOriginModeFlags.Unbounded;
#else
trackingOriginMode = TrackingOriginModeFlags.Device;
#endif // UNITY_2020_2_OR_NEWER
break;
default:
trackingOriginMode = TrackingOriginModeFlags.Device;
Debug.LogWarning("Unknown / unsupported ExperienceScale. Defaulting to Device tracking space.");
break;
}
if (TrySetTrackingOriginModeOnAllXRInputSystems(trackingOriginMode))
{
return;
}
#if UNITY_2020_2_OR_NEWER
// If Unbounded couldn't be set, try falling back to Device
else if (trackingOriginMode == TrackingOriginModeFlags.Unbounded && TrySetTrackingOriginModeOnAllXRInputSystems(TrackingOriginModeFlags.Device))
{
return;
}
#endif // UNITY_2020_2_OR_NEWER
Debug.LogWarning("Tracking origin unable to be set.");
}
private bool TrySetTrackingOriginModeOnAllXRInputSystems(TrackingOriginModeFlags trackingOriginMode)
{
if (XRSubsystemHelpers.InputSubsystem != null && XRSubsystemHelpers.InputSubsystem.TrySetTrackingOriginMode(trackingOriginMode))
{
return true;
}
#if UNITY_2019_3_OR_NEWER
// If the "main" input subsystem can't set the origin mode, check the rest of them
SubsystemManager.GetInstances(XRInputSubsystems);
foreach (XRInputSubsystem xrInputSubsystem in XRInputSubsystems)
{
if (xrInputSubsystem.running && xrInputSubsystem.TrySetTrackingOriginMode(trackingOriginMode))
{
return true;
}
}
#endif // UNITY_2019_3_OR_NEWER
return false;
}
}
}