Interpolation¶
Simulation runs at a fixed timestep (default 1/60s); rendering runs at the variable frame rate. Interpolation smooths component values between fixed frames to prevent visual stuttering.
How it works¶
The four steps below map onto the per-frame phase order:
- Before each fixed update: the previous component value is saved (
InterpolatedPrevious<T>). - During fixed update: systems update the component normally.
- During variable update:
Interpolated<T>is computed by blending previous → current based on progress through the fixed frame. - Rendering: read
Interpolated<T>for smooth visuals.
Setup¶
1. Mark fields as interpolated¶
In your template, use the [Interpolated] attribute:
public partial class SmoothEntity : ITemplate, ITagged<MyTags.Smooth>
{
[Interpolated]
Position Position = default;
[Interpolated]
Rotation Rotation = default;
OrbitParams OrbitParams;
}
Each interpolated field generates three components: Position, Interpolated<Position>, and InterpolatedPrevious<Position>.
2. Define interpolation functions¶
Write static methods with [GenerateInterpolatorSystem] defining how each component type blends. The source generator creates a presentation-phase system with a nested Burst-compiled job for each:
public static class MyInterpolators
{
const string GroupName = "MyGameInterpolators";
[GenerateInterpolatorSystem("PositionInterpolatedUpdater", GroupName)]
[BurstCompile]
public static void InterpolatePosition(
in Position a, in Position b, ref Position result, float t)
{
result.Value = math.lerp(a.Value, b.Value, t);
}
[GenerateInterpolatorSystem("RotationInterpolatedUpdater", GroupName)]
[BurstCompile]
public static void InterpolateRotation(
in Rotation a, in Rotation b, ref Rotation result, float t)
{
// nlerp is cheaper than slerp and sufficient for small angular deltas
result.Value = math.nlerp(a.Value, b.Value, t);
}
}
GroupName groups related interpolators so they can be registered together.
3. Register with WorldBuilder¶
The source generator creates Add{GroupName}, registering all interpolators in the group — both the previous-frame savers and the variable-update blending systems:
var world = new WorldBuilder()
.AddTemplate(SmoothEntity.Template)
.AddMyGameInterpolators() // Generated
.Build();
4. Create entities with interpolated values¶
SetInterpolated() initializes all three components (current, interpolated, previous) in sync:
world.AddEntity<MyTags.Smooth>()
.SetInterpolated(new Position(startPos))
.SetInterpolated(new Rotation(startRot))
.Set(new OrbitParams { ... });
5. Read interpolated values for rendering¶
In a variable-update rendering system, read Interpolated<T> instead of the raw component:
[ExecuteIn(SystemPhase.Presentation)]
public partial class RenderSystem : ISystem
{
[ForEachEntity(typeof(MyTags.Smooth))]
void Execute(in Interpolated<Position> pos, in Interpolated<Rotation> rot, in GameObjectId id)
{
var go = _goManager.Resolve(id);
go.transform.position = (Vector3)pos.Value.Value;
go.transform.rotation = rot.Value.Value;
}
}
What gets generated¶
For each [GenerateInterpolatorSystem] method, the source generator produces:
- An
ISystemwith a nested Burst-compiled job that runs during the presentation phase, iterating entities with the component and blending previous → current via your function. - An extension method on
WorldBuilder(one per group) that registers allInterpolatedPreviousSaver<T>instances and interpolator systems in the group.
You write the math; scheduling, dependency tracking, and registration are handled.
Best practices¶
- Only interpolate visual components — positions, rotations, scales, colors. Don't interpolate gameplay state like health or ammo.
- Use
SetInterpolated()at creation — keeps all three components in sync and avoids a first-frame visual pop. If you forget and the component has no default, Trecs throws. - Group interpolators by project — share a
GroupNameconstant so oneAdd{GroupName}()registers everything. - Prefer
nlerpoverslerpfor rotations — angular deltas between fixed frames are small enough that the difference is imperceptible, andnlerpis much cheaper.
See also¶
- Sample 09 — Interpolation: a full interpolation setup with custom blend functions.