Happy 2019 all! I know it’s a tad bit late for that…
Have been trying to post something for a long time now and finally made it happen this week. In this article, you will learn how to create anchors for your holograms.
Think of an anchor as a static location in the real world for your hologram. You’ll need these for example when you return to your app and want your hologram/object to be in the same position where you put it the last time. Or you’ll need them when you don’t want your object to move.
Of course, Microsoft does a much better job of explaining how to use these and also recommends best practices for anchors, which I found extremely useful and which avoided some costly mistakes: https://docs.microsoft.com/en-us/windows/mixed-reality/spatial-anchors
With the help of the MRTK, anchoring and de-anchoring of objects is so easy, I was quite surprised…
So what we will do is, in our example, have a GameObject (can be anything- I use a simple Cube). Attach the HandDraggable.cs script to it from the HoloToolkit so that we test the moving and non-moving when the object is anchored.
We also will use speech commands to anchor an object and remove the anchor. We will also indicate some kind of visual feedback, for instance change the color of the Cube to red when it’s anchored and green when the anchor is released again.
Let’s start off with the usual things:
1. Create a new project. I have Unity version 2018.2.13f1
2. I’m using the latest stable release of the HoloToolkit 2017.4.3.0 Import it into your project
3. Do the usual tweaks:
a. Delete the main Camera. Add the MixedRealityCameraParent.prefab in the Hierarchy. This will serve as the Main Camera
b. Change the Camera Settings to Hololens preferred:
Skybox to Solid Color
Background to 0,0,0,0
In the MixedRealityCameraManager script which is attached to the MixedRealityCamera object, change the Clear Flags value to Solid Color
Ensure that the Background Color is black
c. Go to Edit ->Project Settings -> Player -> Other Settings -> and change the Scripting Runtime version to .NET 4.x Equivalent and Scripting Backend to .Net
Make sure also that in XR Settings, Virtual Reality Supported is checked
We need both the InputManager and the DefaultCursor in the scene because we will be using HandDraggable and SpeechInput.
4. InputManager
Drag and drop the InputManager.prefab into your scene
5. DefaultCursor
Drag and drop the DefaultCursor.prefab into your scene. In the InputManager’s Inspector Settings, drag and drop the DefaultCursor into the Cursor field of the SimpleSinglePointerSelector script
d. Save the scene
Now let’s add the Cube to our project:
We will move this, anchor and de-anchor it.
Let’s go ahead and add the HandDraggable script to the Cube. I have explained this in more detail in my tutorial to move objects: https://codeholo.com/2018/05/06/move-resize-and-rotate-objects-in-your-hololens-apps/
Make sure your Cube has a collider. Because you need this to move the objects and Normally, this is existing by default when you add the Cube to the scene.
Next let’s write a simple script to do our Anchoring part:
First, we need to use the WorldAnchorManager script within the HoloToolkit. This makes our life easy. Create an empty GameObject. Rename it Managers or something similar.
I like to organize – so we will create another empty child GameObject to the Managers and call it AnchorManager. On it’s Add Component, add the WorldAnchorManager script from the MRTK to the Managers GameObject. We will also move the InputManager to the Managers just to stay further organized.
This script has certain Inspector elements. What we need to check is the PersistentAnchors checkbox- since we need our Cube to be anchored even when we exit our app and restart it.
Now come back to the Cube and we will write a simple script to execute anchoring and release when we want it to:
On the Cube, click on Add Component and add a new script. Call it AnchorScript or something relevant.
Edit this script in Visual Studio. We will write two functions – one to execute anchor and the other to release it.
First we have to reference our WorldAnchorManager in the scene. Let’s create a public variable to hold the WorldAnchorManager. The script will complain that this cannot be found, so you need to add the using directive using HoloToolkit.Unity to it.
Next we add a function AnchorIt() where we would write our code to anchor the Cube and also change it’s color to red after anchoring.
You just need to include this line:
worldAnchorManager.AttachAnchor(this.gameObject);
This will create an anchor of the name Cube in the WorldAnchorStore. This can be retrieved later automatically, even when we restart app (because we checked persistent anchors).
Include the code to change the color to red.
Now for our function to remove the anchor:
In the function (I call it ReleaseAnchor), simply call the line:
worldAnchorManager.RemoveAnchor(this.gameObject);
Include the code to change the color to green.
Now one important part:
We need to include a Start() and call AnchorIt() from there. This ensures that everytime you restart the app, the WorldAnchorStore loads the anchors of the GameObject to which you are referencing to and anchors it in the approximate position in the world space. The first time you do this, the Cube would be anchored as soon as you start the app.Just say “Release” to remove the anchor.
The complete script screenshot is shown below:
Don’t forget to now go back to the Inspector settings of the AnchorScript and add the WorldAnchorManager in the scene.
Let’s add the final part for the speech commands:
Under Managers, create an empty Child object and call it SpeechManager. To the SpeechManager, add the Speech Input Source and the Speech Input Handler. (I have explained how to use speech commands in detail in the tutorial: https://codeholo.com/2017/12/03/how-to-use-voice-input-in-hololens/)
Under the Speech Input Source, add the keywords “Anchor” and “Release“.
Under the Speech Input Handler, add the method AnchorIt() for the speech command Anchor, and the method RemoveAnchor() for the speech command Release.
Don’t forget to check the capability “Microphone” in Publishing Settings.
Before we build and deploy, let’s adjust our camera to see the cube. Let’s also make the cube slightly smaller so that we can see better. I changed the Cube scale to 0.2,0.2,0.2.
Delete the annoying TextMeshPro package before you build. (If you get the TextMeshPro error while deploying, then remove the package Unity TextMeshPro from your project and rebuild. Go to Unity->Window->Package Manager and a pop up appears.Click on TextMeshPro and Remove. While you are at it, also remove the Analytics Library, Ads and In App purchasing)
Deploy onto the HoloLens. Accept the popup which asks you to use the Microphone.
The first time you do this, the Cube would be anchored as soon as you start the app.Just say “Release” to remove the anchor.
So you should be able to first move the Cube using dragging gesture (also explained in a full tutorial https://codeholo.com/2018/05/06/move-resize-and-rotate-objects-in-your-hololens-apps/)
Then you say, “Anchor” and the Cube remains in that location and turns red. You should no longer be able to move the Cube.
Next, you should close the app and restart it. Once you restart, the Cube should be in that approximate position where you last left it. (Tip: to effectively restart the app, make sure you close the window and restart and see the “Made with Unity” splash screen)
Now say “Release”. The Cube should now turn green and be draggable again.
If you also turn on the Debugging mode, you’ll see logs in the Output where WorldanchorStore has attached and released anchors and it says whether it was successful or had a problem etc.
A video of the expected output is shown below:
That’s it! Let me know if you have any question/feedback for the Anchor example tutorial.
Errors and solutions:
Error 1: The Cube does not move
Solution: possibly missing a Collider, or Cursor or InputManager
Error 2: When you say Anchor, nothing happens.
Solution: Check if the Inspector Settings of the AnchorScript has a reference to the WorldAnchorManager in your scene.
Check if the speech commands, Anchor is added and subsequently, the method AnchorIt() is added.
Check if the capability Microphone is enabled
Hi,
i follow your instructions and unfortunately the anchorManager doesn’t work 🙁 The hand draggable work and the speech recognition too. The problem is i ‘m abble to drag the cube even if it is red so it’s supposed to be anchored.
Any ideas ?
Thank you 🙂
I said nothing i forgotten to add spatial mapping (i guess WorldAnchorManager works with) 🙂
Great Tutorial thank a lot ! 😀
Ah ok! cool, thanks for your feedback Nicolas!
Hi Nischita! Thanks for the great guide. I have a question: do you know how to make the scale of the object to be anchored persist also? I used your two handed manipulation guide to scale, rotate, and move my object and this spatial anchor guide to persistently anchor them in place. However, upon restarting my app, although the object is in the right position and rotated correctly, the scale is always reset back to its default state.
Hi Michael, interesting… try saving the scale of the object when you last manipulated it and calling that via a script when you start the app (for example in Awake method) to reset the object’s scale… The persistence is in the anchors and not the scale or any other parameters.. so it would make sense to save and retrieve them.
Dear Nischita,
In the previous tutorial on speech commands, you had recommended that if we use the 2 scripts, the “SpeechInputSource” should be attached to a Manager object, but the “SpeechInputHandler” should be attached to the object which you want to manipulate via voice commands.
Here however, both scripts are attached to the SpeechManager container object, which makes it easier to add the keywords and choose the methods, so I like it better, but I wonder if we can always do this, even though I would have thought (based on your previous recommendation) that the second script should actually be attached to the Cube.
Thanks in advance,
Hey Josh, it was just a recommendation. But you are right, I also like it if we add it to the same object. You can always do it like this. No problem.
Hi Nischita. Thank you for the tutorial. I followed all your instructions but i am able to move the cube also when it is red. I am also using Spatial Mapping and Spatial Understanding. My plan is to put the cube on a real object for example table and after indefinite time i want to find it in the same place.
Thank you in advance
Hi Falah,
What do you mean by move the cube? If you are using any of the manipulation gestures, then sure- you will be able to move it. But if you anchor it and leave it there (without any manipulation), then it will stay there. It is even more accurate if you use Spatial Mapping and Understanding.
Hi again Nischita! I was wondering if you know how to replace an object anchored at a certain location in space with another object.
Hi Michael, First, create your object which needs to replace the original object in your scene. Then you could set the original object to false and the replacing object to true. and just change the transform on the replacing object to the original object. I hope this works.
Hi Nischita,
Thank you for your complete and nice tutorials.
I would like to fix a gameObject using the room model that I have scanned previously. I have dragged/dropped my room model in the SpatialMapping inspector, so when I click on PLAY in Unity I could see my room.
So, my question is how to fix my gameObject in order that when I’ll re-lauch my app, my gameObjectwill still be at the same location.
Second question, I have followed your tutorial about WorldAnchor and when I have made PLAY, I have this error :
Trying to instantiate a second instance of singleton class WorldAnchorManager. Additional Instance was destroyed
UnityEngine.Debug:LogErrorFormat(String, Object[])
HoloToolkit.Unity.Singleton`1:Awake() (at Assets/HoloToolkit/Common/Scripts/Singleton.cs:94)
HoloToolkit.Unity.WorldAnchorManager:Awake() (at Assets/HoloToolkit/Common/Scripts/WorldAnchorManager.cs:97)
Thanks a lot for sharing your expertise,
Anelor
Hi Anelor, Regarding the fixing the GameObject in the same space, that should simply work with anchors relative to the room model. Since you are using a room model and not an actual space, maybe you need to calculate the anchors relative to the room model and the space that it has recognized as well.
Regarding the error for the WorldAnchorManager, have you destroyed the previous instance before creating a new anchor?
Thanks for the detailed post!