using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
///
/// This sample shows you how to listen to changes in the underlying scene.
///
/// At a given update frequency, we query all anchors in the scene and create
/// a snapshot. This is compared to a previous snapshot, and the
/// differences are logged to the console.
///
///
/// In order to create new scene items, you need to run Scene Capture, so
/// this sample will only work on-device (as PC Link does not support it).
///
/// The logic involves checking whether anchors exist in the base snapshot
/// and new snapshot. Furthermore, this sample contains the logic for
/// rooms to be compared, as the room anchor is NEW whenever a child element
/// is added or removed.
///
public class SnapshotSceneManager : MonoBehaviour
{
public float UpdateFrequencySeconds = 5;
SceneSnapshot _snapshot = new SceneSnapshot();
void Start()
{
SceneManagerHelper.RequestScenePermission();
StartCoroutine(UpdateScenePeriodically());
}
void Update()
{
if (OVRInput.GetDown(OVRInput.RawButton.A))
_ = SceneManagerHelper.RequestSceneCapture();
}
IEnumerator UpdateScenePeriodically()
{
while (true)
{
yield return new WaitForSeconds(UpdateFrequencySeconds);
UpdateScene();
}
}
async void UpdateScene()
{
// get current snapshot and compare to previous
var currentSnapshot = await LoadSceneSnapshotAsync();
var differences = await new SnapshotComparer(
_snapshot, currentSnapshot).Compare();
// inform user of changes
var sb = new StringBuilder();
if (differences.Count > 0)
{
sb.AppendLine("---- SCENE SNAPSHOT ----");
foreach (var (anchor, change) in differences)
sb.AppendLine($"{change}: {AnchorInfo(anchor)}");
Debug.Log(sb.ToString());
}
// update previous snapshot
_snapshot = currentSnapshot;
}
async Task LoadSceneSnapshotAsync()
{
// create snapshot from all rooms and their anchors
var snapshot = new SceneSnapshot();
var rooms = new List();
await OVRAnchor.FetchAnchorsAsync(rooms);
foreach (var room in rooms)
{
if (!room.TryGetComponent(out OVRAnchorContainer container))
continue;
var children = new List();
await container.FetchChildrenAsync(children);
snapshot.Anchors.Add(room);
snapshot.Anchors.AddRange(children);
}
return snapshot;
}
string AnchorInfo(OVRAnchor anchor)
{
if (anchor.TryGetComponent(out OVRRoomLayout room) && room.IsEnabled)
return $"{anchor.Uuid} - ROOM";
if (anchor.TryGetComponent(out OVRSemanticLabels labels) && labels.IsEnabled)
return $"{anchor.Uuid} - {labels.Labels}";
return $"{anchor.Uuid}";
}
///
/// A basic container class that holds a list of anchors.
/// This class could be extended to optimize the comparison
/// between snapshots (such as keeping the room-child
/// relationship, or storing the location and/or bounds)
///
class SceneSnapshot
{
public List Anchors { get; } = new List();
}
///
/// This class contains the custom logic for scene snapshot comparison.
///
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,
Changed
}
public async Task> 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)
if (!NewSnapshot.Anchors.Contains(anchor1))
changes.Add((anchor1, ChangeType.Missing));
foreach (var anchor2 in NewSnapshot.Anchors)
if (!BaseSnapshot.Anchors.Contains(anchor2))
changes.Add((anchor2, ChangeType.New));
// further custom checks
await CheckRoomChanges(changes);
return changes;
}
async Task 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.Changed)
continue;
var childAnchors = new List();
if (!await room.FetchLayoutAnchorsAsync(childAnchors))
continue;
var comparisonAnchors = change == ChangeType.New ?
BaseSnapshot.Anchors : NewSnapshot.Anchors;
foreach (var childAnchor in childAnchors)
if (comparisonAnchors.Contains(childAnchor))
changes[i] = (anchor, ChangeType.Changed);
}
}
}
}