Adding AR/VR Avatars & Voice Chat

If you haven’t already, follow our Getting Started guide to get an App Key to use with Normcore. You’ll need one to connect to our backend service.

Once you’re ready to go, start by creating a blank Unity project.

Let’s start by enabling Virtual Reality Supported under XR Settings

Enabling VR support in the Unity project settings.

Next, we’re going to move the camera back to the origin and drag a “Realtime + VR Player prefab into the scene.

Reset the Main Camera transform, and add an instance of Realtime to your scene.

Go ahead and add your App Key to the Realtime component and hit Play. The default VR Player avatar prefab will spawn. It should look something like this:

It works! 🎉

Booom! That’s all it takes. You can send this build to anyone you’d like and Normcore will automatically connect you to the same room and instantiate an avatar for each person.

Custom Avatars

We’ll start by making an empty Game Object in the scene with a RealtimeAvatar component on it. Let’s call it “My Custom Avatar”.

Create an empty GameObject named 'My Custom Avatar', then add a RealtimeAvatar component to it.

RealtimeAvatar includes a button that will create all of the game objects and components we need for a basic avatar. Click “Create Avatar Prefab” on RealtimeAvatar to configure our avatar prefab.

In the Hierarchy, you can see our 'My Custom Avatar' now has some newly created Head and Hand objects, along with some nested sample geometry.

RealtimeAvatar will create the avatar prefab structure for us. There’s a game object for the player, head, and hands. Each component has a RealtimeTransform component on it, and the head has a RealtimeAvatarVoice component on it for voice chat.

Let’s try the avatar out. Drag it into your project to make a prefab. Make sure it’s in a Resources folder so it can be instantiated at runtime. Delete it from the scene, and connect the prefab to the RealtimeAvatarManager component under “Local Avatar Prefab”. Then hit Play to test it out.

Create a prefab from your custom avatar and hook it up into the Realtime instance in your scene.

You should see your cube avatar spawn when Realtime connects to the room. The head game object will scale up/down with voice volume to show the mouth movement of the player.

Now let’s use the assets from the VR Player avatar to create a custom avatar. Delete each of the Geometry game objects that RealtimeAvatar created for us. Then let’s drag the HeadModel, LeftHandModel, and RightHandModel meshes into each of their corresponding game objects on the avatar prefab. Once you’ve got that working, apply the prefab and let’s test again.

Updating our sample avatar to include the geometry used in the sample VR Player avatar bundled with Normcore.

It works, but it looks a little funny. Scaling the cube game object made sense when we didn’t have a mouth on our avatar, but it looks odd here. Let’s create a new component that animates the mouth instead of scaling the whole head game object.

Delete the VoiceScale component from the head game object and create a new component called MouthMove that looks like this:

    using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Normal.Realtime;

public class MouthMove : MonoBehaviour {
    public Transform mouth;

    private RealtimeAvatarVoice _voice;
    private float _mouthSize;

    void Awake() {
        // Get a reference to the RealtimeAvatarVoice component
        _voice = GetComponent<RealtimeAvatarVoice>();

    void Update() {
        // Use the current voice volume (a value between 0 - 1) to calculate the target mouth size (between 0.1 and 1.0)
        float targetMouthSize = Mathf.Lerp(0.1f, 1.0f, _voice.voiceVolume);

        // Animate the mouth size towards the target mouth size to keep the open / close animation smooth
        _mouthSize = Mathf.Lerp(_mouthSize, targetMouthSize, 30.0f * Time.deltaTime);

        // Apply the mouth size to the scale of the mouth geometry
        Vector3 localScale = mouth.localScale;
        localScale.y = _mouthSize;
        mouth.localScale = localScale;

This script starts by getting a reference to RealtimeAvatarVoice. The voice component has a voiceVolume property that we can use to animate the mouth. The voiceVolume property ranges from 0.0 to 1.0, so we start by converting this to a range of 0.1 to 1.0 as we don’t want to scale the mouth down to nothing when the player isn’t talking.

Next we take the targetMouthSize and animate the current _mouthSize towards this value. This smooths out the mouth movement so it doesn’t appear too jittery.

Last, we take the mouth scale and apply it to the mouth transform of the avatar head.

To test this out, make sure the MouthMove component is on the Head game object, wire up the Mouth Pivot transform into the Mouth property of Mouth Move, and hit Apply.

After creating our MouthMove script, remove the Voice Scale component that is attached to the Head by default, and add our new Mouth Move component.

Perfect! The mouth animates nicely now :)

This is still a pretty simple example, but using these tools, you should be able to make any avatar you’d like.

If you’d like to synchronize more than the head and hand positions, check out our guide: Synchronizing Your Own Data with Custom RealtimeComponents.

We’ve also got a few other guides that you might be interested in checking out after this one: