Skip to content

Commit b33b546

Browse files
refactor
After testing for quite some time I came to the conclusion that we needed a "new" lerp and should mark the original lerp as the "legacy" lerp while keeping the added option to have the smooth dampening. Removed the additional phases from the "new" lerp and smooth dampening while also providing users with a more direct and constant maximum interpolation setting that is not directly tied to the frame time delta. This yields a wider range of fine tuning and will be easier to handle adjusting during runtime. The LinearBufferInterpolator RNSM component hooks are in place so we can provide users with a tool to be able to determine what is happening with the LinearBufferInterpolator... it will be released in the examples section once ready to be released. Adjusted API XML documentation and all places that referenced the other enum names changed.
1 parent c0d794f commit b33b546

File tree

5 files changed

+108
-176
lines changed

5 files changed

+108
-176
lines changed

com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs

Lines changed: 27 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public abstract class BufferedLinearInterpolator<T> where T : struct
1414
// Constant absolute value for max buffer count instead of dynamic time based value. This is in case we have very low tick rates, so
1515
// that we don't have a very small buffer because of this.
1616
private const int k_BufferCountLimit = 100;
17-
private const float k_AproximatePrecision = 0.00001f;
17+
private const float k_AproximatePrecision = 0.0001f;
1818
private const double k_SmallValue = 9.999999439624929E-11; // copied from Vector3's equal operator
1919

2020
#region Legacy notes
@@ -119,17 +119,13 @@ internal struct CurrentState
119119
public double EndTime;
120120
public double TimeToTargetValue;
121121
public double DeltaTime;
122-
public double DeltaTimePredict;
123122
public double MaxDeltaTime;
123+
public double LastRemainingTime;
124124
public float LerpT;
125-
public float LerpTPredict;
126125
public bool TargetReached;
127-
public bool PredictingNext;
128126
public T CurrentValue;
129127
public T PreviousValue;
130-
public T PredictValue;
131-
public T Phase1Value;
132-
public T Phase2Value;
128+
public T NextValue;
133129

134130
private float m_CurrentDeltaTime;
135131

@@ -140,53 +136,37 @@ public void AddDeltaTime(float deltaTime)
140136
{
141137
m_CurrentDeltaTime = deltaTime;
142138
DeltaTime = Math.Min(DeltaTime + deltaTime, TimeToTargetValue);
143-
DeltaTimePredict = Math.Min(DeltaTime + deltaTime, TimeToTargetValue + MaxDeltaTime);
144139
LerpT = (float)(TimeToTargetValue == 0.0 ? 1.0 : DeltaTime / TimeToTargetValue);
145-
if (PredictingNext)
146-
{
147-
LerpTPredict = (float)(TimeToTargetValue == 0.0 ? 1.0 : DeltaTimePredict / TimeToTargetValue);
148-
}
149-
else
150-
{
151-
LerpTPredict = LerpT;
152-
}
153140
}
154141

155142
public void SetTimeToTarget(double timeToTarget)
156143
{
157-
DeltaTimePredict = 0.0f;
158-
LerpTPredict = 0.0f;
159144
LerpT = 0.0f;
160145
DeltaTime = 0.0f;
161146
TimeToTargetValue = timeToTarget;
162147
}
163148

164-
public bool TargetTimeAproximatelyReached(bool nextStatePending)
149+
public bool TargetTimeAproximatelyReached()
165150
{
166151
if (!Target.HasValue)
167152
{
168153
return false;
169154
}
170-
return (m_CurrentDeltaTime * (nextStatePending ? (LerpT * 1.30f) : 1.0f)) >= FinalTimeToTarget;
155+
return FinalTimeToTarget <= m_CurrentDeltaTime * 0.5f;
171156
}
172157

173158
public void Reset(T currentValue)
174159
{
175160
Target = null;
176161
CurrentValue = currentValue;
162+
NextValue = currentValue;
177163
PreviousValue = currentValue;
178-
PredictValue = currentValue;
179-
Phase1Value = currentValue;
180-
Phase2Value = currentValue;
181164
TargetReached = false;
182-
PredictingNext = false;
183165
LerpT = 0.0f;
184-
LerpTPredict = 0.0f;
185166
EndTime = 0.0;
186167
StartTime = 0.0;
187168
TimeToTargetValue = 0.0f;
188169
DeltaTime = 0.0f;
189-
DeltaTimePredict = 0.0f;
190170
m_CurrentDeltaTime = 0.0f;
191171
}
192172
}
@@ -230,11 +210,6 @@ public void Reset(T currentValue)
230210
/// </summary>
231211
private T m_RateOfChange;
232212

233-
/// <summary>
234-
/// Represents the predicted rate of change for the value being interpolated when smooth dampening is enabled.
235-
/// </summary>
236-
private T m_PredictedRateOfChange;
237-
238213
/// <summary>
239214
/// Resets interpolator to the defaults.
240215
/// </summary>
@@ -245,7 +220,6 @@ public void Clear()
245220
m_LastMeasurementAddedTime = 0.0;
246221
InterpolateState.Reset(default);
247222
m_RateOfChange = default;
248-
m_PredictedRateOfChange = default;
249223
}
250224

251225
/// <summary>
@@ -266,7 +240,6 @@ public void ResetTo(T targetValue, double serverTime)
266240
private void InternalReset(T targetValue, double serverTime, bool addMeasurement = true)
267241
{
268242
m_RateOfChange = default;
269-
m_PredictedRateOfChange = default;
270243
// Set our initial value
271244
InterpolateState.Reset(targetValue);
272245

@@ -285,7 +258,7 @@ private void InternalReset(T targetValue, double serverTime, bool addMeasurement
285258
/// <param name="minDeltaTime">minimum time delta (defaults to tick frequency).</param>
286259
/// <param name="maxDeltaTime">maximum time delta which defines the maximum time duration when consuming more than one item from the buffer.</param>
287260
/// <param name="lerpAhead">when true, the predicted target <see cref="CurrentState.Phase2Value"/> will lerp towards the next target by the current delta.</param>
288-
private void TryConsumeFromBuffer(double renderTime, double minDeltaTime, double maxDeltaTime, bool lerpAhead)
261+
private void TryConsumeFromBuffer(double renderTime, double minDeltaTime, double maxDeltaTime)
289262
{
290263
BufferedItem? previousItem = null;
291264
var startTime = 0.0;
@@ -315,7 +288,7 @@ private void TryConsumeFromBuffer(double renderTime, double minDeltaTime, double
315288

316289
if (!noStateSet)
317290
{
318-
potentialItemNeedsProcessing = (potentialItem.TimeSent <= renderTime) && potentialItem.TimeSent > InterpolateState.Target.Value.TimeSent;
291+
potentialItemNeedsProcessing = ((potentialItem.TimeSent <= renderTime) && potentialItem.TimeSent > InterpolateState.Target.Value.TimeSent);
319292
if (!InterpolateState.TargetReached)
320293
{
321294
InterpolateState.TargetReached = IsAproximately(InterpolateState.CurrentValue, InterpolateState.Target.Value.Item);
@@ -331,38 +304,23 @@ private void TryConsumeFromBuffer(double renderTime, double minDeltaTime, double
331304
{
332305
InterpolateState.Target = target;
333306
alreadyHasBufferItem = true;
334-
InterpolateState.PredictValue = InterpolateState.CurrentValue;
307+
InterpolateState.NextValue = InterpolateState.CurrentValue;
335308
InterpolateState.PreviousValue = InterpolateState.CurrentValue;
336-
InterpolateState.Phase1Value = InterpolateState.CurrentValue;
337-
InterpolateState.Phase2Value = InterpolateState.CurrentValue;
338309
InterpolateState.SetTimeToTarget(minDeltaTime);
339-
InterpolateState.TimeToTargetValue = minDeltaTime;
340310
startTime = InterpolateState.Target.Value.TimeSent;
341311
InterpolateState.TargetReached = false;
342-
InterpolateState.PredictingNext = false;
343312
InterpolateState.MaxDeltaTime = maxDeltaTime;
344313
}
345314
else
346315
{
347316
if (!alreadyHasBufferItem)
348317
{
349318
alreadyHasBufferItem = true;
319+
InterpolateState.LastRemainingTime = InterpolateState.FinalTimeToTarget;
350320
InterpolateState.TargetReached = false;
351-
startTime = InterpolateState.Target.Value.TimeSent;
352321
InterpolateState.MaxDeltaTime = maxDeltaTime;
353-
InterpolateState.PredictingNext = m_BufferQueue.Count > 0;
354-
if (lerpAhead)
355-
{
356-
InterpolateState.Phase1Value = InterpolateState.PreviousValue;
357-
if (InterpolateState.PredictingNext && m_BufferQueue.TryPeek(out BufferedItem nextTarget))
358-
{
359-
InterpolateState.Phase2Value = Interpolate(InterpolateState.PredictValue, nextTarget.Item, InterpolateState.CurrentDeltaTime);
360-
}
361-
else
362-
{
363-
InterpolateState.Phase2Value = InterpolateState.PredictValue;
364-
}
365-
}
322+
InterpolateState.PreviousValue = InterpolateState.NextValue;
323+
startTime = InterpolateState.Target.Value.TimeSent;
366324
}
367325
InterpolateState.SetTimeToTarget(Math.Max(target.TimeSent - startTime, minDeltaTime));
368326
InterpolateState.Target = target;
@@ -388,7 +346,6 @@ internal void ResetCurrentState()
388346
{
389347
InterpolateState.Reset(InterpolateState.CurrentValue);
390348
m_RateOfChange = default;
391-
m_PredictedRateOfChange = default;
392349
}
393350
}
394351

@@ -403,11 +360,11 @@ internal void ResetCurrentState()
403360
/// <param name="tickLatencyAsTime">The tick latency in relative local time.</param>
404361
/// <param name="minDeltaTime">The minimum time delta between the current and target value.</param>
405362
/// <param name="maxDeltaTime">The maximum time delta between the current and target value.</param>
406-
/// <param name="lerpAhead">Determines whether to use smooth dampening or lerp ahead interpolation type.</param>
363+
/// <param name="lerp">Determines whether to use smooth dampening or lerp interpolation type.</param>
407364
/// <returns>The newly interpolated value of type 'T'</returns>
408-
internal T Update(float deltaTime, double tickLatencyAsTime, double minDeltaTime, double maxDeltaTime, bool lerpAhead)
365+
internal T Update(float deltaTime, double tickLatencyAsTime, double minDeltaTime, double maxDeltaTime, bool lerp)
409366
{
410-
TryConsumeFromBuffer(tickLatencyAsTime, minDeltaTime, maxDeltaTime, lerpAhead);
367+
TryConsumeFromBuffer(tickLatencyAsTime, minDeltaTime, maxDeltaTime);
411368
// Only begin interpolation when there is a start and end point
412369
if (InterpolateState.Target.HasValue)
413370
{
@@ -417,34 +374,26 @@ internal T Update(float deltaTime, double tickLatencyAsTime, double minDeltaTime
417374
// Increases the time delta relative to the time to target.
418375
// Also calculates the LerpT and LerpTPredicted values.
419376
InterpolateState.AddDeltaTime(deltaTime);
420-
var targetValue = InterpolateState.CurrentValue;
421377
// SmoothDampen
422-
if (!lerpAhead)
378+
if (!lerp)
423379
{
424-
InterpolateState.PreviousValue = SmoothDamp(InterpolateState.PreviousValue, InterpolateState.Target.Value.Item, ref m_RateOfChange, (float)InterpolateState.TimeToTargetValue, (float)InterpolateState.TimeToTargetValue * InterpolateState.LerpT);
425-
InterpolateState.PredictValue = SmoothDamp(InterpolateState.PredictValue, InterpolateState.Target.Value.Item, ref m_PredictedRateOfChange, (float)InterpolateState.TimeToTargetValue, (float)(InterpolateState.TimeToTargetValue * InterpolateState.LerpTPredict));
380+
InterpolateState.NextValue = SmoothDamp(InterpolateState.NextValue, InterpolateState.Target.Value.Item, ref m_RateOfChange, (float)InterpolateState.TimeToTargetValue * InterpolateState.LerpT, deltaTime);
426381
}
427-
else// Lerp Ahead
382+
else// Lerp
428383
{
429-
InterpolateState.PreviousValue = Interpolate(InterpolateState.Phase1Value, InterpolateState.Target.Value.Item, InterpolateState.LerpT);
430-
// Note: InterpolateState.LerpTPredict is clamped to LerpT if we have no next target
431-
InterpolateState.PredictValue = InterpolateUnclamped(InterpolateState.Phase2Value, InterpolateState.Target.Value.Item, InterpolateState.LerpTPredict);
432-
384+
InterpolateState.NextValue = Interpolate(InterpolateState.PreviousValue, InterpolateState.Target.Value.Item, InterpolateState.LerpT);
433385
}
434386

435-
// Lerp between the PreviousValue and PredictedValue using the current delta time
436-
targetValue = Interpolate(InterpolateState.PreviousValue, InterpolateState.PredictValue, deltaTime);
437-
438387
// If lerp smoothing is enabled, then smooth current value towards the target value
439388
if (LerpSmoothEnabled)
440389
{
441390
// Apply the smooth lerp to the target to help smooth the final value.
442-
InterpolateState.CurrentValue = Interpolate(InterpolateState.CurrentValue, targetValue, deltaTime / MaximumInterpolationTime);
391+
InterpolateState.CurrentValue = Interpolate(InterpolateState.CurrentValue, InterpolateState.NextValue, Mathf.Clamp(1.0f - MaximumInterpolationTime, 0.0f, 1.0f));
443392
}
444393
else
445394
{
446395
// Otherwise, just assign the target value.
447-
InterpolateState.CurrentValue = targetValue;
396+
InterpolateState.CurrentValue = InterpolateState.NextValue;
448397
}
449398
}
450399
else // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
@@ -499,7 +448,7 @@ private void TryConsumeFromBuffer(double renderTime, double serverTime)
499448
{
500449
InterpolateState.Target = target;
501450
alreadyHasBufferItem = true;
502-
InterpolateState.PreviousValue = InterpolateState.CurrentValue;
451+
InterpolateState.NextValue = InterpolateState.CurrentValue;
503452
InterpolateState.StartTime = target.TimeSent;
504453
InterpolateState.EndTime = target.TimeSent;
505454
}
@@ -509,7 +458,7 @@ private void TryConsumeFromBuffer(double renderTime, double serverTime)
509458
{
510459
alreadyHasBufferItem = true;
511460
InterpolateState.StartTime = InterpolateState.Target.Value.TimeSent;
512-
InterpolateState.PreviousValue = InterpolateState.CurrentValue;
461+
InterpolateState.NextValue = InterpolateState.CurrentValue;
513462
InterpolateState.TargetReached = false;
514463
}
515464
InterpolateState.EndTime = target.TimeSent;
@@ -550,12 +499,13 @@ public T Update(float deltaTime, double renderTime, double serverTime)
550499
{
551500
// The original BufferedLinearInterpolator lerping script to assure the Smooth Dampening updates do not impact
552501
// this specific behavior.
553-
float t = 1.0f;
502+
InterpolateState.LerpT = 1.0f;
554503
if (InterpolateState.TimeToTargetValue > k_SmallValue)
555504
{
556-
t = Math.Clamp((float)((renderTime - InterpolateState.StartTime) / InterpolateState.TimeToTargetValue), 0.0f, 1.0f);
505+
InterpolateState.LerpT = Math.Clamp((float)((renderTime - InterpolateState.StartTime) / InterpolateState.TimeToTargetValue), 0.0f, 1.0f);
557506
}
558-
var target = Interpolate(InterpolateState.PreviousValue, InterpolateState.Target.Value.Item, t);
507+
508+
var target = Interpolate(InterpolateState.NextValue, InterpolateState.Target.Value.Item, InterpolateState.LerpT);
559509

560510
if (LerpSmoothEnabled)
561511
{

0 commit comments

Comments
 (0)