Skip to content
This repository was archived by the owner on Nov 16, 2024. It is now read-only.

Commit 063ce4e

Browse files
Support for Holographic Remoting (#213)
* Make XR Anchor Manager startup async so it can wait for XR startup if necessary. Also, some minor no-op changes to suppress warnings. * Expand remoting support to pre-Unity2020. * Bump patch version to 1.5.2. * Port ARF fix back to ARF2019. * Make AlignSubtree component smarter about auto-save and load. * Update publishing files to v1.5.2.
1 parent 35f7e71 commit 063ce4e

19 files changed

Lines changed: 204 additions & 40 deletions

File tree

Assets/WorldLocking.ASA.Examples/Scripts/ScreenSpacer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private void CaptureLocalPose()
4040
}
4141

4242
[SerializeField]
43-
private MeshFilter meshFilter;
43+
private MeshFilter meshFilter = null;
4444

4545
private void Awake()
4646
{

Assets/WorldLocking.Core/Scripts/ARF/AnchorManagerARF.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,16 @@ public override Pose AnchorFromSpongy
7676

7777
protected override float TrackingStartDelayTime { get { return SpongyAnchorARF.TrackingStartDelayTime; } }
7878

79-
public static AnchorManagerARF TryCreate(IPlugin plugin, IHeadPoseTracker headTracker,
79+
public static async Task<AnchorManagerARF> TryCreate(IPlugin plugin, IHeadPoseTracker headTracker,
8080
GameObject arSessionSource,
8181
GameObject arSessionOriginSource)
8282
{
83+
bool xrRunning = await CheckXRRunning();
84+
if (!xrRunning)
85+
{
86+
Debug.LogError($"Error checking that XR is up and running.");
87+
return null;
88+
}
8389
if (arSessionSource == null)
8490
{
8591
Debug.LogError("Trying to create an AR Foundation anchor manager with null session source holder GameObject.");
@@ -116,6 +122,28 @@ public static AnchorManagerARF TryCreate(IPlugin plugin, IHeadPoseTracker headTr
116122
return anchorManager;
117123
}
118124

125+
/// <summary>
126+
/// Wait to make sure XR is up and running before proceeding. This is important when using Holographic Remoting,
127+
/// during which the delay can be significant.
128+
/// </summary>
129+
/// <returns></returns>
130+
private static async Task<bool> CheckXRRunning()
131+
{
132+
#if WLT_XR_MANAGEMENT_PRESENT
133+
DebugLogSetup($"F={Time.frameCount} checking that XR is running.");
134+
// Wait for XR initialization before initializing the anchor subsystem to ensure that any pending Remoting connection has been established first.
135+
while (UnityEngine.XR.Management.XRGeneralSettings.Instance == null ||
136+
UnityEngine.XR.Management.XRGeneralSettings.Instance.Manager == null ||
137+
UnityEngine.XR.Management.XRGeneralSettings.Instance.Manager.activeLoader == null)
138+
{
139+
DebugLogSetup($"F={Time.frameCount} waiting on XR startup.");
140+
await Task.Yield();
141+
}
142+
DebugLogSetup($"F={Time.frameCount} XR is running.");
143+
#endif // WLT_XR_MANAGEMENT_PRESENT
144+
return true;
145+
}
146+
119147
/// <summary>
120148
/// Set up an anchor manager.
121149
/// </summary>

Assets/WorldLocking.Core/Scripts/ARF/AnchorManagerARF_2019.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,16 @@ public override Pose AnchorFromSpongy
5454

5555
protected override float TrackingStartDelayTime { get { return SpongyAnchorARF.TrackingStartDelayTime; } }
5656

57-
public static AnchorManagerARF TryCreate(IPlugin plugin, IHeadPoseTracker headTracker,
57+
public static async Task<AnchorManagerARF> TryCreate(IPlugin plugin, IHeadPoseTracker headTracker,
5858
GameObject arSessionSource,
5959
GameObject arSessionOriginSource)
6060
{
61+
bool xrRunning = await CheckXRRunning();
62+
if (!xrRunning)
63+
{
64+
Debug.LogError($"Error checking that XR is up and running.");
65+
return null;
66+
}
6167
if (arSessionSource == null)
6268
{
6369
Debug.LogError("Trying to create an AR Foundation anchor manager with null session source holder GameObject.");
@@ -94,6 +100,29 @@ public static AnchorManagerARF TryCreate(IPlugin plugin, IHeadPoseTracker headTr
94100
return anchorManager;
95101
}
96102

103+
/// <summary>
104+
/// Wait to make sure XR is up and running before proceeding. This is important when using Holographic Remoting,
105+
/// during which the delay can be significant.
106+
/// </summary>
107+
/// <returns></returns>
108+
private static async Task<bool> CheckXRRunning()
109+
{
110+
#if WLT_XR_MANAGEMENT_PRESENT
111+
DebugLogSetup($"F={Time.frameCount} checking that XR is running.");
112+
// Wait for XR initialization before initializing the anchor subsystem to ensure that any pending Remoting connection has been established first.
113+
while (UnityEngine.XR.Management.XRGeneralSettings.Instance == null ||
114+
UnityEngine.XR.Management.XRGeneralSettings.Instance.Manager == null ||
115+
UnityEngine.XR.Management.XRGeneralSettings.Instance.Manager.activeLoader == null)
116+
{
117+
DebugLogSetup($"F={Time.frameCount} waiting on XR startup.");
118+
await Task.Yield();
119+
}
120+
DebugLogSetup($"F={Time.frameCount} XR is running.");
121+
#endif // WLT_XR_MANAGEMENT_PRESENT
122+
return true;
123+
}
124+
125+
97126
/// <summary>
98127
/// Set up an anchor manager.
99128
/// </summary>

Assets/WorldLocking.Core/Scripts/ARF/SpongyAnchorARF_2019.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,16 @@ public override Pose SpongyPose
8181
{
8282
get
8383
{
84-
Pose frozenFromAnchor = transform.GetGlobalPose();
85-
Pose spongyFromFrozen = WorldLockingManager.GetInstance().SpongyFromFrozen;
86-
Pose spongyFromAnchor = spongyFromFrozen.Multiply(frozenFromAnchor);
87-
return spongyFromAnchor;
84+
if (WorldLockingManager.GetInstance().ApplyAdjustment)
85+
{
86+
// Global space is frozen space. Transform into spongy space.
87+
Pose frozenFromAnchor = transform.GetGlobalPose();
88+
Pose spongyFromFrozen = WorldLockingManager.GetInstance().SpongyFromFrozen;
89+
Pose spongyFromAnchor = spongyFromFrozen.Multiply(frozenFromAnchor);
90+
return spongyFromAnchor;
91+
}
92+
// Global space is spongy space. Return global pose.
93+
return transform.GetGlobalPose();
8894
}
8995
}
9096

Assets/WorldLocking.Core/Scripts/AlignSubtree.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ private static string FixExtension(string name, string ext)
150150
/// <summary>
151151
/// Encapsulate all prerequisites for successful load here.
152152
/// </summary>
153-
private bool ReadyToAutoLoad { get { return needAutoLoad && (alignmentManager != null); } }
153+
private bool ReadyToAutoLoad { get { return needAutoLoad && (alignmentManager != null) && SupportsPersistence; } }
154154

155155
/// <summary>
156156
/// Encapsulate all prerequisites for successful save here.
@@ -159,7 +159,26 @@ private static string FixExtension(string name, string ext)
159159
/// This does not check to see if a save is actually warranted, that check is elsewhere. This
160160
/// just check whether, if it would be good to save, the system is ready to.
161161
/// </remarks>
162-
private bool ReadyToAutoSave { get { return !needAutoLoad && autoSave; } }
162+
private bool ReadyToAutoSave { get { return !needAutoLoad && autoSave && SupportsPersistence; } }
163+
164+
/// <summary>
165+
/// Check if persistence is supported, to avoid useless (and confusing) spacepin auto-save and load when anchors can't be saved and loaded.
166+
/// </summary>
167+
/// <remarks>
168+
/// This is done on demand, because at start the final anchor manager may or may not have been created yet.
169+
/// </remarks>
170+
private bool SupportsPersistence
171+
{
172+
get
173+
{
174+
var wltMgr = WorldLockingManager.GetInstance();
175+
if (wltMgr.AnchorManager != null && wltMgr.AnchorManager.SupportsPersistence)
176+
{
177+
return true;
178+
}
179+
return false;
180+
}
181+
}
163182
#endregion Internal members
164183

165184
#region Public APIs

Assets/WorldLocking.Core/Scripts/FragmentManager.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,11 @@ public FragmentManager(IPlugin plugin)
7878
public void Update(bool autoRefreeze, bool autoMerge)
7979
{
8080
CurrentFragmentId = plugin.GetMostSignificantFragmentId();
81-
Debug.Assert(CurrentFragmentId.IsKnown(), "Update shouldn't be called with no active fragment.");
81+
Debug.Assert(CurrentFragmentId.IsKnown(), $"F={Time.frameCount} - Update shouldn't be called with no active fragment.");
82+
if (!CurrentFragmentId.IsKnown())
83+
{
84+
return;
85+
}
8286
EnsureFragment(CurrentFragmentId);
8387

8488
if (plugin.Metrics.RefitRefreezeIndicated && autoRefreeze)

Assets/WorldLocking.Core/Scripts/WorldLockingManager.cs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ public Pose PlayspaceFromSpongy
303303
/// <summary>
304304
/// Keep track of whether one-time initializations have been performed yet.
305305
/// </summary>
306-
private bool hasBeenStarted = false;
306+
private enum InitializationState { Uninitialized, Starting, Running };
307+
private InitializationState initializationState = InitializationState.Uninitialized;
307308

308309
/// <summary>
309310
/// A handle of the class offering the optional feature of periodically logging the FrozenWorld engine state to disk
@@ -385,9 +386,9 @@ public void SetContext(WorldLockingContext context)
385386
shared = context.SharedSettings;
386387
DiagnosticRecordings.SharedSettings = context.DiagnosticsSettings;
387388

388-
if (!hasBeenStarted)
389+
if (initializationState == InitializationState.Uninitialized)
389390
{
390-
OneTimeStartUp();
391+
ResetAnchorManager();
391392
}
392393

393394
ApplyNewSettings();
@@ -399,9 +400,11 @@ public void SetContext(WorldLockingContext context)
399400
/// Perform any initialization only appropriate once. This is called after
400401
/// giving the caller a chance to change settings.
401402
/// </summary>
402-
private void OneTimeStartUp()
403+
public async void ResetAnchorManager()
403404
{
404-
anchorManager = SelectAnchorManager(Plugin, headPoseTracker);
405+
initializationState = InitializationState.Starting;
406+
407+
anchorManager = await SelectAnchorManager(Plugin, headPoseTracker);
405408

406409
if (AutoLoad)
407410
{
@@ -412,23 +415,23 @@ private void OneTimeStartUp()
412415
Reset();
413416
}
414417

415-
hasBeenStarted = true;
418+
initializationState = InitializationState.Running;
416419
}
417420

418-
private IAnchorManager SelectAnchorManager(IPlugin plugin, IHeadPoseTracker headTracker)
421+
private async Task<IAnchorManager> SelectAnchorManager(IPlugin plugin, IHeadPoseTracker headTracker)
419422
{
420423
DebugLogSetup($"Select {shared.anchorSettings.anchorSubsystem} anchor manager.");
421424
if (AnchorManager != null)
422425
{
423-
DebugLogSetup("Creating new anchormanager, but have old one. Reseting it before replacing.");
426+
DebugLogSetup("Creating new anchor manager, but have old one. Reseting it before replacing.");
424427
AnchorManager.Reset();
425428
}
426429
var anchorSettings = shared.anchorSettings;
427430
#if WLT_ARFOUNDATION_PRESENT
428431
if (anchorSettings.anchorSubsystem == AnchorSettings.AnchorSubsystem.ARFoundation)
429432
{
430433
DebugLogSetup($"Trying to create ARF anchor manager on {anchorSettings.ARSessionSource.name} and {anchorSettings.ARSessionOriginSource.name}");
431-
AnchorManagerARF arfAnchorManager = AnchorManagerARF.TryCreate(plugin, headTracker,
434+
AnchorManagerARF arfAnchorManager = await AnchorManagerARF.TryCreate(plugin, headTracker,
432435
anchorSettings.ARSessionSource, anchorSettings.ARSessionOriginSource);
433436
if (arfAnchorManager != null)
434437
{
@@ -442,7 +445,7 @@ private IAnchorManager SelectAnchorManager(IPlugin plugin, IHeadPoseTracker head
442445
if (anchorSettings.anchorSubsystem == AnchorSettings.AnchorSubsystem.XRSDK)
443446
{
444447
DebugLogSetup($"Trying to create XR anchor manager");
445-
AnchorManagerXR xrAnchorManager = AnchorManagerXR.TryCreate(plugin, headTracker);
448+
AnchorManagerXR xrAnchorManager = await AnchorManagerXR.TryCreate(plugin, headTracker);
446449
if (xrAnchorManager != null)
447450
{
448451
DebugLogSetup("Success creating XR anchor manager");
@@ -483,6 +486,8 @@ private IAnchorManager SelectAnchorManager(IPlugin plugin, IHeadPoseTracker head
483486
}
484487
AnchorManagerNull nullAnchorManager = AnchorManagerNull.TryCreate(plugin, headTracker);
485488
Debug.Assert(nullAnchorManager != null, "Creation of Null anchor manager should never fail.");
489+
/// No-op await here to suppress warnings if no anchor manager system which requires asynchronous startup is compiled in.
490+
await Task.CompletedTask;
486491
return nullAnchorManager;
487492
}
488493

@@ -566,6 +571,11 @@ private void Update()
566571
{
567572
ErrorStatus = "";
568573

574+
if (initializationState != InitializationState.Running)
575+
{
576+
ErrorStatus = $"Init: F={Time.frameCount} - {initializationState}";
577+
return;
578+
}
569579
if (hasPendingLoadTask)
570580
{
571581
ErrorStatus = "pending background load task";

Assets/WorldLocking.Core/Scripts/XR/AnchorManagerXR.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#endif // WLT_XR_PERSISTENCE
99

1010
//#define WLT_EXTRA_LOGGING
11+
#define WLT_LOG_SETUP
1112

1213
#if WLT_DISABLE_LOGGING
1314
#undef WLT_EXTRA_LOGGING
@@ -63,8 +64,14 @@ public partial class AnchorManagerXR : AnchorManager
6364

6465
private readonly Dictionary<TrackableId, SpongyAnchorXR> anchorsByTrackableId = new Dictionary<TrackableId, SpongyAnchorXR>();
6566

66-
public static AnchorManagerXR TryCreate(IPlugin plugin, IHeadPoseTracker headTracker)
67+
public static async Task<AnchorManagerXR> TryCreate(IPlugin plugin, IHeadPoseTracker headTracker)
6768
{
69+
bool xrRunning = await CheckXRRunning();
70+
if (!xrRunning)
71+
{
72+
return null;
73+
}
74+
6875
/// Try to find an XRAnchorManager (to be XRAnchorManager) here.
6976
/// If we fail that,
7077
/// give up.
@@ -88,6 +95,23 @@ public static AnchorManagerXR TryCreate(IPlugin plugin, IHeadPoseTracker headTra
8895
return anchorManager;
8996
}
9097

98+
private static async Task<bool> CheckXRRunning()
99+
{
100+
#if WLT_XR_MANAGEMENT_PRESENT
101+
DebugLogSetup($"F={Time.frameCount} checking that XR is running.");
102+
// Wait for XR initialization before initializing the anchor subsystem to ensure that any pending Remoting connection has been established first.
103+
while (UnityEngine.XR.Management.XRGeneralSettings.Instance == null ||
104+
UnityEngine.XR.Management.XRGeneralSettings.Instance.Manager == null ||
105+
UnityEngine.XR.Management.XRGeneralSettings.Instance.Manager.activeLoader == null)
106+
{
107+
DebugLogSetup($"F={Time.frameCount} waiting on XR startup.");
108+
await Task.Yield();
109+
}
110+
DebugLogSetup($"F={Time.frameCount} XR is running.");
111+
#endif // WLT_XR_MANAGEMENT_PRESENT
112+
return true;
113+
}
114+
91115
/// <summary>
92116
/// Find the correct AnchorManager for this session.
93117
/// </summary>
@@ -128,7 +152,7 @@ private static XRAnchorSubsystem FindAnchorManager()
128152
{
129153
activeSubsystem = sub;
130154
++numFound;
131-
DebugLogSetup($"Start changed anchor subsystem {sub.subsystemDescriptor.id} to running.");
155+
DebugLogSetup($"Start changed anchor subsystem [{sub.subsystemDescriptor.id}] to running.");
132156
}
133157
}
134158
}
@@ -172,7 +196,7 @@ private static XRSessionSubsystem FindSessionSubsystem()
172196
{
173197
activeSession = session;
174198
++numFound;
175-
DebugLogSetup($"Start changed session {session.subsystemDescriptor.id} to running.");
199+
DebugLogSetup($"Start changed session [{session.subsystemDescriptor.id}] to running.");
176200
}
177201
}
178202
}

0 commit comments

Comments
 (0)