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

Commit 3777fd9

Browse files
Support local world locking (#202)
* Up-port local application of base world locking to subgraph in scene hierarchy from Samples/AlignSubtree. * Update UPM generation files for version 1.5.0. * Don't modify the camera hierarchy if adjustments aren't being applied by the WLT.
1 parent 38ee794 commit 3777fd9

23 files changed

Lines changed: 296 additions & 58 deletions

Assets/WorldLocking.Core/Editor/WorldLockingContextEditor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ public override void OnInspectorGUI()
7676
{
7777
using (new EditorGUI.IndentLevelScope())
7878
{
79+
AddProperty(mgrPath, "applyAdjustment");
80+
7981
AddProperty(mgrPath, "AdjustmentFrame");
8082

8183
AddProperty(mgrPath, "CameraParent");

Assets/WorldLocking.Core/Scripts/AlignSubtree.cs

Lines changed: 123 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

4+
//#define WLT_LOG_SAVE_LOAD
5+
46
using System;
57
using System.Collections;
68
using System.Collections.Generic;
@@ -40,6 +42,27 @@ public class AlignSubtree : MonoBehaviour
4042
/// </summary>
4143
public bool CollectFromTree { get { return collectFromTree; } set { collectFromTree = value; } }
4244

45+
[SerializeField]
46+
[Tooltip("Optional orienter for implicit orientation SpacePins. If null, will search for it in subtree.")]
47+
private Orienter orienter;
48+
49+
private IOrienter iorienter = null;
50+
/// <summary>
51+
/// Optional orienter for implicit orientation SpacePins. If null, will search for it in subtree.
52+
/// </summary>
53+
public IOrienter Orienter
54+
{
55+
get
56+
{
57+
return orienter == null ? iorienter : orienter;
58+
}
59+
set
60+
{
61+
iorienter = value;
62+
orienter = null;
63+
}
64+
}
65+
4366
[SerializeField]
4467
[Tooltip("Explicit list of Space Pins to manage.")]
4568
private List<SpacePin> ownedPins = new List<SpacePin>();
@@ -108,8 +131,31 @@ private static string FixExtension(string name, string ext)
108131
/// </summary>
109132
public AlignmentManager AlignmentManager => alignmentManager;
110133

111-
private bool needLoad = false;
134+
/// <summary>
135+
/// Flag saying that, when ready, we want to try to load persisted spacepins.
136+
/// </summary>
137+
private bool needAutoLoad = false;
138+
139+
private bool autoSave = false;
140+
141+
/// <summary>
142+
/// When the number of saved pins changes (usually increases), then we need to save.
143+
/// </summary>
144+
private int numSavedPins = 0;
145+
146+
/// <summary>
147+
/// Encapsulate all prerequisites for successful load here.
148+
/// </summary>
149+
private bool ReadyToAutoLoad { get { return needAutoLoad && (alignmentManager != null); } }
112150

151+
/// <summary>
152+
/// Encapsulate all prerequisites for successful save here.
153+
/// </summary>
154+
/// <remarks>
155+
/// This does not check to see if a save is actually warranted, that check is elsewhere. This
156+
/// just check whether, if it would be good to save, the system is ready to.
157+
/// </remarks>
158+
private bool ReadyToAutoSave { get { return !needAutoLoad && autoSave; } }
113159
#endregion Internal members
114160

115161
#region Public APIs
@@ -120,6 +166,7 @@ private static string FixExtension(string name, string ext)
120166
/// <returns>True on successful save.</returns>
121167
public bool Save()
122168
{
169+
DebugLogSaveLoad($"Subtree {name} Save {(alignmentManager == null ? "a=null" : "a=good")}");
123170
if (alignmentManager != null)
124171
{
125172
return alignmentManager.Save();
@@ -133,6 +180,7 @@ public bool Save()
133180
/// <returns>True on successful load.</returns>
134181
public bool Load()
135182
{
183+
DebugLogSaveLoad($"Subtree {name} Load {(alignmentManager == null ? "a=null" : "a=good")}");
136184
if (alignmentManager != null)
137185
{
138186
return alignmentManager.Load();
@@ -208,6 +256,16 @@ public void ClaimPinOwnership()
208256

209257
#endregion Public APIs
210258

259+
#region Internal utilility
260+
261+
private static void DebugLogSaveLoad(string message)
262+
{
263+
#if WLT_LOG_SAVE_LOAD
264+
Debug.Log($"F={Time.frameCount} {message}");
265+
#endif // WLT_LOG_SAVE_LOAD
266+
}
267+
#endregion // Internal utility
268+
211269
#region Internal AlignmentManager management
212270
/// <summary>
213271
/// Create the alignmentManager if needed.
@@ -231,6 +289,15 @@ private void CheckInternalWiring()
231289
{
232290
subTree = transform;
233291
}
292+
if (orienter == null)
293+
{
294+
orienter = GetComponentInChildren<Orienter>();
295+
Debug.Log($"No Orienter found on {name}, implicit Orienter found in subtree is {(orienter == null ? "null" : orienter.name)}");
296+
}
297+
if (Orienter != null)
298+
{
299+
Orienter.AlignmentManager = alignmentManager;
300+
}
234301
}
235302

236303
/// <summary>
@@ -239,7 +306,9 @@ private void CheckInternalWiring()
239306
private void Start()
240307
{
241308
CheckInternalWiring();
242-
needLoad = WorldLockingManager.GetInstance().AutoLoad;
309+
needAutoLoad = WorldLockingManager.GetInstance().AutoLoad;
310+
autoSave = WorldLockingManager.GetInstance().AutoSave;
311+
DebugLogSaveLoad($"Subtree {name} Start");
243312
}
244313

245314
/// <summary>
@@ -249,7 +318,7 @@ private void Update()
249318
{
250319
Debug.Assert(alignmentManager != null);
251320

252-
CheckLoad();
321+
CheckAutoLoad();
253322

254323
var wltMgr = WorldLockingManager.GetInstance();
255324
Debug.Assert(alignmentManager != wltMgr.AlignmentManager);
@@ -259,14 +328,60 @@ private void Update()
259328
var pinnedFromLocked = alignmentManager.PinnedFromLocked;
260329
var lockedFromPinned = pinnedFromLocked.Inverse();
261330

262-
subTree.SetGlobalPose(lockedFromPinned);
331+
if (wltMgr.ApplyAdjustment)
332+
{
333+
subTree.SetGlobalPose(lockedFromPinned);
334+
}
335+
else
336+
{
337+
var spongyFromLocked = wltMgr.SpongyFromLocked;
338+
var pinnedFromFrozen = wltMgr.PinnedFromFrozen;
339+
340+
var spongyFromFrozen = spongyFromLocked.Multiply(lockedFromPinned).Multiply(pinnedFromFrozen);
341+
subTree.SetGlobalPose(spongyFromFrozen);
342+
}
343+
344+
CheckAutoSave();
345+
}
346+
347+
/// <summary>
348+
/// Go through owned space pins and count how many are active.
349+
/// </summary>
350+
/// <returns>Number of owned active space pins.</returns>
351+
private int CountActivePins()
352+
{
353+
int numActive = 0;
354+
for (int i = 0; i < ownedPins.Count; ++i)
355+
{
356+
if (ownedPins[i].PinActive)
357+
{
358+
numActive++;
359+
}
360+
}
361+
return numActive;
362+
}
363+
364+
/// <summary>
365+
/// See if conditions are right for performing a save.
366+
/// </summary>
367+
private void CheckAutoSave()
368+
{
369+
if (ReadyToAutoSave)
370+
{
371+
int numActive = CountActivePins();
372+
if (numActive != numSavedPins)
373+
{
374+
Save();
375+
numSavedPins = numActive;
376+
}
377+
}
263378
}
264379

265-
private void CheckLoad()
380+
private void CheckAutoLoad()
266381
{
267-
if (needLoad)
382+
if (ReadyToAutoLoad)
268383
{
269-
needLoad = false;
384+
needAutoLoad = false;
270385
Load();
271386
}
272387
}
@@ -279,6 +394,7 @@ private void CheckLoad()
279394
private void OnEnable()
280395
{
281396
ClaimPinOwnership();
397+
DebugLogSaveLoad($"Subtree {name} OnEnable");
282398
}
283399

284400
#endregion Internal AlignmentManager management

Assets/WorldLocking.Core/Scripts/AlignmentManager.cs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

4-
//#define EXTRA_DEBUGGING
4+
//#define WLT_NAN_EXTRA_DEBUGGING
5+
//#define WLT_LOG_SAVE_LOAD
56

67
using System;
78
using System.Collections.Generic;
@@ -645,9 +646,11 @@ private string GetPersistentFileName()
645646
/// <returns>True if successfully saved.</returns>
646647
private bool Save(Stream stream)
647648
{
649+
DebugLogSaveLoad($"Enter save {SaveFileName}");
648650
bool saved = false;
649651
using (BinaryWriter writer = new BinaryWriter(stream))
650652
{
653+
DebugLogSaveLoad($"Saving {SaveFileName} v={version} c={data.Count}");
651654
writer.Write((uint)version);
652655
writer.Write((int)data.Count);
653656
foreach (var keyVal in data)
@@ -671,6 +674,7 @@ private bool Save(Stream stream)
671674
/// </remarks>
672675
private bool Load(Stream stream)
673676
{
677+
DebugLogSaveLoad($"Enter load {SaveFileName}");
674678
data.Clear();
675679
bool loaded = false;
676680
using (BinaryReader reader = new BinaryReader(stream))
@@ -679,6 +683,7 @@ private bool Load(Stream stream)
679683
if (v == version)
680684
{
681685
int count = reader.ReadInt32();
686+
DebugLogSaveLoad($"Loading {SaveFileName} v={version} c={count}");
682687
for (int i = 0; i < count; ++i)
683688
{
684689
string name = reader.ReadString();
@@ -947,6 +952,7 @@ private static FragmentId CurrentFragmentId
947952

948953
private void ActivateCurrentFragment()
949954
{
955+
DebugLogSaveLoad($"Active fragment from {ActiveFragmentId.FormatStr()} to {CurrentFragmentId.FormatStr()}");
950956
activePoses.Clear();
951957
for (int i = 0; i < sentPoses.Count; ++i)
952958
{
@@ -979,12 +985,20 @@ private void OnRefit(FragmentId mainId, FragmentId[] absorbedIds)
979985

980986
#region Persistence synchronizations
981987

988+
private static void DebugLogSaveLoad(string message)
989+
{
990+
#if WLT_LOG_SAVE_LOAD
991+
Debug.Log($"F={Time.frameCount}: {message}");
992+
#endif // WLT_LOG_SAVE_LOAD
993+
}
994+
982995
/// <summary>
983996
/// Add to queue for being saved to database next chance.
984997
/// </summary>
985998
/// <param name="refPose"></param>
986999
private void QueueForSave(ReferencePose refPose)
9871000
{
1001+
DebugLogSaveLoad($"QueueForSave {SaveFileName}");
9881002
int idx = FindReferencePoseById(referencePosesToSave, refPose.anchorId);
9891003
if (idx < 0)
9901004
{
@@ -999,6 +1013,7 @@ private void CheckSave()
9991013
{
10001014
if (referencePosesToSave.Count > 0)
10011015
{
1016+
DebugLogSaveLoad($"{SaveFileName} has {referencePosesToSave.Count} to save");
10021017
for (int i = referencePosesToSave.Count - 1; i >= 0; --i)
10031018
{
10041019
poseDB.Set(referencePosesToSave[i]);
@@ -1033,6 +1048,7 @@ private void CheckFragment()
10331048
{
10341049
if (!referencePoses[i].fragmentId.IsKnown())
10351050
{
1051+
DebugLogSaveLoad($"Transfer {referencePoses[i].anchorId.FormatStr()} from frag={referencePoses[i].fragmentId.FormatStr()} to {fragmentId.FormatStr()}");
10361052
referencePoses[i].fragmentId = fragmentId;
10371053
changed = true;
10381054
}
@@ -1095,19 +1111,19 @@ private static WeightedPose WeightedAverage(WeightedPose lhs, WeightedPose rhs)
10951111
};
10961112
}
10971113
float interp = rhs.weight / (lhs.weight + rhs.weight);
1098-
#if EXTRA_DEBUGGING
1114+
#if WLT_NAN_EXTRA_DEBUGGING
10991115
if (float.IsNaN(interp))
11001116
{
11011117
Debug.LogError("Interp NAN");
11021118
}
1103-
#endif // EXTRA_DEBUGGING
1119+
#endif // WLT_NAN_EXTRA_DEBUGGING
11041120

11051121
WeightedPose ret;
11061122
ret.pose.position = lhs.pose.position + interp * (rhs.pose.position - lhs.pose.position);
11071123
ret.pose.rotation = Quaternion.Slerp(lhs.pose.rotation, rhs.pose.rotation, interp);
11081124
ret.pose.rotation = Quaternion.Normalize(ret.pose.rotation);
11091125
ret.weight = lhs.weight + rhs.weight;
1110-
#if EXTRA_DEBUGGING
1126+
#if WLT_NAN_EXTRA_DEBUGGING
11111127
if (float.IsNaN(ret.pose.position.x))
11121128
{
11131129
Debug.LogError("Position NAN");
@@ -1116,7 +1132,7 @@ private static WeightedPose WeightedAverage(WeightedPose lhs, WeightedPose rhs)
11161132
{
11171133
Debug.LogError("Weight NAN");
11181134
}
1119-
#endif // EXTRA_DEBUGGING
1135+
#endif // WLT_NAN_EXTRA_DEBUGGING
11201136

11211137
return ret;
11221138
}

Assets/WorldLocking.Core/Scripts/IOrienter.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ public interface IOrientable
4949
/// </summary>
5050
public interface IOrienter
5151
{
52+
/// <summary>
53+
/// Optional subtree alignment manager.
54+
/// </summary>
55+
/// <remarks>
56+
/// If unset, will use global alignment manager, ie WorldLockingManager.GetInstance().AlignmentManager.
57+
/// </remarks>
58+
IAlignmentManager AlignmentManager { get; set; }
59+
5260
/// <summary>
5361
/// Add this orientable to the list to be both source of rotation computation, and targets to apply the computed rotation.
5462
/// </summary>

Assets/WorldLocking.Core/Scripts/LinkageSettings.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ public bool UseExisting
3737
}
3838
}
3939

40+
[SerializeField]
41+
[Tooltip("Apply world locking adjustment to the AdjustmentFrame.")]
42+
private bool applyAdjustment;
43+
44+
/// <summary>
45+
/// Apply world locking adjustment to the AdjustmentFrame.
46+
/// </summary>
47+
/// <remarks>
48+
/// If this is false, then it is up to the application to apply the correction.
49+
/// This allows the correction to be applied selectively to subsets of the scene hierarchy.
50+
/// </remarks>
51+
public bool ApplyAdjustment { get { return applyAdjustment; } set { applyAdjustment = value; } }
52+
4053
/// <summary>
4154
/// The transform at which to apply the camera adjustment. This can't be the camera node, as its
4255
/// transform is overwritten every frame with head pose data. But the camera should be an attached
@@ -58,6 +71,7 @@ public bool UseExisting
5871
/// </summary>
5972
public void InitToDefaults()
6073
{
74+
ApplyAdjustment = true;
6175
AdjustmentFrame = null;
6276
CameraParent = null;
6377
}

0 commit comments

Comments
 (0)