Quick answer: Wrap each weight (or a list of weights) in a NetworkVariable<float> / NetworkList<float>. On OnValueChanged, call SetBlendShapeWeight locally. Server publishes; clients apply.
Player toggles a smile. Locally the face changes. Other players see a still face. SkinnedMeshRenderer state isn’t replicated by Netcode by default.
The Symptom
Visible facial or morph changes don’t propagate to other clients. Position and animation replicate correctly; only blend shapes are static on remote views.
The Fix
using Unity.Netcode;
using UnityEngine;
public class FaceSync : NetworkBehaviour
{
public SkinnedMeshRenderer face;
public NetworkVariable<float> smile = new();
private const int SmileIndex = 0;
public override void OnNetworkSpawn()
{
smile.OnValueChanged += OnSmileChanged;
OnSmileChanged(0, smile.Value);
}
private void OnSmileChanged(float oldV, float newV)
{
face.SetBlendShapeWeight(SmileIndex, newV);
}
[ServerRpc]
public void SetSmileServerRpc(float v)
{
smile.Value = v;
}
}
Owning client calls SetSmileServerRpc; server writes the NetworkVariable; all clients (including the owner) get OnValueChanged and apply locally.
Many Blend Shapes
For a face with 50+ shapes, NetworkList:
public NetworkList<float> weights = new();
public override void OnNetworkSpawn()
{
weights.OnListChanged += ApplyAllWeights;
}
void ApplyAllWeights(NetworkListEvent<float> ev)
{
for (int i = 0; i < weights.Count && i < face.sharedMesh.blendShapeCount; i++)
face.SetBlendShapeWeight(i, weights[i]);
}
Bandwidth
For high-frequency face mocap, quantize floats to byte (0..255 = 0..100% weight) and send via custom message at 20Hz with linear interpolation locally. Saves a lot of bandwidth.
Verifying
Host + client. Owner changes smile. Remote view shows the change within one tick. If not, OnValueChanged isn’t firing on the remote — verify subscription order in OnNetworkSpawn.
“NetworkVariable for the value. OnValueChanged applies. Faces sync.”
Related Issues
For SkinnedMeshRenderer bounds, see SMR bounds. For Mecanim foot slide, see foot slide.
NetworkVariable. Apply in callback. Faces propagate.