The Mixed Reality Forums here are no longer being used or maintained.
There are a few other places we would like to direct you to for support, both from Microsoft and from the community.
The first way we want to connect with you is our mixed reality developer program, which you can sign up for at https://aka.ms/IWantMR.
For technical questions, please use Stack Overflow, and tag your questions using either hololens or windows-mixed-reality.
If you want to join in discussions, please do so in the HoloDevelopers Slack, which you can join by going to https://aka.ms/holodevelopers, or in our Microsoft Tech Communities forums at https://techcommunity.microsoft.com/t5/mixed-reality/ct-p/MicrosoftMixedReality.
And always feel free to hit us up on Twitter @MxdRealityDev.
Creating and assigning spatial anchors
I've been trying to create, save and load HoloToolkit's WorldAnchors to GameObjects in the hololens, but can't make sense of it.
Here's what I have:
In "Start()" I first create the anchor store
void Start () { WorldAnchorStore.GetAsync(AnchorStoreReady); } WorldAnchorStore anchorStore;
When I placed a hologram using gaze, I create an anchor and save it to the store:
WorldAnchor anchor = placeObject.GetComponent<WorldAnchor>(); if (anchor == null) { anchor = placeObject.AddComponent<WorldAnchor>(); } anchorStore.Save(placeObject.name, anchor);
Next time I run, I would try and load the anchor when the anchor store is ready:
void AnchorStoreReady(WorldAnchorStore store) { anchorStore = store; LoadAnchor(); } private void LoadAnchor() { anchor = anchorStore.Load(placeObject.name, placeObject); }
The moment I do this, my gameobject 'placeObject' ends up at 0,0,0.
What piece am I missing?
Best Answers
-
OptionsPatrick mod
Hey dotMorten,
I have a feeling that what you may be missing is 'deleting' the anchor before saving the anchor with the same name again.Here's a quick script that I just tested by attaching the script to a cube with a cube collider. I can tap the cube to pick it up, and tap again to set the cube back down. When I relaunch the app, the cube is in the last place I left it. If I don't delete the old anchor from the store (the anchorStore.delete call) then the cube would stay in the first position I placed it in.
using UnityEngine; using UnityEngine.VR.WSA.Persistence; using UnityEngine.VR.WSA; public class PersistoMatic : MonoBehaviour { public string ObjectAnchorStoreName; WorldAnchorStore anchorStore; bool Placing = false; // Use this for initialization void Start () { WorldAnchorStore.GetAsync(AnchorStoreReady); } void AnchorStoreReady(WorldAnchorStore store) { anchorStore = store; Placing = true; Debug.Log("looking for " + ObjectAnchorStoreName); string[] ids = anchorStore.GetAllIds(); for (int index = 0; index < ids.Length; index++) { Debug.Log(ids[index]); if (ids[index] == ObjectAnchorStoreName) { WorldAnchor wa = anchorStore.Load(ids[index], gameObject); Placing = false; break; } } } // Update is called once per frame void Update () { if (Placing) { gameObject.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 2; } } void OnSelect() { if (anchorStore == null) { return; } if (Placing) { WorldAnchor attachingAnchor = gameObject.AddComponent<WorldAnchor>(); if (attachingAnchor.isLocated) { Debug.Log("Saving persisted position immediately"); bool saved = anchorStore.Save(ObjectAnchorStoreName, attachingAnchor); Debug.Log("saved: " + saved); } else { attachingAnchor.OnTrackingChanged += AttachingAnchor_OnTrackingChanged; } } else { WorldAnchor anchor = gameObject.GetComponent<WorldAnchor>(); if (anchor != null) { DestroyImmediate(anchor); } string[] ids = anchorStore.GetAllIds(); for (int index = 0; index < ids.Length; index++) { Debug.Log(ids[index]); if (ids[index] == ObjectAnchorStoreName) { bool deleted = anchorStore.Delete(ids[index]); Debug.Log("deleted: " + deleted); break; } } } Placing = !Placing; } private void AttachingAnchor_OnTrackingChanged(WorldAnchor self, bool located) { if (located) { Debug.Log("Saving persisted position in callback"); bool saved = anchorStore.Save(ObjectAnchorStoreName, self); Debug.Log("saved: " + saved); self.OnTrackingChanged -= AttachingAnchor_OnTrackingChanged; } } }
===
This post provided as-is with no warranties and confers no rights. Using information provided is done at own risk.(Daddy, what does 'now formatting drive C:' mean?)
5 -
Optionsneerajwadhwa mod
@dotMorten I see the confusion now. When you save the World Anchor by a name, you actually save that location. Think of this key as the filename for your anchor. If you want to associate other data with that anchor, such as a 3D model that the user placed at that location, save that to your app's local storage and associate it with the key you chose. Here's how you can save and load a world anchor.
anchor = anchorStore.Load(placeObject.name, placeObject);
// add a check after this to see if the anchor actually loaded.
// anchor.isLocation will tell you thatI would also recommend you subscribe to the anchor.OnTrackingChanged += Anchor_OnTrackingChanged; events documented here.
I am also working on a simplified version of this script in parallel with you.
5
Answers
@dotMorten is the transform position of the object you attached this script to at 0,0,0 ?
You could also refer the ImportExportAnchorManager.cs script from the HoloToolkit which does something similar.
@neerajwadhwa Well... I've tried various things. What is the correct process? If I want to move the object using gaze, I constantly update the transform while in place-mode based on the raycast hit. So do I update the transform, or do I create a world anchor first and update that?
@dotMorten we recommend that you have a gameobject which you treat as your anchor (could be a parent gameobject at 0, -0.25, 2). Have your World Anchor script on this gameobject. Then your placement hologram could be a child of the parent anchor game object and will be rendered relative to that position. And now you can move this placement hologram with your gaze. This way your anchor position will always remain constant and your holograms will render relative to that position. You could choose to show a hologram at that anchor location too but you don't have to. You placement hologram will be the one people care about and anchor will almost be invisible.
Also, we do recommend creating an anchor first.
Thanks but it's still not clear.
Let's say I want to place a hologram (1,2,3) - a location I got from the gaze hittest.
Do I just set the transform on the parent gameobject to 1,2,3, and then what do I do with the WorldAnchor? Do I just add the component, and it'll automatically know that what it's associated with is at 1,2,3?
Or do I create a world anchor and set the transform on this instead?
When I'm loading the anchor from the anchor store, how do I get it's anchor position on to the game object? Do I read it's transform and copy the transform on to the gameobject's transform, or do I just attach the loaded anchor to the gameobject? (currently when I attach a gameobject loaded from the anchor store, the gameobject jumps to (0,0,0) and ignores any transform set on it )
Any chance you have some code showing how to do this workflow?
The 'ImportExportAnchorManager.cs' is not a good example since it is throwing the anchor sharing all over it making it very confusing to dissect (but granted this is at least how I got this far - which isn't far).
@dotMorten for the specifics above and perhaps World anchor in Unity will help:
Please help me understand what exactly is your scenario if these steps don't help answer your questions.
@neerajwadhwa Thanks. This is what I'm doing:
1. use the gaze to place an object by modifying the gameobject's transform based on the gaze raycast.
2. When place is complete assign a world anchor component to it and then save the anchor to the anchor store.
3. When app is relaunched, I load the anchor and assign it back to the gameobject (not modification of the transform explicitly).
1 and 2 seems to work just fine. The problem is 3. The moment I attached the anchor I loaded from the anchor store, the gameobject jumps to (0,0,0), and not to the location I originally placed it at.
Regarding your #3 point, I assume if I want to re-place the gameobject to a new location, I should destroy the world anchor while in place mode, and then create a new one when done?
Hey dotMorten,
I have a feeling that what you may be missing is 'deleting' the anchor before saving the anchor with the same name again.
Here's a quick script that I just tested by attaching the script to a cube with a cube collider. I can tap the cube to pick it up, and tap again to set the cube back down. When I relaunch the app, the cube is in the last place I left it. If I don't delete the old anchor from the store (the anchorStore.delete call) then the cube would stay in the first position I placed it in.
===
This post provided as-is with no warranties and confers no rights. Using information provided is done at own risk.
(Daddy, what does 'now formatting drive C:' mean?)
@dotMorten I see the confusion now. When you save the World Anchor by a name, you actually save that location. Think of this key as the filename for your anchor. If you want to associate other data with that anchor, such as a 3D model that the user placed at that location, save that to your app's local storage and associate it with the key you chose. Here's how you can save and load a world anchor.
anchor = anchorStore.Load(placeObject.name, placeObject);
// add a check after this to see if the anchor actually loaded.
// anchor.isLocation will tell you that
I would also recommend you subscribe to the anchor.OnTrackingChanged += Anchor_OnTrackingChanged; events documented here.
I am also working on a simplified version of this script in parallel with you.
@dotMorten @Patrick 's script is ensuring that you delete the World Anchor that you already saved and then re-saving it when you move your placement object again. Since you cannot save the same anchor name twice in the local anchor store. Please see if you were hitting that issue.
I was trying this out in the unity editor, but for some reason
WorldAnchorStore.GetAsync(AnchorStoreReady);
never completes. Is there not a way to get the WorldAnchorStore in the Unity Editor?Stephen Hodgson
Microsoft HoloLens Agency Readiness Program
Virtual Solutions Developer at Saab
HoloToolkit-Unity Moderator
trying to save the world anchor returns a null reference error even though i have a world anchor attached to the gameobject and references as a public anchor.