188 lines
7.2 KiB
C#
188 lines
7.2 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
|
|
// This namespace contains helper classes for the DynamicSceneManager.
|
|
namespace DynamicSceneManagerHelper
|
|
{
|
|
/// <summary>
|
|
/// A class that holds a list of anchors, along with data that
|
|
/// can be used to identify when a change has occured.
|
|
/// </summary>
|
|
class SceneSnapshot
|
|
{
|
|
public class Data
|
|
{
|
|
public List<OVRAnchor> Children;
|
|
public Rect? Rect;
|
|
public Bounds? Bounds;
|
|
}
|
|
public Dictionary<OVRAnchor, Data> Anchors { get; } = new Dictionary<OVRAnchor, Data>();
|
|
public bool Contains(OVRAnchor anchor) => Anchors.ContainsKey(anchor);
|
|
}
|
|
|
|
/// <summary>
|
|
/// This class contains the custom logic for scene snapshot comparison.
|
|
/// </summary>
|
|
class SnapshotComparer
|
|
{
|
|
public SceneSnapshot BaseSnapshot { get; }
|
|
public SceneSnapshot NewSnapshot { get; }
|
|
|
|
public SnapshotComparer(SceneSnapshot baseSnapshot, SceneSnapshot newSnapshot)
|
|
{
|
|
BaseSnapshot = baseSnapshot;
|
|
NewSnapshot = newSnapshot;
|
|
}
|
|
|
|
public enum ChangeType
|
|
{
|
|
New,
|
|
Missing,
|
|
ChangedId,
|
|
ChangedBounds
|
|
}
|
|
|
|
public List<(OVRAnchor, ChangeType)> Compare()
|
|
{
|
|
var changes = new List<(OVRAnchor, ChangeType)>();
|
|
|
|
// if in base but not in new, then missing
|
|
// if in new but not in base, then new
|
|
foreach (var anchor1 in BaseSnapshot.Anchors.Keys)
|
|
if (!NewSnapshot.Contains(anchor1))
|
|
changes.Add((anchor1, ChangeType.Missing));
|
|
foreach (var anchor2 in NewSnapshot.Anchors.Keys)
|
|
if (!BaseSnapshot.Contains(anchor2))
|
|
changes.Add((anchor2, ChangeType.New));
|
|
|
|
// further checks
|
|
CheckRoomChanges(changes);
|
|
CheckBoundsChanges(changes);
|
|
|
|
return changes;
|
|
}
|
|
|
|
void CheckRoomChanges(List<(OVRAnchor, ChangeType)> changes)
|
|
{
|
|
// a room with new/deleted/edited child anchors is considered
|
|
// a NEW anchor, so we will check if any child elements are
|
|
// the same and mark both old and new room anchors as CHANGED
|
|
for (var i = 0; i < changes.Count; i++)
|
|
{
|
|
var (anchor, change) = changes[i];
|
|
|
|
var isRoom = anchor.TryGetComponent(out OVRRoomLayout room) && room.IsEnabled;
|
|
if (!isRoom || change == ChangeType.ChangedId)
|
|
continue;
|
|
|
|
var isNewAnchor = NewSnapshot.Contains(anchor);
|
|
var isOldAnchor = BaseSnapshot.Contains(anchor);
|
|
if (!isNewAnchor && !isOldAnchor)
|
|
continue;
|
|
|
|
var children = isNewAnchor ?
|
|
NewSnapshot.Anchors[anchor].Children :
|
|
BaseSnapshot.Anchors[anchor].Children;
|
|
var comparisonSnapshot = change == ChangeType.New ?
|
|
BaseSnapshot : NewSnapshot;
|
|
|
|
foreach (var child in children)
|
|
if (comparisonSnapshot.Contains(child))
|
|
changes[i] = (anchor, ChangeType.ChangedId);
|
|
}
|
|
}
|
|
|
|
void CheckBoundsChanges(List<(OVRAnchor, ChangeType)> changes)
|
|
{
|
|
// first match pairs of base and new snapshots
|
|
foreach (var baseAnchor in BaseSnapshot.Anchors.Keys)
|
|
{
|
|
var newAnchor = NewSnapshot.Anchors.Keys.FirstOrDefault(
|
|
newAnchor => newAnchor.Uuid == baseAnchor.Uuid);
|
|
|
|
// we have a pair, now compare bounds data
|
|
if (newAnchor.Uuid == baseAnchor.Uuid)
|
|
{
|
|
var baseData = BaseSnapshot.Anchors[baseAnchor];
|
|
var newData = NewSnapshot.Anchors[newAnchor];
|
|
|
|
var changed2DBounds = Has2DBounds(baseData, newData) && Are2DBoundsDifferent(baseData, newData);
|
|
var changed3DBounds = Has3DBounds(baseData, newData) && Are3DBoundsDifferent(baseData, newData);
|
|
|
|
if (changed2DBounds || changed3DBounds)
|
|
changes.Add((baseAnchor, ChangeType.ChangedBounds));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Has2DBounds(SceneSnapshot.Data data1, SceneSnapshot.Data data2)
|
|
=> data1.Rect.HasValue && data2.Rect.HasValue;
|
|
bool Are2DBoundsDifferent(SceneSnapshot.Data data1, SceneSnapshot.Data data2)
|
|
=> data1.Rect?.min != data2.Rect?.min || data1.Rect?.max != data2.Rect?.max;
|
|
bool Has3DBounds(SceneSnapshot.Data data1, SceneSnapshot.Data data2)
|
|
=> data1.Bounds.HasValue && data2.Bounds.HasValue;
|
|
bool Are3DBoundsDifferent(SceneSnapshot.Data data1, SceneSnapshot.Data data2)
|
|
=> data1.Bounds?.min != data2.Bounds?.min || data1.Bounds?.max != data2.Bounds?.max;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This class wraps the logic for interacting with Unity
|
|
/// game objects.
|
|
/// </summary>
|
|
class UnityObjectUpdater
|
|
{
|
|
public async Task<GameObject> CreateUnityObject(OVRAnchor anchor, GameObject parent)
|
|
{
|
|
// if this is a room, we only need to make a GameObject
|
|
if (anchor.TryGetComponent(out OVRRoomLayout _))
|
|
return new GameObject($"Room-{anchor.Uuid}");
|
|
|
|
// only interested in the anchors which are locatable
|
|
if (!anchor.TryGetComponent(out OVRLocatable locatable))
|
|
return null;
|
|
await locatable.SetEnabledAsync(true);
|
|
|
|
// get semantic classification for object name
|
|
var label = "other";
|
|
if (anchor.TryGetComponent(out OVRSemanticLabels labels))
|
|
label = labels.Labels;
|
|
|
|
// create and parent Unity game object if possible
|
|
var gameObject = new GameObject(label);
|
|
if (parent != null)
|
|
gameObject.transform.SetParent(parent.transform);
|
|
|
|
// set location and create objects for 2D, 3D, triangle mesh
|
|
var helper = new SceneManagerHelper(gameObject);
|
|
helper.SetLocation(locatable);
|
|
|
|
if (anchor.TryGetComponent(out OVRBounded2D b2d) && b2d.IsEnabled)
|
|
helper.CreatePlane(b2d);
|
|
if (anchor.TryGetComponent(out OVRBounded3D b3d) && b3d.IsEnabled)
|
|
helper.CreateVolume(b3d);
|
|
if (anchor.TryGetComponent(out OVRTriangleMesh mesh) && mesh.IsEnabled)
|
|
helper.CreateMesh(mesh);
|
|
return gameObject;
|
|
}
|
|
|
|
public void UpdateUnityObject(OVRAnchor anchor, GameObject gameObject)
|
|
{
|
|
var helper = new SceneManagerHelper(gameObject);
|
|
if (anchor.TryGetComponent(out OVRLocatable locatable))
|
|
helper.SetLocation(locatable);
|
|
if (anchor.TryGetComponent(out OVRBounded2D b2d) && b2d.IsEnabled)
|
|
helper.UpdatePlane(b2d);
|
|
if (anchor.TryGetComponent(out OVRBounded3D b3d) && b3d.IsEnabled)
|
|
helper.UpdateVolume(b3d);
|
|
if (anchor.TryGetComponent(out OVRTriangleMesh mesh) && mesh.IsEnabled)
|
|
helper.UpdateMesh(mesh);
|
|
}
|
|
}
|
|
|
|
static class ObjectPool
|
|
{
|
|
}
|
|
}
|