Skip to content

Commit fe93343

Browse files
update
Adding more properties for users to adjust as well as an additional interpolation type as there are various use cases where one model doesn't fit all genres.
1 parent bc2e9f2 commit fe93343

File tree

4 files changed

+313
-104
lines changed

4 files changed

+313
-104
lines changed

com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ public class NetworkTransformEditor : NetcodeEditorBase<NetworkTransform>
3131
private SerializedProperty m_PositionInterpolationTypeProperty;
3232
private SerializedProperty m_RotationInterpolationTypeProperty;
3333
private SerializedProperty m_ScaleInterpolationTypeProperty;
34+
private SerializedProperty m_PositionLerpSmoothing;
35+
private SerializedProperty m_RotationLerpSmoothing;
36+
private SerializedProperty m_ScaleLerpSmoothing;
3437

3538
private SerializedProperty m_PositionMaximumInterpolationTimeProperty;
3639
private SerializedProperty m_RotationMaximumInterpolationTimeProperty;
@@ -77,6 +80,11 @@ public override void OnEnable()
7780
m_ScaleInterpolationTypeProperty = serializedObject.FindProperty(nameof(NetworkTransform.ScaleInterpolationType));
7881
m_ScaleMaximumInterpolationTimeProperty = serializedObject.FindProperty(nameof(NetworkTransform.ScaleMaxInterpolationTime));
7982

83+
m_PositionLerpSmoothing = serializedObject.FindProperty(nameof(NetworkTransform.PositionLerpSmoothing));
84+
m_RotationLerpSmoothing = serializedObject.FindProperty(nameof(NetworkTransform.RotationLerpSmoothing));
85+
m_ScaleLerpSmoothing = serializedObject.FindProperty(nameof(NetworkTransform.ScaleLerpSmoothing));
86+
87+
8088

8189
m_UseQuaternionSynchronization = serializedObject.FindProperty(nameof(NetworkTransform.UseQuaternionSynchronization));
8290
m_UseQuaternionCompression = serializedObject.FindProperty(nameof(NetworkTransform.UseQuaternionCompression));
@@ -198,36 +206,42 @@ private void DisplayNetworkTransformProperties()
198206
if (networkTransform.SynchronizePosition)
199207
{
200208
DrawPropertyField(m_PositionInterpolationTypeProperty);
201-
// Only display when using Lerp.
202-
if (networkTransform.PositionInterpolationType == NetworkTransform.InterpolationTypes.Lerp)
209+
210+
BeginIndent();
211+
if (networkTransform.PositionInterpolationType != NetworkTransform.InterpolationTypes.SmoothDampening)
203212
{
204-
BeginIndent();
205213
DrawPropertyField(m_SlerpPosition);
214+
}
215+
DrawPropertyField(m_PositionLerpSmoothing);
216+
if (networkTransform.PositionLerpSmoothing)
217+
{
206218
DrawPropertyField(m_PositionMaximumInterpolationTimeProperty);
207-
EndIndent();
208219
}
220+
EndIndent();
209221
}
210222
if (networkTransform.SynchronizeRotation)
211223
{
212224
DrawPropertyField(m_RotationInterpolationTypeProperty);
213-
// Only display when using Lerp.
214-
if (networkTransform.RotationInterpolationType == NetworkTransform.InterpolationTypes.Lerp)
225+
226+
BeginIndent();
227+
DrawPropertyField(m_RotationLerpSmoothing);
228+
if (networkTransform.RotationLerpSmoothing)
215229
{
216-
BeginIndent();
217230
DrawPropertyField(m_RotationMaximumInterpolationTimeProperty);
218-
EndIndent();
219231
}
232+
EndIndent();
220233
}
221234
if (networkTransform.SynchronizeScale)
222235
{
223236
DrawPropertyField(m_ScaleInterpolationTypeProperty);
224-
// Only display when using Lerp.
225-
if (networkTransform.ScaleInterpolationType == NetworkTransform.InterpolationTypes.Lerp)
237+
238+
BeginIndent();
239+
DrawPropertyField(m_ScaleLerpSmoothing);
240+
if (networkTransform.ScaleLerpSmoothing)
226241
{
227-
BeginIndent();
228242
DrawPropertyField(m_ScaleMaximumInterpolationTimeProperty);
229-
EndIndent();
230243
}
244+
EndIndent();
231245
}
232246
EndIndent();
233247
EditorGUILayout.Space();

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

Lines changed: 102 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,16 @@ internal struct CurrentState
120120
public double EndTime;
121121
public float TimeToTargetValue;
122122
public float DeltaTime;
123+
public float DeltaTimePredict;
124+
public float MaxDeltaTime;
123125
public float LerpT;
126+
public float LerpTPredict;
124127
public bool TargetReached;
128+
public bool PredictingNext;
125129
public T CurrentValue;
126130
public T PreviousValue;
127131
public T PredictValue;
132+
public T PredictTarget;
128133

129134
private float m_AverageDeltaTime;
130135

@@ -143,7 +148,25 @@ public void AddDeltaTime(float deltaTime)
143148
m_AverageDeltaTime *= 0.5f;
144149
}
145150
DeltaTime = Math.Min(DeltaTime + m_AverageDeltaTime, TimeToTargetValue);
151+
DeltaTimePredict = Math.Min(DeltaTime + DeltaTimePredict, TimeToTargetValue + MaxDeltaTime);
146152
LerpT = TimeToTargetValue == 0.0f ? 1.0f : DeltaTime / TimeToTargetValue;
153+
if (PredictingNext)
154+
{
155+
LerpTPredict = TimeToTargetValue == 0.0f ? 1.0f : DeltaTimePredict / TimeToTargetValue;
156+
}
157+
else
158+
{
159+
LerpTPredict = LerpT;
160+
}
161+
}
162+
163+
public void SetTimeToTarget(float timeToTarget)
164+
{
165+
DeltaTimePredict = 0.0f;
166+
LerpTPredict = 0.0f;
167+
LerpT = 0.0f;
168+
DeltaTime = 0.0f;
169+
TimeToTargetValue = timeToTarget;
147170
}
148171

149172
public void ResetDelta()
@@ -166,11 +189,17 @@ public void Reset(T currentValue)
166189
Target = null;
167190
CurrentValue = currentValue;
168191
PreviousValue = currentValue;
192+
PredictValue = currentValue;
193+
PredictTarget = currentValue;
169194
TargetReached = false;
170-
// When reset, we consider ourselves to have already arrived at the target (even if no target is set)
195+
PredictingNext = false;
171196
LerpT = 0.0f;
197+
LerpTPredict = 0.0f;
172198
EndTime = 0.0;
173199
StartTime = 0.0;
200+
TimeToTargetValue = 0.0f;
201+
DeltaTime = 0.0f;
202+
DeltaTimePredict = 0.0f;
174203
ResetDelta();
175204
}
176205
}
@@ -222,6 +251,8 @@ public void Reset(T currentValue)
222251
/// </summary>
223252
private protected bool m_IsAngularValue;
224253

254+
private bool m_WasPredictedLerp;
255+
225256
/// <summary>
226257
/// Resets interpolator to the defaults.
227258
/// </summary>
@@ -273,7 +304,7 @@ private void InternalReset(T targetValue, double serverTime, bool isAngularValue
273304
/// <param name="renderTime">render time: the time in "ticks ago" relative to the current tick latency</param>
274305
/// <param name="minDeltaTime">minimum time delta (defaults to tick frequency)</param>
275306
/// <param name="maxDeltaTime">maximum time delta which defines the maximum time duration when consuming more than one item from the buffer</param>
276-
private void TryConsumeFromBuffer(double renderTime, float minDeltaTime, float maxDeltaTime)
307+
private void TryConsumeFromBuffer(double renderTime, float minDeltaTime, float maxDeltaTime, bool isPredictedLerp)
277308
{
278309
BufferedItem? previousItem = null;
279310
var startTime = 0.0;
@@ -294,7 +325,7 @@ private void TryConsumeFromBuffer(double renderTime, float minDeltaTime, float m
294325
if (!noStateSet)
295326
{
296327
potentialItemNeedsProcessing = (potentialItem.TimeSent <= renderTime) && potentialItem.TimeSent >= InterpolateState.Target.Value.TimeSent;
297-
currentTargetTimeReached = InterpolateState.TargetTimeAproximatelyReached(potentialItemNeedsProcessing ? 1.5f : 1.0f);
328+
currentTargetTimeReached = InterpolateState.TargetTimeAproximatelyReached(potentialItemNeedsProcessing ? 1.15f : 0.85f);
298329
if (!potentialItemNeedsProcessing && !InterpolateState.TargetReached)
299330
{
300331
InterpolateState.TargetReached = IsAproximately(InterpolateState.CurrentValue, InterpolateState.Target.Value.Item);
@@ -317,24 +348,33 @@ private void TryConsumeFromBuffer(double renderTime, float minDeltaTime, float m
317348
alreadyHasBufferItem = true;
318349
InterpolateState.PredictValue = InterpolateState.CurrentValue;
319350
InterpolateState.PreviousValue = InterpolateState.CurrentValue;
351+
InterpolateState.SetTimeToTarget(minDeltaTime);
320352
InterpolateState.TimeToTargetValue = minDeltaTime;
321353
startTime = InterpolateState.Target.Value.TimeSent;
322354
InterpolateState.TargetReached = false;
355+
InterpolateState.PredictingNext = false;
356+
InterpolateState.MaxDeltaTime = maxDeltaTime;
323357
}
324358
else
325359
{
326360
if (!alreadyHasBufferItem)
327361
{
328362
alreadyHasBufferItem = true;
329-
startTime = InterpolateState.Target.Value.TimeSent;
330-
//InterpolateState.PreviousValue = InterpolateState.CurrentValue;
331-
//InterpolateState.PredictValue = InterpolateState.CurrentValue;
332-
InterpolateState.LerpT = 0.0f;
333363
InterpolateState.TargetReached = false;
364+
InterpolateState.PredictingNext = false;
365+
startTime = InterpolateState.Target.Value.TimeSent;
366+
InterpolateState.PredictTarget = target.Item;
367+
InterpolateState.MaxDeltaTime = maxDeltaTime;
368+
if (m_BufferQueue.TryPeek(out BufferedItem lookAheadItem))
369+
{
370+
InterpolateState.PredictTarget = Interpolate(target.Item, lookAheadItem.Item, InterpolateState.AverageDeltaTime);
371+
InterpolateState.PredictingNext = true;
372+
}
334373
}
335374
// TODO: We might consider creating yet another queue to add these items to and assure that the time is accelerated
336375
// for each item as opposed to losing the resolution of the values.
337-
InterpolateState.TimeToTargetValue = Mathf.Clamp((float)(target.TimeSent - startTime), minDeltaTime, maxDeltaTime);
376+
var timeToTarget = Mathf.Clamp((float)(target.TimeSent - startTime), minDeltaTime, maxDeltaTime);
377+
InterpolateState.SetTimeToTarget(timeToTarget);
338378
InterpolateState.Target = target;
339379
}
340380
InterpolateState.ResetDelta();
@@ -353,6 +393,14 @@ private void TryConsumeFromBuffer(double renderTime, float minDeltaTime, float m
353393
}
354394
}
355395

396+
internal void ResetCurrentState()
397+
{
398+
if (InterpolateState.Target.HasValue)
399+
{
400+
InterpolateState.Reset(InterpolateState.CurrentValue);
401+
}
402+
}
403+
356404
/// <summary>
357405
/// Interpolation Update to use when smooth dampening is enabled on a <see cref="Components.NetworkTransform"/>.
358406
/// </summary>
@@ -364,28 +412,45 @@ private void TryConsumeFromBuffer(double renderTime, float minDeltaTime, float m
364412
/// <param name="tickLatencyAsTime">The tick latency in relative local time.</param>
365413
/// <param name="minDeltaTime">The minimum time delta between the current and target value.</param>
366414
/// <param name="maxDeltaTime">The maximum time delta between the current and target value.</param>
415+
/// <param name="isLerpAndExtrapolate">Determines whether to use smooth dampening or extrapolation.</param>
416+
/// <param name="lerpSmoothing">Determines if lerp smoothing is enabled for this instance.</param>
367417
/// <returns>The newly interpolated value of type 'T'</returns>
368-
internal T Update(float deltaTime, double tickLatencyAsTime, float minDeltaTime, float maxDeltaTime)
418+
internal T Update(float deltaTime, double tickLatencyAsTime, float minDeltaTime, float maxDeltaTime, bool isLerpAndExtrapolate, bool lerpSmoothing)
369419
{
370-
TryConsumeFromBuffer(tickLatencyAsTime, minDeltaTime, maxDeltaTime);
371-
// Only interpolate when there is a start and end point and we have not already reached the end value
372-
if (InterpolateState.Target.HasValue && !InterpolateState.TargetReached)
420+
TryConsumeFromBuffer(tickLatencyAsTime, minDeltaTime, maxDeltaTime, isLerpAndExtrapolate);
421+
// Only begin interpolation when there is a start and end point
422+
if (InterpolateState.Target.HasValue)
373423
{
374-
InterpolateState.AddDeltaTime(deltaTime);
375-
424+
// As long as the target hasn't been reached, interpolate or smooth dampen.
425+
if (!InterpolateState.TargetReached)
376426
{
377-
378-
// Smooth dampen our current time
379-
InterpolateState.PreviousValue = SmoothDamp(InterpolateState.PreviousValue, InterpolateState.Target.Value.Item, ref m_RateOfChange, InterpolateState.TimeToTargetValue, InterpolateState.DeltaTime);
380-
InterpolateState.PredictValue = SmoothDamp(InterpolateState.PredictValue, InterpolateState.Target.Value.Item, ref m_PredictedRateOfChange, InterpolateState.TimeToTargetValue, Mathf.Min(InterpolateState.TimeToTargetValue, InterpolateState.DeltaTime + InterpolateState.AverageDeltaTime));
381-
// Smooth dampen a predicted time based on our minimum delta time
382-
//var predict = SmoothDamp(InterpolateState.CurrentValue, InterpolateState.Target.Value.Item, ref m_PredictedRateOfChange, InterpolateState.TimeToTargetValue, Mathf.Min(InterpolateState.TimeToTargetValue, InterpolateState.DeltaTime + InterpolateState.AverageDeltaTime));
383-
384-
// Lerp between the current and predicted.
385-
// Note: Since smooth dampening cannot over shoot, both current and predict will eventually become the same or will be very close to the same.
386-
// Upon stopping motion, the final resing value should be a very close aproximation of the authority side.
387-
InterpolateState.CurrentValue = Interpolate(InterpolateState.PreviousValue, InterpolateState.PredictValue, deltaTime);
427+
InterpolateState.AddDeltaTime(deltaTime);
428+
429+
// SmoothDampen or LerpExtrapolateBlend
430+
if (!isLerpAndExtrapolate)
431+
{
432+
InterpolateState.PreviousValue = SmoothDamp(InterpolateState.PreviousValue, InterpolateState.Target.Value.Item, ref m_RateOfChange, InterpolateState.TimeToTargetValue, InterpolateState.DeltaTime);
433+
var predictedTime = InterpolateState.PredictingNext ? InterpolateState.DeltaTime : Mathf.Min(InterpolateState.TimeToTargetValue, InterpolateState.DeltaTime + InterpolateState.AverageDeltaTime);
434+
InterpolateState.PredictValue = SmoothDamp(InterpolateState.PredictValue, InterpolateState.PredictTarget, ref m_PredictedRateOfChange, InterpolateState.TimeToTargetValue, predictedTime);
435+
}
436+
else
437+
{
438+
InterpolateState.PreviousValue = Interpolate(InterpolateState.PreviousValue, InterpolateState.Target.Value.Item, InterpolateState.LerpT);
439+
InterpolateState.PredictValue = InterpolateUnclamped(InterpolateState.PredictValue, InterpolateState.Target.Value.Item, InterpolateState.LerpTPredict);
440+
}
388441

442+
// Lerp between the PreviousValue and PredictedValue (extrapolated) using this frame's delta time
443+
var targetValue = Interpolate(InterpolateState.PreviousValue, InterpolateState.PredictValue, deltaTime);
444+
if (lerpSmoothing)
445+
{
446+
// If lerp smoothing is enabled, then smooth current value towards the target value
447+
InterpolateState.CurrentValue = Interpolate(InterpolateState.CurrentValue, targetValue, deltaTime / MaximumInterpolationTime);
448+
}
449+
else
450+
{
451+
// Otherwise, just assign the target value.
452+
InterpolateState.CurrentValue = targetValue;
453+
}
389454
}
390455
}
391456
m_NbItemsReceivedThisFrame = 0;
@@ -467,8 +532,9 @@ private void TryConsumeFromBuffer(double renderTime, double serverTime)
467532
/// <param name="deltaTime">time since last call</param>
468533
/// <param name="renderTime">our current time</param>
469534
/// <param name="serverTime">current server time</param>
535+
/// <param name="lerpSmoothing">Determines if lerp smoothing is enabled for this instance.</param>
470536
/// <returns>The newly interpolated value of type 'T'</returns>
471-
public T Update(float deltaTime, double renderTime, double serverTime)
537+
public T Update(float deltaTime, double renderTime, double serverTime, bool lerpSmoothing = true)
472538
{
473539
TryConsumeFromBuffer(renderTime, serverTime);
474540
// Only interpolate when there is a start and end point and we have not already reached the end value
@@ -495,9 +561,16 @@ public T Update(float deltaTime, double renderTime, double serverTime)
495561
}
496562
var target = Interpolate(InterpolateState.PreviousValue, InterpolateState.Target.Value.Item, t);
497563

498-
// Assure our MaximumInterpolationTime is valid and that the second lerp time ranges between deltaTime and 1.0f.
499-
var secondLerpTime = Mathf.Clamp(deltaTime / Mathf.Max(deltaTime, MaximumInterpolationTime), deltaTime, 1.0f);
500-
InterpolateState.CurrentValue = Interpolate(InterpolateState.CurrentValue, target, secondLerpTime);
564+
if (lerpSmoothing)
565+
{
566+
// Assure our MaximumInterpolationTime is valid and that the second lerp time ranges between deltaTime and 1.0f.
567+
var secondLerpTime = Mathf.Clamp(deltaTime / MaximumInterpolationTime, deltaTime, 1.0f);
568+
InterpolateState.CurrentValue = Interpolate(InterpolateState.CurrentValue, target, secondLerpTime);
569+
}
570+
else
571+
{
572+
InterpolateState.CurrentValue = target;
573+
}
501574
}
502575
m_NbItemsReceivedThisFrame = 0;
503576
return InterpolateState.CurrentValue;

0 commit comments

Comments
 (0)