// 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; } } }