I have been debugging jitter in my project which uses NetCode for Entities, and Unity Physics. This became very noticable when I added a system to sync my player entities transform out into a game object, and target it with a cinemachine camera.
I had started with using an interpolated rigid body, which I noticed a lot of jitter with. To better understand what was happening I built a custom interpolation system and stumbled upon a hunk of code in NetcodePredictionFixedRateManager com.unity.netcode/Runtime/Snapshot/GhostPredictionSystemGroup.cs at master · needle-mirror/com.unity.netcode · GitHub
Adding an epsilon to the DeltaTime can cause the numerator to “overflow” into a an extra remaining update, which is actually for a PartialTick. With my simulation running at 64hz, the epsilon is ~6% of my timestep, and causes my systems to run for a partial tick pretty frequently.
This has an impact on the physics engine as com.unity.netcode/Runtime/Physics/PredictedPhysicsSystemGroup.cs at master · needle-mirror/com.unity.netcode · GitHub only guards against “FirstTimeFullyPredictingTick” if there are no ghosts with velocities (I think is the logic here, I’m not sure).
If this com.unity.physics/Unity.Physics/ECS/GraphicsIntegration/Systems/BufferInterpolatedRigidBodiesMotion.cs at master · needle-mirror/com.unity.physics · GitHub runs on a partial tick, and then a full tick on the next update, it will on the frame of the partial tick snapshot a “double move” (because we’re actually a tick ahead of where we should be), and then on the next frame is will likely to no move at all, because we’re now processing the same partial tick as a full tick.
I’m pretty fresh to both all the technologies here, so I apologies for any logical errors. Hopefully the code pointers help to follow my empirical experiences here.
I’m also no expert on floating point accuracy problems, but it seems the worry is an extremely small DeltaTime. If that is the case, a guard like
if (group.World.Time.DeltaTime < m_TimeStep)
{
return false;
}
Would ensure that the calculation is always close to 1, or whatever simulation::fixed multiple is expected without risking processing ticks before we should.
I’m basing my assumption that PredictedFixedStepSimulationSystemGroup shouldn’t run partial ticks on the comment associated with it
/// <summary>
/// <para>A fixed update group inside the ghost prediction. This is equivalent to <see cref="FixedStepSimulationSystemGroup"/> but for prediction.
/// The fixed update group can have a higher update frequency than the rest of the prediction, and it does not do partial ticks.</para>
/// <para>Note: This SystemGroup is intentionally added to non-netcode worlds, to help enable single-player testing.</para>
/// </summary>
It also seems somewhat wasteful that the physics system re-snapshots re-simulated ticks, as BufferInterpolatedRigidBodiesMotion runs in PhysicsSystemGroup though I understand this is likely due to NetCode wrapping around Physics, rather than Physics knowing about NetCode. If Physics were to check
if (!networkTime.IsFinalFullPredictionTick)
return;
like GhostPredictionHistorySystem does, this problem would likely be less obvious, though I would still need to guard the movement system for my kinematic rigid body from running partial ticks, as that causes double movement within a frame as well.
TL;DR:
Had issues with interpolating kinematic rigid bodies using NetCode for Entites and Unity Physics.
Removing the epsilon from this line com.unity.netcode/Runtime/Snapshot/GhostPredictionSystemGroup.cs at 27b500c085edbce2e5f21547833cd5bb5138f2b4 · needle-mirror/com.unity.netcode · GitHub and running my movement system in [UpdateInGroup(typeof(AfterPhysicsSystemGroup))] (since the physics snapshots before physics runs, if you update before your prev and current are always the same) fixed all jittering.