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