Follow camera jitters on multiplayer clients

Hi there!

I’ve already read a couple of threads that treat very similar topics, however, none of those threads were very helpful for my problem so far.

I’ve implemented simple networking with an authoritative server, so the client only sends his input and the server calculates the player movement and responds with the new position and rotation.

The player is flying a rigidbody plane that is moved by torque and forces (in the server-side movement code). The camera is set to smoothly follow the plane at a set distance, i.e. it’s not ‘glued’ to the plane but drags behind a little.

The player network script is observed by a NetworkView so the player can send his input via RPC and the server response is handled in OnSerializeNetworkView().
In the player’s Update() method the input is sent to the server. In the player’s FixedUpdate() method the movement code is executed (server-only). And in OnSerializeNetworkView() the position and rotation are overwritten with the new values from the server.

In this scenario, the camera works as intended on the server (which is to be expected) but jitters a lot on the client. I’m connecting to the host locally, so lag is not an issue.
I know the camera is causing the issue because everything runs smoothly when I just stick the camera to the plane (without smooth following).

So I was thinking the camera update - where the camera position and rotation is adjusted to the player’s position and rotation - might not be in synch with the update of the player’s position and rotation. In order to rule out that theory, I call the camera update as soon as the player’s position changes (which is when the server packet arrives in OnSerializeNetworkView).

That didn’t fix the jittering, so I assumed that not all of the player’s transform’s variables are up to date until the internal update routines have finished. I was relying on the transform, though, to transform the camera’s distance vector into world space. So in order to get rid of any variable dependencies, I feed the camera update the new position and rotation. I then determine the camera position vector myself and even calculate my own time delta in order to rule out another potential error source.
Here is my code for the camera update:

public void UpdateCamera(Vector3 pos, Quaternion rot)
{
    float deltaTime = Time.time - this.lastTime;
	
    Vector3 wantedPosition = pos + (rot * this.relativePosition);
    transform.position = Vector3.Lerp(transform.position, wantedPosition, deltaTime * 5.0f);
    transform.rotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * 10.0f);
	
    this.lastTime = Time.time;
}

this.relativePosition is initialized like this:

this.relativePosition = new Vector3(0, height, -Mathf.Sqrt(distance*distance - height*height)); //c²=a²+b²

And this is my OnSerializeNetworkView method where the player’s position and rotation are changed:

void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
    if (stream.isWriting)
    {
        Vector3 pos = this.transform.position;
        Quaternion rot = this.transform.rotation;
        stream.Serialize(ref pos);
        stream.Serialize(ref rot);
    }
    else
    {
        Vector3 posReceive = Vector3.zero;
        Quaternion rotReceive = Quaternion.identity;
        stream.Serialize(ref posReceive);
        stream.Serialize(ref rotReceive);

        CameraControl cam = Camera.main.GetComponent<CameraControl>();
        cam.UpdateCamera(pos, rot);
    }
}

Of course this still doesn’t fix my problem. OnSerializeNetworkView is the only place where the player’s position and rotation are changed and only then the camera’s position and rotation are updated. In my understanding they should be totally synchronized despite the discreteness of the updates.

Increasing the network rate has no effect on the jittering (as expected). Implementing the network interpolation and extrapolation code from the NetworkRigidbody code from the networking tutorial has helped improve the jitter to some extent but it’s still noticable. Same goes for the interpolation option of the player’s rigidbody component.

What I can’t understand is why the camera still jitters even though the player’s and camera’s update are totally in synch. Jittering should appear if they’re out of synch and the positional updates are being called at different times which is just not the case here.

Any form of advice is very much appreciated.
Thanks in advance!

The jitter was in fact caused by the discreteness of the network updates - i.e. 15 times per second OnSerializeNetworkView is called.

My goal was to implement simple networking first and then care about stuff like prediction, interpolation and lag compensation. However, I would not advise others to do the same because the jittering was in fact fixed by implementing prediction (another problem that originates from this is that now there’s a slight jitter everytime the network update arrives and corrects the prediction values by overwriting them, but that should be fixable with the help of frame buffering / interpolating).

Thanks to Fattie for pushing me into the right direction!