I am working on implementing Spatial Anchors in my app. I used this tutorial: Meta Quest Spatial Anchors Tutorial
In the tutorial he only shows how to spawn, save and load one prefab, but my app needs different prefabs.
I have figured out how to spawn in different prefabs with a Spatial Anchor component, but the saving is the thing I can’t figure out.
I have tried to find other tutorials, but they all only save one prefab.
Any ideas on how to do that or where to find more information on this?
Thank you in advance.
Anchor Loader script:
using System;
using UnityEngine;
public class AnchorLoader : MonoBehaviour
{
private SpatialAnchorManager spatialAnchorManager;
[SerializeField]
private OVRSpatialAnchor anchorPrefab;
Action<OVRSpatialAnchor.UnboundAnchor, bool> _onLoadAnchor;
void Start() {
spatialAnchorManager = GetComponent<SpatialAnchorManager>();
_onLoadAnchor = OnLocalized;
}
public void LoadAnchorsByUuid() {
if (!PlayerPrefs.HasKey(SpatialAnchorManager.NumUuidsPlayerPref)) {
PlayerPrefs.SetInt(SpatialAnchorManager.NumUuidsPlayerPref, 0);
}
var playerUuidCount = PlayerPrefs.GetInt(SpatialAnchorManager.NumUuidsPlayerPref);
if (playerUuidCount == 0) {
Debug.Log("No anchors to load");
return;
}
var uuids = new Guid[playerUuidCount];
for (int i = 0; i < playerUuidCount; i++) {
var uuidKey = "uuid" + i;
var currentUuid = PlayerPrefs.GetString(uuidKey);
uuids[i] = new Guid(currentUuid);
}
Load(new OVRSpatialAnchor.LoadOptions {
Timeout = 0,
StorageLocation = OVRSpace.StorageLocation.Local,
Uuids = uuids
});
Debug.Log("Load Anchors by UUID method called");
}
private async void Load(OVRSpatialAnchor.LoadOptions options) {
var anchors = await OVRSpatialAnchor.LoadUnboundAnchorsAsync(options);
if (anchors == null) {
return;
}
foreach (var anchor in anchors) {
if (anchor.Localized) {
_onLoadAnchor(anchor, true);
} else if (!anchor.Localizing) {
var result = await anchor.LocalizeAsync();
_onLoadAnchor(anchor, result);
}
}
}
private void OnLocalized(OVRSpatialAnchor.UnboundAnchor unboundAnchor, bool success) {
OVRSpatialAnchor prefab;
if (spatialAnchorManager.GetAnchorPrefab() == null) {
prefab = anchorPrefab;
} else {
prefab = spatialAnchorManager.GetAnchorPrefab();
}
if (!success) return;
var pose = unboundAnchor.Pose;
var spatialAnchor = Instantiate(prefab, pose.position, pose.rotation);
unboundAnchor.BindTo(spatialAnchor);
Debug.Log("Localized anchor with UUID: " + spatialAnchor.Uuid);
}
}
Spatial Anchor Manager script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpatialAnchorManager : MonoBehaviour
{
public static SpatialAnchorManager instance;
private OVRSpatialAnchor anchorPrefab;
public const string NumUuidsPlayerPref = "numUuids";
[SerializeField]
private List<GameObject> spatialAnchorPrefabs;
private List<OVRSpatialAnchor> anchors = new List<OVRSpatialAnchor>();
private OVRSpatialAnchor lastCreatedAnchor;
private AnchorLoader anchorLoader;
void Awake() {
if (instance == null) {
instance = this;
}
}
void Start() {
anchorLoader = GetComponent<AnchorLoader>();
LoadSavedAnchors();
}
public void CreateSpatialAnchor(int prefabIndex) {
var position = new Vector3(OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch).x, 0, OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch).z);
var rotation = Quaternion.Euler(0, OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTouch).eulerAngles.y, 0);
GameObject instance = Instantiate(spatialAnchorPrefabs[prefabIndex], position, rotation);
anchorPrefab = instance.AddComponent<OVRSpatialAnchor>();
StartCoroutine(AnchorCreated(anchorPrefab));
}
private IEnumerator AnchorCreated(OVRSpatialAnchor workingAnchor) {
while (!workingAnchor.Created && !workingAnchor.Localized) {
yield return new WaitForEndOfFrame();
}
Guid anchorGuid = workingAnchor.Uuid;
anchors.Add(workingAnchor);
lastCreatedAnchor = workingAnchor;
Debug.Log("Created anchor with UUID: " + anchorGuid);
}
public async void SaveLastCreatedAnchor() {
if (lastCreatedAnchor == null) {
Debug.Log("No anchor to save");
return;
}
var success = await lastCreatedAnchor.SaveAsync();
if (success) {
Debug.Log("Saved anchor with UUID: " + lastCreatedAnchor.Uuid);
} else {
Debug.Log("Failed to save anchor");
}
SaveUuidToPlayerPrefs(lastCreatedAnchor.Uuid);
}
void SaveUuidToPlayerPrefs(Guid uuid) {
if (!PlayerPrefs.HasKey(NumUuidsPlayerPref)) {
PlayerPrefs.SetInt(NumUuidsPlayerPref, 0);
}
int playerNumUuids = PlayerPrefs.GetInt(NumUuidsPlayerPref);
PlayerPrefs.SetString("uuid" + playerNumUuids, uuid.ToString());
}
public async void UnSaveLastCreatedAnchor() {
var success = await lastCreatedAnchor.EraseAsync();
if (success) {
Debug.Log("Unsaved anchor with UUID: " + lastCreatedAnchor.Uuid);
Destroy(lastCreatedAnchor.gameObject);
} else {
Debug.Log("Failed to unsave anchor");
}
}
public void UnsaveAllAnchors() {
foreach (var anchor in anchors) {
UnsaveAnchor(anchor);
}
anchors.Clear();
ClearAllUuidsFromPlayerPrefs();
Debug.Log("Unsaved all anchors method called");
}
private async void UnsaveAnchor(OVRSpatialAnchor anchor) {
await anchor.EraseAsync();
Debug.Log("Unsaved anchor with UUID: " + anchor.Uuid);
}
private void ClearAllUuidsFromPlayerPrefs() {
if (PlayerPrefs.HasKey(NumUuidsPlayerPref)) {
int playerNumUuids = PlayerPrefs.GetInt(NumUuidsPlayerPref);
for (int i = 0; i < playerNumUuids; i++) {
PlayerPrefs.DeleteKey("uuid" + i);
}
PlayerPrefs.DeleteKey(NumUuidsPlayerPref);
PlayerPrefs.Save();
}
}
public void LoadSavedAnchors() {
anchorLoader.LoadAnchorsByUuid();
}
public OVRSpatialAnchor GetAnchorPrefab() {
return anchorPrefab;
}
}