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.
How to Share and Update GameObject Transforms over multiple Hololens on a Sharing Service?

Hello, I am a Unity Programmer and I am having a very difficult time with Updating transforms for game objects between multiple Hololens over the sharing service/network.
I have managed to get the generic sharing prefab and network service working on my own project and I have also applied the remote head manager successfully which creates a primitive cube and updates its transform across multiple Hololens. I even have SpatialMapping and tap to place working as well.
I now want to take my own custom game objects from within the app, place them on a wall or floor and have them update their location on other headsets.
I've Searched through the Question and Answers as well as the forums on both this and Unity's site. I have re-watched Hololens academy multiple times including 240 sharing. But the issue of updating transforms of game objects within an app hasn't been brought up but once back in July.
I am not trying to use Photon or Unet unless i absolutely have to as i would like to keep this as simple to follow as possible.
and As for trying to read how the custom message can be altered, i'm not sure I have enough networking background to figure it out on my own. would anyone be able to help me figure this out?
Best Answers
-
Patrick mod
I can help you, but you're going to have to believe in yourself.
I don't expect that with the information we gave in Holograms 240 that you would be able to spawn arbitrary objects in a shared world. A super confident programmer could look through the code and piece together the patterns, but let's face it how many of us are really super confident?
I'll try to lay it out in a way that you hopefully can achieve this.
You don't need to know any networking, per se, to edit the custom messages. You do need to keep in mind that you aren't maintaining one world, but you are instead maintaining a world for each user in the experience, and in general you want all of those worlds to look the same.
The player avatar store in combination with the projectile launcher in the project is probably super close to what you need, if we can just squeeze them together somehow.
Let's think about what you get from the player avatar store.
You want to let people put objects in the world, and it sounds like you'd like having a list of objects available. The PlayerAvatarStore has a list of game objects that you can set from the Unity Editor and will spawn them in a long line. It's not the best UI, but it works in a pinch. You could take the time to make the interface nicer-like put the objects inside some sort of panel with a way to scroll so that you can support 100's of objects, but we'll start simple, and could use the UI this script affords;
The way PlayerAvatarStore is put together isn't exactly what you want though. You don't want to change the digital persona of the user, but instead want to change what the user places in the world. To do this, you'll want to make a new script called something like 'SpawnedItemSelector' that keeps track of the index into the PlayerAvatars[] array. And PlayerAvatars should probably be renamed to something like 'SpawnableItems'. So it's probably cut and paste time. Just make a new script called 'SpawnedItemStore: Singleton' and rename the things that need to be renamed.
So the SpawnedItemSelector should be used in this block instead of the AvatarSelector:
// Add AvatarSelector component to handle avatar selection by user. AvatarSelector avatarSelector = nextAvatar.GetComponent<AvatarSelector>(); if (avatarSelector == null) { avatarSelector = nextAvatar.AddComponent<AvatarSelector>(); } avatarSelector.AvatarIndex = index;
Now let's look and see what AvatarSelector does, and see how we can morph AvatarSelector into 'SpawnedItemSelector'.
Fortunately AvatarSelector is a very small script. It does a couple things:
1. It dismisses the picker. (This might not be what you want. In your case maybe you want to have the picker always open, I don't know).
2. It tells the LocalPlayerManager what AvatarIndex is used. In our case we can have it tell the LocalPlayerManager what SpawnedItemIndex is used.
3. And in the local player manager, setting the AvatarIndex causes the local player manager to send one of those custom messages to everyone else in the scene so they know what to render for your avatar. In the case of the SpawnedItem we don't actually need to do anything over the network just yet. It's just important that we keep track of the User's most recently selected SpawnedItemIndexOkay, so at this point we have a SpawnedItemStore and a SpawnedItemSelector and our Local Player Manager can know which SpawnedItem to spawn. Now we need to spawn the item.
Here we are going to follow the projectile launcher behavior. Maybe we'd even make a new script called "ItemSpawner". This script will need to do three things:
1. Spawn the users selected Spawned item in their world view at the position of their choosing
2. Send a custom message with enough information for other users in the scene to spawn the same item in the same location.
3. Listen for other users in the scene to spawn their items at their requested location in the local user's scene.So for the item spawner we are going to need to create a custom message that lets us send information about what to spawn where. What information do we need to spawn an item?
1. Probably the user that owns the item, though not necessarily.
2. The index in to the SpawnedItemStore's list of items.
3. A Vector3 for position and a Quaternion for rotation.In the ProjectileLauncher start function we see that it requests to handle the 'ShootProjectile' custom message. We'll do the same thing, but we need to setup a 'SpawnItem' custom message. In CustomMessages.cs close to the top is the TestMessageID enum. Add an item BEFORE the 'Max' entry called SpawnItem.
Then if you search through customMessages for 'shootprojectile' you'll find a SendShootProjectile function that takes a Vector3 and a direction. Copy and paste that function and rename the copy to SendSpawnedItem. Remember that we need to send a UserID, the SpawnedItemIndex, a position and a rotation. So SendSpawnedItem should look like:
public void SendSpawnedItem(int SpawnedItemIndex, Vector3 position, Quaternion rotation) { // If we are connected to a session, broadcast our head info if (this.serverConnection != null && this.serverConnection.IsConnected()) { // Create an outgoing network message to contain all the info we want to send NetworkOutMessage msg = CreateMessage((byte)TestMessageID.SendSpawnedItem); msg.Write(SpawnedItemIndex); AppendVector3(msg, position); AppendQuaternion(msg, rotation); // Send the message as a broadcast, which will cause the server to forward it to all other users in the session. this.serverConnection.Broadcast( msg, MessagePriority.Immediate, MessageReliability.Reliable, MessageChannel.Avatar); } }
if you are paying super close attention you'll notice that this function isn't sending the user ID. That's because CreateMessage() always adds the user ID.
===
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?)
7 -
Patrick mod
Meanwhile back at projectile launcher...
The SpawnProjectile function handles spawning locally and calling the custom messages class with all the information needed. ShootProjectile actually creates the GameObject in the world. There's a lot of noise in here that won't apply to us. We just need to Instantiate a copy of the GameObject at the LocalPlayers 'SpawnedItemIndex' at whatever position you like, then send all that information to CustomMessages.Instance.SendSpawnedItem. If you can, it would be best if these items could be spawned as children of the anchor object. In this case you can send the transform.localPosition and transform.localRotation as the Vector3 and Quaternion. Otherwise you'll need to do the anchor.inversetransform... stuff on the way out and the anchor.transform on the way in to keep the objects in the same coordinate system.
Finally we have ProcessRemotePRojectile, which we can call ProcessRemoteSpawnedItem. Here we need to read the network message in the same order as it was written. The userID is always part of the message and you always need to read it, even if you aren't using it. Then you need to read the remote item index, the position, and the rotation. Then you need to call the SpawnItem function you based off of the SpawnProjectile function.
Something like:
void ProcessRemoteSpawnedItem(NetworkInMessage msg) { // Parse the message long userID = msg.ReadInt64(); int RemoteItemIndex = msg.ReadInt32(); Vector3 remoteItemPosition = CustomMessages.Instance.ReadVector3(msg); Quaternion remoteItemDirection = CustomMessages.Instance.ReadQuaternion(msg); SpawnItem(RemoteItemIndex, remoteItemPosition, remoteItemDirection); }
/whew.
Okay, so I'm still leaving some gaps like wiring up the ItemSpawner as opposed to the ProjectileLauncher. That's handled in the AppStateManager.cs as the 'overridefocussedobject'. I'm happy to answer questions about that as well, but the networking bit is what you seemed most interested 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?)
7 -
Davon92 ✭
Ok so still trying to process what i need to make it a simpler test.
I do not need a store as of yet as i'm using objects already in the scene.
I do need a Send Object Transform function in custom messages that acts like send Head Transform function but do i have to add an item index for specific items?
Can I instead have the script on a game object and that object will handle its own call to send its local position and rotation to custom messages?
Next i need the process remote Spawned item function this seems pretty straight forward as it reads the information then calls the spawn item function.
For my instance of the spawn projectile function which calls the custom message send shoot projectile. I am misunderstanding the need or the transform anchor. How is the anchor transform variable sending information to the custom message that the vector 3 position and quaternion variables could not send instead?
Also I am using the tap to place script the tell my object where to eventually end up.
So is it correct to assume that i should create a callback when the user has finished placing that will call to the "spawn projectile" function or even a keyword update that will act as the point of reference to call the script with the position and rotation?
5
Answers
I can help you, but you're going to have to believe in yourself.
I don't expect that with the information we gave in Holograms 240 that you would be able to spawn arbitrary objects in a shared world. A super confident programmer could look through the code and piece together the patterns, but let's face it how many of us are really super confident?
I'll try to lay it out in a way that you hopefully can achieve this.
You don't need to know any networking, per se, to edit the custom messages. You do need to keep in mind that you aren't maintaining one world, but you are instead maintaining a world for each user in the experience, and in general you want all of those worlds to look the same.
The player avatar store in combination with the projectile launcher in the project is probably super close to what you need, if we can just squeeze them together somehow.
Let's think about what you get from the player avatar store.
You want to let people put objects in the world, and it sounds like you'd like having a list of objects available. The PlayerAvatarStore has a list of game objects that you can set from the Unity Editor and will spawn them in a long line. It's not the best UI, but it works in a pinch. You could take the time to make the interface nicer-like put the objects inside some sort of panel with a way to scroll so that you can support 100's of objects, but we'll start simple, and could use the UI this script affords;
The way PlayerAvatarStore is put together isn't exactly what you want though. You don't want to change the digital persona of the user, but instead want to change what the user places in the world. To do this, you'll want to make a new script called something like 'SpawnedItemSelector' that keeps track of the index into the PlayerAvatars[] array. And PlayerAvatars should probably be renamed to something like 'SpawnableItems'. So it's probably cut and paste time. Just make a new script called 'SpawnedItemStore: Singleton' and rename the things that need to be renamed.
So the SpawnedItemSelector should be used in this block instead of the AvatarSelector:
Now let's look and see what AvatarSelector does, and see how we can morph AvatarSelector into 'SpawnedItemSelector'.
Fortunately AvatarSelector is a very small script. It does a couple things:
1. It dismisses the picker. (This might not be what you want. In your case maybe you want to have the picker always open, I don't know).
2. It tells the LocalPlayerManager what AvatarIndex is used. In our case we can have it tell the LocalPlayerManager what SpawnedItemIndex is used.
3. And in the local player manager, setting the AvatarIndex causes the local player manager to send one of those custom messages to everyone else in the scene so they know what to render for your avatar. In the case of the SpawnedItem we don't actually need to do anything over the network just yet. It's just important that we keep track of the User's most recently selected SpawnedItemIndex
Okay, so at this point we have a SpawnedItemStore and a SpawnedItemSelector and our Local Player Manager can know which SpawnedItem to spawn. Now we need to spawn the item.
Here we are going to follow the projectile launcher behavior. Maybe we'd even make a new script called "ItemSpawner". This script will need to do three things:
1. Spawn the users selected Spawned item in their world view at the position of their choosing
2. Send a custom message with enough information for other users in the scene to spawn the same item in the same location.
3. Listen for other users in the scene to spawn their items at their requested location in the local user's scene.
So for the item spawner we are going to need to create a custom message that lets us send information about what to spawn where. What information do we need to spawn an item?
1. Probably the user that owns the item, though not necessarily.
2. The index in to the SpawnedItemStore's list of items.
3. A Vector3 for position and a Quaternion for rotation.
In the ProjectileLauncher start function we see that it requests to handle the 'ShootProjectile' custom message. We'll do the same thing, but we need to setup a 'SpawnItem' custom message. In CustomMessages.cs close to the top is the TestMessageID enum. Add an item BEFORE the 'Max' entry called SpawnItem.
Then if you search through customMessages for 'shootprojectile' you'll find a SendShootProjectile function that takes a Vector3 and a direction. Copy and paste that function and rename the copy to SendSpawnedItem. Remember that we need to send a UserID, the SpawnedItemIndex, a position and a rotation. So SendSpawnedItem should look like:
if you are paying super close attention you'll notice that this function isn't sending the user ID. That's because CreateMessage() always adds the user ID.
===
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?)
Meanwhile back at projectile launcher...
The SpawnProjectile function handles spawning locally and calling the custom messages class with all the information needed. ShootProjectile actually creates the GameObject in the world. There's a lot of noise in here that won't apply to us. We just need to Instantiate a copy of the GameObject at the LocalPlayers 'SpawnedItemIndex' at whatever position you like, then send all that information to CustomMessages.Instance.SendSpawnedItem. If you can, it would be best if these items could be spawned as children of the anchor object. In this case you can send the transform.localPosition and transform.localRotation as the Vector3 and Quaternion. Otherwise you'll need to do the anchor.inversetransform... stuff on the way out and the anchor.transform on the way in to keep the objects in the same coordinate system.
Finally we have ProcessRemotePRojectile, which we can call ProcessRemoteSpawnedItem. Here we need to read the network message in the same order as it was written. The userID is always part of the message and you always need to read it, even if you aren't using it. Then you need to read the remote item index, the position, and the rotation. Then you need to call the SpawnItem function you based off of the SpawnProjectile function.
Something like:
/whew.
Okay, so I'm still leaving some gaps like wiring up the ItemSpawner as opposed to the ProjectileLauncher. That's handled in the AppStateManager.cs as the 'overridefocussedobject'. I'm happy to answer questions about that as well, but the networking bit is what you seemed most interested 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?)
This is relevant to my interests. We're hoping to ultimately have a server that holds information on the spatial coordinates and state of a handful of visualizations.
Thanks for the Advice and Help, I wasn't able to try it over the weekend as the Hololens is at my job. I will try these tips today and see how it goes.
Ok so still trying to process what i need to make it a simpler test.
I do not need a store as of yet as i'm using objects already in the scene.
I do need a Send Object Transform function in custom messages that acts like send Head Transform function but do i have to add an item index for specific items?
Can I instead have the script on a game object and that object will handle its own call to send its local position and rotation to custom messages?
Next i need the process remote Spawned item function this seems pretty straight forward as it reads the information then calls the spawn item function.
For my instance of the spawn projectile function which calls the custom message send shoot projectile. I am misunderstanding the need or the transform anchor. How is the anchor transform variable sending information to the custom message that the vector 3 position and quaternion variables could not send instead?
Also I am using the tap to place script the tell my object where to eventually end up.
So is it correct to assume that i should create a callback when the user has finished placing that will call to the "spawn projectile" function or even a keyword update that will act as the point of reference to call the script with the position and rotation?
Yes, you'd need an item index for specific items.
Yes, you could put the script on a game object and have it handle sending it's positions. Combined with the item index, that would be cleaner. It's clear to me that you are getting this. The script would probably be an edited version of tap to place since you only need to send the transform once the object has been placed.
The anchor is required as it represents a common reference point for all devices. When the app starts up each device makes an 'implicit' anchor to represent the origin of the world. This position is arbitrary. The common reference point gives each device a transform from it's arbitrary origin to the common reference point. Put more simply, raw world coordinates are different for each device in the experience. If you just sent the vector3 and quaternion without doing the anchor inversetransform function everyone in the experience would see things in different places.
So you can make a callback or you can just make a modified tap to place that keeps track of the object id and sends the updated transform with the object id. If you aren't going to be able to add new objects to the world then you probably don't need the separate script.
===
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?)
Thank you Patrick!
After working with a programmer at work we were able to get a simple test running. The placement now changes over 2 headsets.
However there is some offset in position between the headsets that i am troubleshooting at the moment.
Ill let you know if i get it sorted out.
You have been a great help and your response time is impeccable.
I have the similar issue. I could get some time without offset and most of the time with offset. I am not sure what s really causing this inconsistencies. If you can share some of your experience, that will be great.
Has anyone been using the sync system? I've been experimenting a bit with it but haven't had much luck.
Stephen Hodgson
Microsoft HoloLens Agency Readiness Program
Virtual Solutions Developer at Saab
HoloToolkit-Unity Moderator
My case is that I already have the message broadcast and I also register to listen to the message. But I don't receive the message although through debug I did see it sent out. Any idea?
Might be my question is not clear, I make it more details here https://forums.hololens.com/discussion/2607/hololens-sharing-using-custom-message/p1?new=1
I really like the direction of this project. I am doing something similar, but want to control the scale of an object as well as position. I'd like to have one unit control the object (position, rotation, and scale), but am running into problems. I have several units able to view the same object and all can change it's position (based off of the 240 project), but keep running into issues with scale. Any suggestions?
Hello, Back Again with an Update to this Question. I Had it working for a bit But because of changes asked for in this project We Have Hit A Nose Dive. Our Client wanted an administrator Menu To Select and Create Objects for users to see.
We have the admin menu working. it instantiates objects and allows me to place them on walls. with the tap gesture. however when new users join the session they do not create the items that the admin placed. because they were not in their scene to begin with. also they only move the last object placed By the admin and only when the other headsets have an object placed in their scene. What do I need to provide to the discussion so that I Can I Fix This?
To Make this Simple Here is what i have.
I Have A Hologram Collection already in scene, That is my world Anchor. The Admin will instantiate child game objects to the hologram collection.
(The users that join will receive these objects in the same location as they were placed by the Admin. )
I Have Added to the Custom Message script Written to Receive Spawned Items position and rotation.
I have another Script Name Senders Attached to my Hologram Collection that acts similar to the remote head Manager. it has a start function that assigns the A Message Handler Enum to the local position and local rotation of the Hologram Collection. It also has the instance session joined and session left delegates subscribed to so that i can check when a user enters and leaves.
The problem that im seeing is that i have no way to tell another hololense to
instantiate a group items from the previous hololense.
so I've managed to solve a bunch of problems that I have had and am only left with 1 main major problem to deal with.
I am trying to create and share a common world anchor. However the documentation handles this very differently than how Patrick described sharing of transform position and rotation. What is the Proper Way to create and send world anchor information over hololense using the import export manager and Custom Message.cs. Thank you,