@@ -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