-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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] AnimationState improvements #621
Comments
This is partially done for spine-libgdx, including unit tests. Tabled until #48 is done. |
Testing #github Slack channel! |
From @pharan on May 7, 2016 20:26 (I want to see how discussions work/look here.)
Probably the same fix as case 3. But this might be also be important distinction. |
From @pharan on May 18, 2016 3:45 2 forum users recently looked for case 8 and this case: track 0, animation 1 playing in a loop I think this is case 2? In light of all this "mix" stuff, I also propose disambiguating some of the terminology. At least TrackEntry.mix would be nicer as TrackEntry.alpha so it's not confused (to be related) with the process of "mixing" between next and previous. (ie, Just for its clarity, I'm partial to the term "crossfade" to refer to the process of fading between previous and next animations. But I also think it looks a bit weird in the API, so I could go for something else. I agree that "Mix" is a good term for the process that would otherwise be known as "Apply, but with Alpha against the current values". |
I believe those cases are described above. I've rewritten the cases in a better format and checked the ones that are complete in the dev branch. TrackEntry.alpha is OK, though it breaks existing code for maybe little gain. |
This stuff is great. Really looking forward to #2!! |
Linking this topic since we talked about threshold values and AttachmentTimelines during mixing, (but only events during mixing is listed). http://esotericsoftware.com/forum/Libgdx-Attachment-Bug-Fix-Proposal-6614 |
Clarification on Current implementation code: case: related case: |
BinaryCats reported this weird issue. Makes sense to me, though it might be super specific. case: This is also a consistency thing: The expected behavior is how it would act if the track was not empty, because of this code in AnimationState.setCurrent:
https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java#L194-L199 bcats fix: add |
…pply attachment timelines or fire events for an animation being mixed out. #621
- Renamed `previous` to `mixingFrom` for clarity. - Added `trackEntry` method to fully initialize TrackEntry. - Moved `mixDuration` initialization to happen when TrackEntry is initialized. This allows mix times to be specified (or changed) through the TrackEntry, without using AnimationStateData. - Made EventQueue static to ease porting. - Javadocs. #621
- Added `animationStart` so a portion of an animation can be looped. - Changed timing fields to: trackTime, trackLast, trackEnd, animationStart, animationEnd, animationLast - Removed default *Threshold fields. People can just set it on the track entry if they don't like the defaults. - Removed `loopCount` from complete event. People can calculate it based on track time. #621 closes #535 closes #593
I believe all of the comments and linked issues above have been handled. |
I think 6 may be three separate issues/mislabeled. It would be:
Result: Aim animation is immediately applied with alpha: 1. There is no previous TrackEntry to mix from. I think:
Result: "run" animation immediately starts because there is no previous animation to mix from. I think this case is mostly undefinable and less important (users haven't had problems with this/nobody's looking for it), but may also be solved if 6.2 is solved. |
Pharan's understanding matches my own. I've had scenarios where an upper body animation is playing on another track to override the full body idle or run animation on the arms and you want to blend back into it. |
Idea for case 2:
pros:
cons:
|
The above idea for case 2 is different from my current implementation of the modified AnimationState. That just did the reset as tracks were applied and had no bool per TrackEntry. I think users should have the convenience of just setting a bool on the AnimationState so this resetting behavior is applied with all setAnimation/addAnimation calls. From what I can tell, this is the most common case. And the hands-off case is for users who plan complex animations. |
Lots of work has been done in the dev-setupPose branch, for the above and other niceties: Assuming what has been done so far properly solves all the uses cases, what we have left is 5, 6 (including @pharan's expansion), and 10. 5 is probably pretty straightforward, we'll keep a linked list of animations being mixed out. We already have a I have a feeling 6 may be best implemented using an empty animation. Eg:
This would result in the run animation mixing in from the setup pose for 0.1 seconds, playing, then mixing out for 0.2 seconds. This gives explicit control in the usual way over how mixing happens or doesn't happen, which are both valid use cases. Internally an empty animation is used, so we don't litter the code with null checks. This is already being used for the new 10 is maybe the hardest, as there is no way to know which direction is the correct rotation. Additive mixing doesn't appear to be a solution, since it doesn't handle layering and mixing animations. The only real solution is likely for bones to describe some limits to their rotations that can be respected when mixing. This is beyond the scope of this AnimationState fix up effort, so 10 is likely to be pushed to a later date. |
The empty animation approach is committed to the
This sets an empty animation, which mixes to the setup pose over 0.1f (of course, that mix would only be useful if an animation was already playing). After that, it mixes from the setup pose to the |
Sniff, it's beautiful. On Aug 28, 2016 6:08 PM, "Nathan Sweet" notifications@github.com wrote:
|
Everything we wanted to do here is now done in the |
The multiple mixing setting has been removed. Multiple mixing is always done and dipping is avoided for adjacent track entries. This is pretty close to complete. Mixing `a -> b` where both key property `x` avoids dipping. If the mix is interrupted by `c`, the dipping is properly mixed out. However, if `c` *also* keys `x`, a dip is seen. This is good test JSON data: http://n4te.com/x/1948-6b1G.txt The problem can be seen by doing `m1 -> m1-dup` then interrupting the mix with `m1`. Related issues: #621, #815, #899, #900
From @NathanSweet on May 7, 2016 16:14
a
b
Result:
a
is left in the state it was when the animation changed,b
snaps into position.Expected:
a
mixes back to the setup pose,b
mixes from the setup pose.Solution: Need a TrackEntry setting for animations to mix to/from the setup pose during mixing.
a
b
for the same slotResult: animation 1's attachment is shown if
a
key is after theb
key.Expected: highest track attachment is shown.
Solution: Don't use lastTime in AttachmentTimeline. Store attachment name for each slot to avoid excessive skin lookups, then get the attachment from the skeleton/skin lazily. If name is the same, we can't avoid the skin lookup entirely (eg the skin may have changed).
Result: Animation 1 never fires events during mixing.
Expected: Events for previous animation can be enabled or disabled as needed.
Solution: TrackEntry "event threshold" setting for what percentage of the mix is required for events to be fired. Could a single threshold setting for events and attachment keys (12 below).
Result: With a long mix time, animation 1 disappears when animation 3 starts.
Expected: All animations are mixed.
Solution: Support mixing any number of animations. Mixing is order dependent.
Result: Aim animation mix starts at 1 because there is no previous animation to mix from.
Expected: Aim animation should be mixed in.
Solution: Currently have TrackEntry.mix but no way for it to change over time.
Result: A small amount of time is lost at each animation change, as it takes a frame to change animations.
Expected: Sum of elapsed time == sum of animation durations.
Solution: Carry any leftover time from last animation to next.
Result: Calling setAnimation from
end
event causes stackoverflow.Expected: No crash.
Solution: Defer events so changes in callbacks can't corrupt internal state.
Result: scaleX mixes from 1 to -1.2.
Expected: Depending on the animation, scaleX should either transition from 1 to -1.2 or instantly flip to negative scale.
Solution: TrackEntry setting that causes scaleX to be either -1.2 (not mix at all) or mix from -1 to -1.2 (mix but use sign from animation 2). Could also have a threshold similar to events to define at what mix percentage is the scale sign is taken from animation 2.
Result: Rotation mixes from 0 to 170.
Expected: Depending on the skeleton, rotation may need to take the other direction, eg to avoid a shoulder rotating unrealistically.
Solution: Additive mixing would preserve the rotation directions of the animations being mixed, but has other problems such as higher tracks mixing with lower ones. Possibly we could provide an angle that rotation mixing should not cross, but this seems like a complex solution.
Expected: When animations are interrupted, events are not always fired in a sensible order. Eg, all events are fired after
complete
, even if some events were from the last few frames of the animation and some from the first few frames.Solution: Add
interrupt
event. Define and enforce the order events are fired using an event queue.Result: Animation 1 changes attachment visibility during mixing.
Expected: Attachment visibility changes for previous animation can be enabled or disabled as needed.
Solution: TrackEntry "attachment visibility threshold" setting for what percentage of the mix is required for attachment visibility to be changed. Could be a single threshold setting for events (4 above) and attachment keys.
Result: TrackEntry
mix
(how much of this animation is applied) has nothing to do withmixTime
ormixDuration
(crossfading from previous animation to this animation).Solution: Rename to
alpha
.Solution: Similar to 4 and 12 above, draw order timelines for animations being mixed out should use a threshold setting so changes after the new animation are set can be disallowed.
See this crude image.
1. The animation being mixed out is rotating the bone.
2. The new animation has the bone keyed pointing down.
3. The result is a mix of 1 and 2.
4. The animation being mixed continues rotating the bone.
5. The new animation still has the bone keyed pointing down.
6. The result is a mix of 4 and 5, but the shortest rotation now results in the bone jumping to the other side.
Solution: One "fix" is to not update the
trackTime
of themixingFrom
track. This usually looks OK for short mix times. Any other ideas?Copied from original issue: badlogic/spine-internal#49
The text was updated successfully, but these errors were encountered: