Skip to content

Commit

Permalink
GLTFRecorder: fix issue where resulting animation would have linear i…
Browse files Browse the repository at this point in the history
…nterpolation for cases where a jump was expected
  • Loading branch information
wschnepp authored and hybridherbst committed Feb 26, 2024
1 parent cde6ca3 commit f8d50d4
Showing 1 changed file with 29 additions and 5 deletions.
34 changes: 29 additions & 5 deletions Runtime/Scripts/Timeline/GLTFRecorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ internal class Track
private AnimationData tr;
private ExportPlan plan;
private Dictionary<double, object> samples;
private object lastSample;
private Tuple<double, object> lastSample = null;
private Tuple<double, object> secondToLastSample = null;

public Track(AnimationData tr, ExportPlan plan, double time)
{
Expand All @@ -245,11 +246,34 @@ public void SampleIfChanged(double time)
var value = plan.Sample(tr);
if (value == null || (value is Object o && !o))
return;
if (!value.Equals(lastSample))
{
samples[time] = value;
lastSample = value;
// As a memory optimization we want to be able to skip identical samples.
// But, we cannot always skip samples when they are identical to the previous one - otherwise cases like this break:
// - First assume an object is invisible at first (by having a scale of (0,0,0))
// - At some point in time, it is instantaneously set "visible" by updating its scale from (0,0,0) to (1,1,1)
// If we simply skip identical samples on insert, instead of a instantaneous
// visibility/scale changes we get a linearly interpolated scale change because only two samples will be recorded:
// - one (0,0,0) at the start of time
// - (1,1,1) at the time of the visibility change
// What we want to get is
// - one sample with (0,0,0) at the start,
// - one with the same value right before the instantaneous change,
// - and then at the time of the change, we need a sample with (1,1,1)
// With this setup, now the linear interpolation only has an effect in the very short duration between the last two samples and we get the animation we want.

// How do we achieve both?
// Always sample & record and then on adding the next sample(s) we check
// if the *last two* samples were identical to the current sample.
// If that is the case we can remove/overwrite the middle sample with the new value.
if (lastSample != null
&& secondToLastSample != null
&& lastSample.Item2.Equals(secondToLastSample.Item2)
&& lastSample.Item2.Equals(value)) {

samples.Remove(lastSample.Item1);
}
samples[time] = value;
secondToLastSample = lastSample;
lastSample = new Tuple<double, object>(time, value);
}

}
Expand Down

0 comments on commit f8d50d4

Please sign in to comment.