Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

In Cavrnus, CoPresence operates through Property values, which are communicated Transiently and do not get logged in the Journal.

Local vs Remote User Avatars

In Cavrnus, the Local and Remote Avatars are separate. When a remote user joins, we will Instantiate() the Avatar specified in the Cavrnus Spatial Connector, and provide it with relevant property paths (this will be explained below).

Local User’s, by contrast, are left up to the Application to provide/configure. If you wish to display a local Avatar, use a first person camera, or include an XR Rig, it will need to be done by your project. Then, there are a handful of simply steps to have that object send CoPresence data to Cavrnus.

Sending Transform Data from Local User

Each user is responsible for sending their own CoPresence Data. To do this, you simply need to select the local user’s Camera/Rig/etc, and then use the menu item Set Selected Object As Local User. This will add the Cavrnus Local User Flag component, as well as a Sync Transform + Cavrnus Properties Container.

...

At runtime, the Cavrnus Local User Flag will go through all the Sync Transform scripts and disable their ability to receive data from the server. This ensures that whatever character controller you are using is “send only” and won’t be fighting with Property Data coming in from the server. After that it will simply monitor your local Transform and send CoPresence updates via Properties!

Using a Custom (Remote) Avatar

To create a Custom Avatar for remote users, we’ll assume you already have a model you wish to use. Here we will be using a simple Robot mesh.

...

  1. When a remote user’s Avatar is spawned, it will iterate through all of its Sync Components and uncheck “Send My Changes”. This ensures that only the user in question can update their CoPresence.

  2. Notice that right now the Unique Container Name is called “Robot Remote”. Nodes below it may be called something like “Robot Remote/Head”. When it is spawned for a User, that User’s ID will replace “Robot Remote”. So the first Properties Container will become something like “/users/0wu9vekvi24”, and the Head would then become “/users/0wu9vekvi24/Head”. Any Containers that don’t start with “Robot Remote” will retain their original property path.

Adding UI/Name Tags to Remote Avatar

In addition to the CoPresence Transform, which is constantly being sent by the Remote User, there are additional user Properties which are exposed through properties, but are set elsewhere. These include things like the User’s Name, weather they are Muted, what Volume they are Speaking at, etc. This data is actually sent over-the-wire using different channels, but is copied into Properties for your convenience under-the-hood. Since the data is coming in from elsewhere, these properties are read-only, and any attempt to Post() to them will fail. While a simple BindXProperty call will retrieve them, for your convenience we have added calls to get them directly in the CavrnusShortcutsLibrary.

...

The name tag we provide in the existing built-in avatar is built entirely using the above tools & principals.

Adding Hands/Rigging to Remote Avatar

While, by default, Avatars need only have a SyncTransform on their root node, if you wanted to send over additional data you need only add more components to the relevant parts.

...

Code Block
public void BindAvatarBones(CavrnusSpaceConnection spaceConn)
{
	foreach(var bone in skinnedMeshRenderer.bones)
    {
        string ContainerName = GetComponent<CavrnusPropertiesContainer>().UniqueContainerName;
        string PropertyName = bone.name; //We assume the bones all have unique names.  If they don't, ensure this is unique some other way.

        spaceConn.BindTransformPropertyValue(ContainerName, PropertyName, boneTrns =>
        {
            bone.localPosition = boneTrns.LocalPosition;
            bone.localEulerAngles = boneTrns.LocalEulerAngles;
            bone.localScale = boneTrns.LocalScale;
        });
    }
}

Sending Hands/Rigging from Local Player Character

The above is, of course, irrelevant, if no data is being sent to the given properties.

...

Code Block
private Dictionary<string, CavrnusLivePropertyUpdate<CavrnusTransformData>> boneSenders = new Dictionary<string, CavrnusLivePropertyUpdate<CavrnusTransformData>>();
private void Update()
{
	foreach (var bone in skinnedMeshRenderer.bones)
	{
        var currentBoneTransform = new CavrnusTransformData(bone.localPosition, bone.localEulerAngles, bone.localScale);

		if (!boneSenders.ContainsKey(bone.name))
        {
			string ContainerName = GetComponent<CavrnusPropertiesContainer>().UniqueContainerName;
			string PropertyName = bone.name; //We assume the bones all have unique names.  If they don't, ensure this is unique some other way.

            boneSenders[bone.name] = spaceConn.BeginTransientTransformPropertyUpdate(ContainerName, PropertyName, currentBoneTransform);
        }
        else
        {
            boneSenders[bone.name].UpdateWithNewData(currentBoneTransform);
		}
	}
}

XR Headset Transform Troubleshooting

XR headsets present some unique difficulties. Specifically, they often have several levels of Hierarchy, all of which are affecting the Transforms. This means a simple SyncTransform component will not always do the trick, since it will only capture one level of that.

...