/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Diagnostics; using Meta.XR.Util; using UnityEngine; using Debug = UnityEngine.Debug; /// /// Represents a type Scene anchor. /// /// /// This component provides properties for accessing information on the Walls, Floors, and Ceiling. /// /// and associated classes are deprecated (v65), please use [MR Utility Kit](https://developer.oculus.com/documentation/unity/unity-mr-utility-kit-overview)" instead. /// [DisallowMultipleComponent] [RequireComponent(typeof(OVRSceneAnchor))] [HelpURL("https://developer.oculus.com/documentation/unity/unity-scene-use-scene-anchors/#further-scene-model-unity-components")] [Obsolete(OVRSceneManager.DeprecationMessage)] [Feature(Feature.Scene)] public class OVRSceneRoom : MonoBehaviour, IOVRSceneComponent { /// /// The representing the floor of the room. /// /// /// A room contains only a single Floor. /// public OVRScenePlane Floor { get; private set; } /// /// The representing the ceiling of the room. /// /// /// A room contains only a single Ceiling. /// public OVRScenePlane Ceiling { get; private set; } /// /// The set of representing the walls of the room. /// /// /// A room may contain a single Wall, but typically there is more than one. /// public OVRScenePlane[] Walls { get; private set; } = Array.Empty(); private OVRSceneAnchor _sceneAnchor; private OVRSceneManager _sceneManager; private Guid _uuid; internal static readonly Dictionary SceneRooms = new(); internal static readonly List SceneRoomsList = new(); private void Awake() { _sceneAnchor = GetComponent(); _sceneManager = FindAnyObjectByType(); _uuid = _sceneAnchor.Uuid; if (_sceneAnchor.Space.Valid) { ((IOVRSceneComponent)this).Initialize(); } } void IOVRSceneComponent.Initialize() { SceneRooms[_uuid] = this; SceneRoomsList.Add(this); } internal async OVRTask LoadRoom(Guid floor, Guid ceiling, Guid[] walls) { using (new OVRObjectPool.HashSetScope(out var uuids)) using (new OVRObjectPool.ListScope(out var anchors)) { uuids.Add(floor); uuids.Add(ceiling); foreach (var wall in walls) { uuids.Add(wall); } if (_sceneAnchor.Anchor.TryGetComponent(out var container)) { foreach (var uuid in container.Uuids) { uuids.Add(uuid); } } else { LogWarning($"{name} has no anchor container. Some elements may be missing."); } var result = await OVRSceneManager.FetchAnchorsAsync(uuids, anchors); if (!result) { LogError($"Failed to fetch the {uuids.Count} anchors belonging to {name}"); return false; } Log($"{name} has {anchors.Count} anchors."); using (new OVRObjectPool.ListScope(out var results)) using (new OVRObjectPool.ListScope>(out var tasks)) { foreach (var anchor in anchors) { if (anchor.TryGetComponent(out var locatable)) { tasks.Add(locatable.SetEnabledAsync(true)); } } await OVRTask.WhenAll(tasks, results); } foreach (var anchor in anchors) { if (!anchor.TryGetComponent(out var locatable) || !locatable.IsEnabled) { #if DEVELOPMENT_BUILD || UNITY_EDITOR var labels = anchor.TryGetComponent(out var component) && component.IsEnabled ? component.Labels : null; LogWarning($"Anchor {anchor}{(string.IsNullOrEmpty(labels) ? "" : $" ({labels})")} could not be localized. Ignoring."); #endif continue; } OVRPlugin.GetSpaceComponentStatus(anchor.Handle, OVRPlugin.SpaceComponentType.Bounded2D, out var bounded2dEnabled, out _); OVRPlugin.GetSpaceComponentStatus(anchor.Handle, OVRPlugin.SpaceComponentType.Bounded3D, out var bounded3dEnabled, out _); OVRPlugin.GetSpaceComponentStatus(anchor.Handle, OVRPlugin.SpaceComponentType.TriangleMesh, out var triangleMeshEnabled, out _); var isStrictly2d = bounded2dEnabled && !(bounded3dEnabled || triangleMeshEnabled); // The plane prefab is for anchors that are only 2D, i.e. they only have // a 2D component. If a volume component exists, we use a volume prefab, // else we pass null (prefab overrides may be used) var prefab = isStrictly2d ? _sceneManager.PlanePrefab : bounded3dEnabled ? _sceneManager.VolumePrefab : null; var sceneAnchor = _sceneManager.InstantiateSceneAnchor(anchor, prefab); if (sceneAnchor) { sceneAnchor.transform.parent = transform; sceneAnchor.IsTracked = true; } } bool TryGetPlane(Guid uuid, out OVRScenePlane plane) { plane = null; return OVRSceneAnchor.SceneAnchors.TryGetValue(uuid, out var sceneAnchor) && sceneAnchor.TryGetComponent(out plane); } OVRScenePlane GetPlane(Guid uuid) => TryGetPlane(uuid, out var plane) ? plane : null; Floor = GetPlane(floor); Ceiling = GetPlane(ceiling); using (new OVRObjectPool.ListScope(out var planes)) { foreach (var wall in walls) { if (TryGetPlane(wall, out var plane)) { planes.Add(plane); } } Walls = planes.ToArray(); } } return true; } private void OnDestroy() { SceneRooms.Remove(_uuid); SceneRoomsList.Remove(this); } [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] private void Log(string message) => Debug.Log($"[{nameof(OVRSceneRoom)}] {message}", gameObject); [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] private void LogWarning(string message) => Debug.LogWarning($"[{nameof(OVRSceneRoom)}] {message}", gameObject); [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] private void LogError(string message) => Debug.LogError($"[{nameof(OVRSceneRoom)}] {message}", gameObject); }