public void Compute_Step4_InterpolateWithThreeOldEnoughSnapshots() { // add three old enough snapshots. // (localTime - bufferTime) SimpleSnapshot first = new SimpleSnapshot(0, 0, 1); SimpleSnapshot second = new SimpleSnapshot(1, 1, 2); SimpleSnapshot third = new SimpleSnapshot(2, 2, 2); buffer.Add(first.remoteTimestamp, first); buffer.Add(second.remoteTimestamp, second); buffer.Add(third.remoteTimestamp, third); // compute with initialized remoteTime and buffer time of 2 seconds // and a delta time to be sure that we move along it no matter what. double localTime = 4; double deltaTime = 0.5; double interpolationTime = 0; float bufferTime = 2; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should spit out the interpolated snapshot Assert.That(result, Is.True); // interpolation started just now, from 0. // and deltaTime is 0.5, so we should be at 0.5 now. Assert.That(interpolationTime, Is.EqualTo(0.5)); // buffer should be untouched, we are still interpolating between // the first two. third should still be there. Assert.That(buffer.Count, Is.EqualTo(3)); // computed snapshot should be interpolated in the middle Assert.That(computed.value, Is.EqualTo(1.5).Within(Mathf.Epsilon)); }
public void Compute_Step4_InterpolateWithTwoOldEnoughSnapshots() { // add two old enough snapshots // (localTime - bufferTime) SimpleSnapshot first = new SimpleSnapshot(0, 0, 1); // IMPORTANT: second snapshot delta is != 1 so we can be sure that // interpolationTime result is actual time, not 't' ratio. // for a delta of 1, absolute and relative values would // return the same results. SimpleSnapshot second = new SimpleSnapshot(2, 2, 2); buffer.Add(first.remoteTimestamp, first); buffer.Add(second.remoteTimestamp, second); // compute with initialized remoteTime and buffer time of 2 seconds // and a delta time to be sure that we move along it no matter what. double localTime = 4; double deltaTime = 1.5; double interpolationTime = 0; float bufferTime = 2; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should spit out the interpolated snapshot Assert.That(result, Is.True); // interpolation started just now, from 0. // and deltaTime is 1.5, so we should be at 1.5 now. Assert.That(interpolationTime, Is.EqualTo(1.5)); // buffer should be untouched, we are still interpolating between the two Assert.That(buffer.Count, Is.EqualTo(2)); // interpolationTime is at 1.5, so 3/4 between first & second. // computed snapshot should be interpolated at 3/4ths. Assert.That(computed.value, Is.EqualTo(1.75).Within(Mathf.Epsilon)); }
public void Compute_Step3_WaitsUntilBufferTime() { // add two snapshots that are barely not old enough // (localTime - bufferTime) // IMPORTANT: use a 'definitely old enough' remoteTime to make sure // that compute() actually checks LOCAL, not REMOTE time! SimpleSnapshot first = new SimpleSnapshot(0.1, 0.1, 0); SimpleSnapshot second = new SimpleSnapshot(0.9, 1.1, 0); buffer.Add(first.remoteTimestamp, first); buffer.Add(second.remoteTimestamp, second); // compute with initialized remoteTime and buffer time of 2 seconds // and a delta time to be sure that we move along it no matter what. double localTime = 3; double deltaTime = 0.5; double interpolationTime = 0; float bufferTime = 2; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should not spit out any snapshot to apply Assert.That(result, Is.False); // no interpolation should happen yet (not old enough) Assert.That(interpolationTime, Is.EqualTo(0)); // buffer should be untouched Assert.That(buffer.Count, Is.EqualTo(2)); }
public void Compute_Step5_OvershootWithEnoughSnapshots_2x_MovesToSecondNextSnapshot() { // add two old enough snapshots // (localTime - bufferTime) SimpleSnapshot first = new SimpleSnapshot(0, 0, 1); SimpleSnapshot second = new SimpleSnapshot(1, 1, 2); // IMPORTANT: third snapshot needs to be: // - a different time delta // to test if overflow is correct if deltas are different. // it's not obvious if we ever use t ratio between [0,1] where an // overflow of 0.1 between A,B could speed up B,C interpolation if // that's not the same delta, since t is a ratio. // - a different value delta to check if it really _interpolates_, // not just extrapolates further after A,B SimpleSnapshot third = new SimpleSnapshot(3, 3, 4); SimpleSnapshot fourth = new SimpleSnapshot(5, 5, 6); buffer.Add(first.remoteTimestamp, first); buffer.Add(second.remoteTimestamp, second); buffer.Add(third.remoteTimestamp, third); buffer.Add(fourth.remoteTimestamp, fourth); // compute with initialized remoteTime and buffer time of 2 seconds // and a delta time to be sure that we move along it no matter what. // -> interpolation time is already at '1' at the end. // -> compute will add 1.5 deltaTime // -> so we should overshoot beyond second and third even // // localTime is 7. fourth snapshot localTime is at 5. // bufferTime is 2. // so fourth is exactly old enough and we should move there. double localTime = 7; double deltaTime = 2.5; double interpolationTime = 1; float bufferTime = 2; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should spit out the interpolated snapshot Assert.That(result, Is.True); // interpolation started at the end = 1 // and deltaTime is 2.5, so we were at 4.5 internally. // we have more snapshots, so we: // * jump to third, subtract delta of 1-0 = 1 => 2.5 // * jump to fourth, subtract delta of 3-1 = 2 => 0.5 // * end up at 0.5 again, between third and fourth Assert.That(interpolationTime, Is.EqualTo(0.5)); // buffer's first entry should have been removed Assert.That(buffer.Count, Is.EqualTo(2)); // computed snapshot should be 1/4 way between second and third // because delta is 2 and interpolationTime is at 0.5 which is 1/4 Assert.That(computed.value, Is.EqualTo(4.5).Within(Mathf.Epsilon)); }
public void Compute_Step1_DefaultDoesNothing() { // compute with defaults double localTime = 0; double deltaTime = 0; double interpolationTime = 0; float bufferTime = 0; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should not spit out any snapshot to apply Assert.That(result, Is.False); // no interpolation should have happened yet Assert.That(interpolationTime, Is.EqualTo(0)); // buffer should still be untouched Assert.That(buffer.Count, Is.EqualTo(0)); }
public void Compute_Step4_InterpolateAfterLongPause() { // add two immediate, and one that arrives 100s later // (localTime - bufferTime) SimpleSnapshot first = new SimpleSnapshot(0, 0, 0); SimpleSnapshot second = new SimpleSnapshot(1, 1, 1); SimpleSnapshot third = new SimpleSnapshot(101, 2, 101); buffer.Add(first.remoteTimestamp, first); buffer.Add(second.remoteTimestamp, second); buffer.Add(third.remoteTimestamp, third); // compute where we are half way between first and second, // and now are updated 1 minute later. double localTime = 103; // 1011+bufferTime so third snapshot is old enough double deltaTime = 98.5; // 99s - interpolation time double interpolationTime = 0.5; // half way between first and second float bufferTime = 2; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should spit out the interpolated snapshot Assert.That(result, Is.True); // interpolation started at 0.5, right between first & second. // we received another snapshot at t=101. // delta = 98.5 seconds // => interpolationTime = 99 // => overshoots second goal, so we move to third goal and subtract 1 // => so we should be at 98 now Assert.That(interpolationTime, Is.EqualTo(98)); // we moved to the next snapshot. so only 2 should be in buffer now. Assert.That(buffer.Count, Is.EqualTo(2)); // delta between second and third is 100. // interpolationTime is at 98 // interpolationTime is relative to second.time // => InverseLerp(1, 101, 1 + 98) = 0.98 // which is at 98% of the value // => Lerp(1, 101, 0.98): 101-1 is 100. 98% are 98. relative to '1' // makes it 99. Assert.That(computed.value, Is.EqualTo(99).Within(Mathf.Epsilon)); }
public void Compute_Step5_OvershootWithoutEnoughSnapshots() { // add two old enough snapshots // (localTime - bufferTime) SimpleSnapshot first = new SimpleSnapshot(0, 0, 1); SimpleSnapshot second = new SimpleSnapshot(1, 1, 2); buffer.Add(first.remoteTimestamp, first); buffer.Add(second.remoteTimestamp, second); // compute with initialized remoteTime and buffer time of 2 seconds // and a delta time to be sure that we move along it no matter what. // -> interpolation time is already at '1' at the end. // -> compute will add 0.5 deltaTime // -> so we should NOT overshoot aka extrapolate beyond second snap. double localTime = 3; double deltaTime = 0.5; double interpolationTime = 1; float bufferTime = 2; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should spit out the interpolated snapshot Assert.That(result, Is.True); // interpolation started at the end = 1 // and deltaTime is 0.5, so it's at 1.5 internally. // // BUT there's NO reason to overshoot interpolationTime if there's // no other snapshots to move to. // interpolationTime overshoot is only for smooth transitions WHILE // moving. // for example, if we keep overshooting to 100, then we would // instantly skip the next 20 snapshots. // => so it should be capped at second.remoteTime Assert.That(interpolationTime, Is.EqualTo(1)); // buffer should be untouched, we are still interpolating between the two Assert.That(buffer.Count, Is.EqualTo(2)); // computed snapshot should NOT extrapolate beyond second snap. Assert.That(computed.value, Is.EqualTo(2).Within(Mathf.Epsilon)); }
public void Compute_Step4_InterpolateWithCatchup() { // add two old enough snapshots // (localTime - bufferTime) SimpleSnapshot first = new SimpleSnapshot(0, 0, 1); SimpleSnapshot second = new SimpleSnapshot(1, 1, 2); buffer.Add(first.remoteTimestamp, first); buffer.Add(second.remoteTimestamp, second); // start applying 25% catchup per excess when > 2. int catchupThreshold = 2; float catchupMultiplier = 0.25f; // two excess snapshots to make sure that multiplier is accumulated SimpleSnapshot excess1 = new SimpleSnapshot(2, 2, 3); SimpleSnapshot excess2 = new SimpleSnapshot(3, 3, 4); buffer.Add(excess1.remoteTimestamp, excess1); buffer.Add(excess2.remoteTimestamp, excess2); // compute with initialized remoteTime and buffer time of 2 seconds // and a delta time to be sure that we move along it no matter what. double localTime = 3; double deltaTime = 0.5; double interpolationTime = 0; float bufferTime = 2; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should spit out the interpolated snapshot Assert.That(result, Is.True); // interpolation started just now, from 0. // and deltaTime is 0.5 + 50% catchup, so we should be at 0.75 now Assert.That(interpolationTime, Is.EqualTo(0.75)); // buffer should be untouched, we are still interpolating between // the first two. Assert.That(buffer.Count, Is.EqualTo(4)); // computed snapshot should be interpolated in 3/4 because // interpolationTime is at 3/4 Assert.That(computed.value, Is.EqualTo(1.75).Within(Mathf.Epsilon)); }
public void Compute_Step3_WaitsForSecondSnapshot() { // add a snapshot at t = 0 SimpleSnapshot first = new SimpleSnapshot(0, 0, 0); buffer.Add(first.remoteTimestamp, first); // compute at localTime = 2 with bufferTime = 1 // so the threshold is anything < t=1 double localTime = 2; double deltaTime = 0; double interpolationTime = 0; float bufferTime = 1; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should not spit out any snapshot to apply Assert.That(result, Is.False); // no interpolation should happen yet (not enough snapshots) Assert.That(interpolationTime, Is.EqualTo(0)); // buffer should be untouched Assert.That(buffer.Count, Is.EqualTo(1)); }
public void Compute_Step5_OvershootWithEnoughSnapshots_NextIsntOldEnough() { // add two old enough snapshots // (localTime - bufferTime) // // IMPORTANT: second.time needs to be != second.time-first.time // to guarantee that we cap interpolationTime (which is // RELATIVE from 0..delta) at delta, not at second.time. // this was a bug before. SimpleSnapshot first = new SimpleSnapshot(1, 1, 1); SimpleSnapshot second = new SimpleSnapshot(2, 2, 2); // IMPORTANT: third snapshot needs to be: // - a different time delta // to test if overflow is correct if deltas are different. // it's not obvious if we ever use t ratio between [0,1] where an // overflow of 0.1 between A,B could speed up B,C interpolation if // that's not the same delta, since t is a ratio. // - a different value delta to check if it really _interpolates_, // not just extrapolates further after A,B SimpleSnapshot third = new SimpleSnapshot(4, 4, 4); buffer.Add(first.remoteTimestamp, first); buffer.Add(second.remoteTimestamp, second); buffer.Add(third.remoteTimestamp, third); // compute with initialized remoteTime and buffer time of 2 seconds // and a delta time to be sure that we move along it no matter what. // -> interpolation time is already at '1' at the end. // -> compute will add 0.5 deltaTime // -> so we overshoot beyond the second one and move to the next // // localTime is at 4 // third snapshot localTime is at 4. // bufferTime is 2, so it is NOT old enough and we should wait! double localTime = 4; double deltaTime = 0.5; double interpolationTime = 1; float bufferTime = 2; int catchupThreshold = Int32.MaxValue; float catchupMultiplier = 0; bool result = SnapshotInterpolation.Compute(localTime, deltaTime, ref interpolationTime, bufferTime, buffer, catchupThreshold, catchupMultiplier, SimpleSnapshot.Interpolate, out SimpleSnapshot computed); // should still spit out a result between first & second. Assert.That(result, Is.True); // interpolation started at the end = 1 // and deltaTime is 0.5, so we were at 1.5 internally. // // BUT there's NO reason to overshoot interpolationTime while we // wait for the next snapshot which isn't old enough. // we stopped movement anyway. // interpolationTime overshoot is only for smooth transitions WHILE // moving. // for example, if we overshoot to 100 while waiting, then we would // instantly skip the next 20 snapshots. // => so it should be capped at max // => which is always 0..delta, NOT first.time .. second.time!! Assert.That(interpolationTime, Is.EqualTo(1)); // buffer should be untouched. shouldn't have moved to third yet. Assert.That(buffer.Count, Is.EqualTo(3)); // computed snapshot should be all the way at second snapshot. Assert.That(computed.value, Is.EqualTo(2).Within(Mathf.Epsilon)); }