using System.Collections; using System.Collections.Generic; using System.IO; using Unity.Collections; using UnityEngine; using UnityEngine.UI; using UnityEngine.XR.ARFoundation; #if UNITY_IOS using UnityEngine.XR.ARKit; #endif /// /// Demonstrates the saving and loading of an /// ARWorldMap /// /// /// ARWorldMaps are only supported by ARKit, so this API is in the /// UntyEngine.XR.ARKit namespace. /// public class ARWorldMapController : MonoBehaviour { [SerializeField] ARSession m_ARSession; [SerializeField] Text m_ErrorText; [SerializeField] Button m_SaveButton; [SerializeField] Button m_LoadButton; [SerializeField] Text m_LogText; [SerializeField] Text m_MappingStatus; /// /// Create an ARWorldMap and save it to disk. /// public void OnSaveButton() { #if UNITY_IOS StartCoroutine(Save()); #endif } /// /// Load an ARWorldMap from disk and apply it /// to the current session. /// public void OnLoadButton() { #if UNITY_IOS StartCoroutine(Load()); #endif } /// /// Reset the ARSession, destroying any existing trackables, /// such as planes. Upon loading a saved ARWorldMap, saved /// trackables will be restored. /// public void OnResetButton() { m_ARSession.Reset(); } #if UNITY_IOS IEnumerator Save() { var sessionSubsystem = ARSubsystemManager.sessionSubsystem; if (sessionSubsystem == null) { Log("No session subsystem available. Could not save."); yield break; } var request = sessionSubsystem.GetARWorldMapAsync(); while (!request.status.IsDone()) yield return null; if (request.status.IsError()) { Log(string.Format("Session serialization failed with status {0}", request.status)); yield break; } var worldMap = request.GetWorldMap(); request.Dispose(); SaveAndDisposeWorldMap(worldMap); } IEnumerator Load() { var sessionSubsystem = ARSubsystemManager.sessionSubsystem; if (sessionSubsystem == null) { Log("No session subsystem available. Could not load."); yield break; } var file = File.Open(path, FileMode.Open); if (file == null) { Log(string.Format("File {0} does not exist.", path)); yield break; } Log(string.Format("Reading {0}...", path)); int bytesPerFrame = 1024 * 10; var bytesRemaining = file.Length; var binaryReader = new BinaryReader(file); var allBytes = new List(); while (bytesRemaining > 0) { var bytes = binaryReader.ReadBytes(bytesPerFrame); allBytes.AddRange(bytes); bytesRemaining -= bytesPerFrame; yield return null; } var data = new NativeArray(allBytes.Count, Allocator.Temp); data.CopyFrom(allBytes.ToArray()); Log(string.Format("Deserializing to ARWorldMap...", path)); ARWorldMap worldMap; if (ARWorldMap.TryDeserialize(data, out worldMap)) data.Dispose(); if (worldMap.valid) { Log("Deserialized successfully."); } else { Debug.LogError("Data is not a valid ARWorldMap."); yield break; } Log("Apply ARWorldMap to current session."); sessionSubsystem.ApplyWorldMap(worldMap); } void SaveAndDisposeWorldMap(ARWorldMap worldMap) { Log("Serializing ARWorldMap to byte array..."); var data = worldMap.Serialize(Allocator.Temp); Log(string.Format("ARWorldMap has {0} bytes.", data.Length)); var file = File.Open(path, FileMode.Create); var writer = new BinaryWriter(file); writer.Write(data.ToArray()); writer.Close(); data.Dispose(); worldMap.Dispose(); Log(string.Format("ARWorldMap written to {0}", path)); } #endif string path { get { return Path.Combine(Application.persistentDataPath, "my_session.worldmap"); } } bool supported { get { #if UNITY_IOS var sessionSubsystem = ARSubsystemManager.sessionSubsystem; if (sessionSubsystem != null) return sessionSubsystem.WorldMapSupported(); #endif return false; } } void Awake() { m_LogMessages = new List(); } void Log(string logMessage) { m_LogMessages.Add(logMessage); } void Update() { if (supported) { m_ErrorText.gameObject.SetActive(false); m_SaveButton.gameObject.SetActive(true); m_LoadButton.gameObject.SetActive(true); m_MappingStatus.gameObject.SetActive(true); } else { m_ErrorText.gameObject.SetActive(true); m_SaveButton.gameObject.SetActive(false); m_LoadButton.gameObject.SetActive(false); m_MappingStatus.gameObject.SetActive(false); } var sessionSubsystem = ARSubsystemManager.sessionSubsystem; if (sessionSubsystem == null) return; var numLogsToShow = 20; string msg = ""; for (int i = Mathf.Max(0, m_LogMessages.Count - numLogsToShow); i < m_LogMessages.Count; ++i) { msg += m_LogMessages[i]; msg += "\n"; } m_LogText.text = msg; #if UNITY_IOS m_MappingStatus.text = string.Format("Mapping Status: {0}", sessionSubsystem.GetWorldMappingStatus()); #endif } List m_LogMessages; }