Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[runtimes] Hold previous on 3+ animations causes dipping #1738

Closed
HaraldCsaszar opened this issue Aug 12, 2020 · 4 comments
Closed

[runtimes] Hold previous on 3+ animations causes dipping #1738

HaraldCsaszar opened this issue Aug 12, 2020 · 4 comments
Assignees

Comments

@HaraldCsaszar
Copy link
Collaborator

Reported on this forum thread:
http://esotericsoftware.com/forum/Hold-Previous-question-14401
Reproduction asset link posted in topmost posting.

When 3+ animations are enqueued on track 1 and at least one on track 0, the setup pose (the arrow pointing downward) is part of the final result. The enqueued animations all key the same bone (the arrow pointing upward).

The following code reproduces the issue in SkeletonViewer, as well as in Unity:

state.setAnimation(0, "straight up", true);

TrackEntry entry = state.setAnimation(1, "straight up", false);
entry.mixDuration = 0.5f;
entry = state.addAnimation(1, "straight up", false, 0.5f);
entry.holdPrevious = true;
entry.mixDuration = 0.5f;
entry = state.addAnimation(1, "straight up", false, 0.01f);
entry.holdPrevious = true;
entry.mixDuration = 0.5f;
@NathanSweet
Copy link
Member

Here is a repro that is a little better because it behaves differently with/without holdPrevious:

state.setAnimation(0, "up right", true);
state.setAnimation(1, "up right", false);
TrackEntry entry = state.addAnimation(1, "idle", false, 0.1f);
entry.holdPrevious = true;
entry.mixDuration = 0.5f;
entry = state.addAnimation(1, "straight up", false, 0.35f);
entry.holdPrevious = true;
entry.mixDuration = 0.5f;

@NathanSweet
Copy link
Member

The repro is a "mix interruption", which is where a mix A->B is interrupted with C, giving (A->B)->C. When this happens interruptAlpha is stored to keep all the mixing smooth.

Currently when using holdPrevious we set all timelines for the entry before to HOLD so they will be applied 100%, without mixing. A secondary effect of HOLD, and the reason for this issue, is that the HOLD case always uses MixBlend.setup. That is done because the HOLD documentation says:

  1. This is the first timeline to set this property.

When we blindly use HOLD for all timelines, that isn't necessarily true, making MixBlend.setup the wrong choice.

Here's walking through the repro to show the problem. When we are applying (A->B)->C:

  1. A is applied fully (alpha is 1) because the B entry has holdPrevious.
  2. B would be applied fully because the C entry has holdPrevious, except C has interruptAlpha (alpha is 1 * interruptAlpha). When alpha < 1 the MixBlend determines what happens. HOLD uses MixBlend.setup and so we mix from the setup pose to B. However what we want is to mix from A to B, since that is what we were doing before C came along.
  3. We apply C but it doesn't matter because we already messed up.

We could introduce another flag which is the same as HOLD but uses the entry's MixBlend instead of MixBlend.setup. It could be named HOLD_PREV, since that is why we'll use it, or maybe HOLD_SUBSEQUENT since that describes what it does.

@NathanSweet
Copy link
Member

Exports for 3.8 and 4.0-beta: http://n4te.com/x/8499-export.zip

@HaraldCsaszar
Copy link
Collaborator Author

HaraldCsaszar commented Aug 13, 2020

  • spine-libgdx

  • spine-csharp
  • spine-xna
  • spine-monogame
  • spine-unity
  • spine-tk2d

  • spine-c
  • spine-cpp
  • spine-sfml
  • spine-cocos2d-objc
  • spine-cocos2dx
  • spine-ue4

  • spine-ts core
  • spine-ts webgl
  • spine-ts canvas
  • spine-ts threejs

  • spine-as3
  • spine-starling

  • spine-lua
  • spine-love
  • spine-corona

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants