Guide: Integrating Ready Player Me with coherence

Hey all! Recently we tried integrating coherence with the famous avatar creation platform Ready Player Me.

After some fiddling, we found out that it’s quite simple to have a completely custom character and sync its position and animations with coherence, and also have the appearance – powered by Ready Player Me – be the same on all connected clients.

We made a small demo project that demonstrates just that, which you can get from this Github repository. We think the code explains itself, but we’re also in the process of making a short video about it.

RPM Integration Demo - Github repository

If you run into trouble or are new to RPM, check out their documentation or their developer forums.

Here’s a brief writeup:

Loading avatars with RPM
RPM avatars are identified by a URL, which contains their ID. The URLs look something like this:

https://models.readyplayer.me/64d26077fd49224c9eab0e97.glb

Where 64d26077fd49224c9eab0e97 is the avatar ID. The avatar ID is all we need to download an avatar mesh.

Making it networked
As you might know, in coherence you define networked Prefabs beforehand, you specify which properties to network on that Prefab, then you bake the netcode.

However, when you request the loading of an avatar in RPM, it automatically instantiates it in the scene. But that’s not networked!

To solve that, we transfer the mesh data from that automatically-instantiated avatar to the one that is networked with coherence.

And by storing that ID in a synced string variable called avatarModelID on the script applied to the player Prefab, NetworkAvatar, we ensure that all other Clients can load the same avatar.

Basically the loading of avatars is not done by coherence, but is happening individually on each connected Client. In other words, each Client is downloading all avatars from the RPM servers, but the IDs to download them are synced by coherence.

The flow
When the player connects, a script in the scene instantiates the Prefab, assigns it the avatarModelID coming from the UI, and invokes a method called LoadRpmAvatar(). This method contacts the RPM servers and calls for the loading of the avatar, proving the unique ID.

When the avatar finishes loading, RPM automatically instantiates it in the scene.

The NetworkAvatar script at this point reacts to that, takes all of the mesh data that has been downloaded, and injects it into the networked Prefab. They make it very easy, and provide a utility function to do this called AvatarMeshHelper.TransferMesh().

Finally, it destroys the non-networked one.

What happens on other Clients
At this point, because the player Prefab is a network entity, it has been instantiated on all clients by coherence automatically. And when the avatarModelID is assigned, it also gets broadcasted to all connected Clients.

Since avatarModelID has an [OnValueSynced] attribute (you can learn more about it here), as soon as it’s synced over the network it will invoke the method ReloadAvatar() on non-authoritative Clients, triggering the download of the avatar for them too.

This is the mechanism to ensure that the RPM avatar is downloaded on all Clients, and not only on the one that has authority.

The end?
That’s it. In short:

  • Spawn the networked Prefab, and download the avatar locally with the ID
  • Inject the mesh data that’s been downloaded into the networked Prefab
  • Share that ID
  • Repeat the process on all connected clients thanks to [OnValueSynced]

This was a very simplified implementation of RPM, which is a much deeper SDK (as is coherence :slight_smile: ). We recommend to check their documentation to learn more about it.

For now, have fun with RPM and drop any related questions in this thread! And don’t forget that they also have developer forums!

2 Likes

The video is now out!