Please note that the way to use hold previous is to set it to true on all track entries for track 1. Also, when using hold previous, all animations on track 1 must key all the same properties. If not, then you may see snapping when the mix duration has elapsed (when the old animation keys something the new one doesn't). The only exception is if you are using an empty animation to mix out the animation on track 1, then you should not set hold previous to true to allow the old animation to mix out.
In other words, any time you set or add an animation for a track, you get a TrackEntry. To use hold previous, any time you set or add an animation for track 1, you should get the TrackEntry and set HoldPrevious to true, as you have shown.
By "keying the same properties", I mean that all the animations used on track 1 should have timelines for the properties any of the other track 1 animations have timelines for. All timelines should have keys on frame 0. There is no requirement to set keys at the same times or have the same animation lengths.
It should help if you understand how it works, but brace yourself because thinking through AnimationState can be tricky!
Consider track 1 mixing from animation A to B. Normally A is mixed out while B mixes in. Let's say A and B key the same translation bone value. It is reasonable to expect the bone to not move during the mix, however if A mixes to the setup pose while B is mixing in, the bone translation will "dip" toward the setup pose, then B takes over and moves it back. This is the "dipping" problem you are seeing.
When dipping occurs on the lowest track that keys a property, we can fix it. When A is the first animation to key the bone translation, AnimationState knows it can safely apply A fully instead of mixing it out. This is safe because no lower track is keying the bone translation, so applying it fully won't overwrite values from other tracks. So A is applied fully, then B is applied mixing from A's position to B's position. This gives us the mixing we want, without any dipping. :greatsuccess:
However, we cannot apply such a fix if a lower track is keying the same property. Say Z is on track 0, A is on track 1, and then we are mixing from A to B on track 1. Z, A, and B all key the same bone translation (same or different values, doesn't matter). Z is applied first. Next A is applied, but we can't use the dipping fix because we want to apply A on top of the value Z sets. That is because A may be mixing in or have TrackEntry alpha set, so may mix with the value Z set. So we mix A out while we mix B in, and that causes dipping: the bone moves from A's position toward the Z's position as A is mixed out, then moves to B's position as B is fully mixed in. :headwall:
Now consider the same Z, A, B scenario when B has hold previous = true. Z is applied first. Next A is applied fully, because hold previous means that the previous animation is applied fully instead of being mixed out. Note that applying A fully means any value Z set is overwritten. Next B is mixed in, so the bone position mixes from A to B without any dipping.
Still with me? Good! :cooldoge:
Finally to get to my point: why do A and B need to key the same properties? Let's say Z and A keys a bone translation that B does not:
Without hold previous, first Z is applied. Next A is applied mixing out: over the mix duration the bone position moves from A's position to Z's position. Lastly B is applied and the bone is not changed since B does not key it. When the mix from A to B is finished, A is no longer applied and the bone is at Z's position.
With hold previous, which we need to fix dipping, first Z is applied. Next A is applied fully, so the bone is set to A's position (the position set by Z is overwritten). Lastly B is applied, which doesn't change the bone. When the mix from A to B is finished, A is no longer applied so the bone jumps from A's position to Z's position. Such jumping is undesirable. :scared:
How to fix this? B should set a key for the bone. Then with hold previous, first Z is applied. Next A is applied fully, so the bone is set to A's position. Lastly B is applied mixing in, so the bone position changes from A's position to B's position. When the mix from A to B is finished, A is no longer applied and the bone is at Z's position without any jumping.
Ideally that makes sense to you. If all that is too much, then just follow the advice that all your track 1 animations have timelines for the same properties. :wounded:
Note that another way to setup your skeleton, as mentioned in the issue, is to not key the bones in track 0 animations that you want to control in track 1 animations. This will make the dipping go away because AnimationState can fix it, as described above. If you were keying bones on track 0 for an idle animation, you could instead apply the idle animation on track 2 using additive. This means first the animations for tracks 0 and 1 are applied, then the animation for track 2 is applied by adding the keyed values to what was set by lower tracks. To do that set TrackEntry mixBlend
to MixBlend add
.
You can experiment using the Preview view. I don't suggest building all the animations and implementing it at runtime until it is working like you want in Preview. You can set the speed to very slow or even 0 to give yourself time to queue up other animations in Preview.