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] AttachmentTimeline sets to Setup state before first frame #1728

Closed
HaraldCsaszar opened this issue Jul 28, 2020 · 1 comment
Closed
Assignees
Labels

Comments

@HaraldCsaszar
Copy link
Collaborator

HaraldCsaszar commented Jul 28, 2020

When manually changing a slot's attachment to X followed by starting an animation hide-attachment which sets the slot's attachment to null in the middle of the animation, the attachment is set to SetupPose state at the start of the animation (before the first keyframe) instead of leaving it at X.

Even when starting the animation on a track > 0 this issue persists.

Reproduction asset:
esotericsoftware.com/files/issues/1728-HideMidAnim.zip

Code to reproduce:

skeletonAnimation.Skeleton.SetAttachment("gun", "gun-freeze");
skeletonAnimation.AnimationState.SetAnimation(1, "hide-attachment", false);

Expected:
The manually assigned "gun-freeze" (blue gun) attachment should be shown for the first 20 frames of the animation until the animation changes the attachment to null.
Actual:
The normal (green) "gun" attachment is shown all the time, even before the first key at frame 20.

@NathanSweet
Copy link
Member

Sorry for the delay in investigating this further. I'm not sure the expected behavior is correct.

History

In the past the behavior was that the skeleton state is kept except for what an animation keyed. This behavior allowed keeping game state in the skeleton (which weapon is equipped, where a bone is pointing, etc) which is arguably a Bad Idea because it couples the model/view.

Keeping the state meant you had to manage/reset that state yourself. Often that was done by keying everything to ensure that state from previous animations did not ruin subsequent animations. That was problematic because it required a lot of keys and was error prone because inevitably keying something was forgotten, especially after changing rigging. Also, the Spine editor resets the skeleton state each frame and it was confusing that animations would play differently at runtime, where that is not typically done.

Eventually we changed this so animations don't leave state behind. Except for explicitly clearing a track, when an animation is no longer applied the properties it keyed are reset to the setup pose. Instead of keeping state in the skeleton, typically game state is applied (eg setting attachments or modifying bone transforms) each frame after applying animations.

This history is related to this issue because we must decide what existing skeleton state is important and what the animation should set.

Current behavior

Currently the animation overwrites any existing state for all the properties it keys. If you set an attachment or rotate a bone, then apply an animation that keys those > frame 0, you will get the setup pose for the bone and attachment until the first key.

If we did not do this, you would get whatever state the skeleton had from previous animations until the first key. That would not be as bad as what we had previously: to avoid existing state you would need to key frame 0 only for the timelines in your animation, not the timelines for all properties. However, it would still be problematic in the same ways: extra keys and surprising behavior at runtime when frame 0 keys are forgetten.

Repro that shows behavior before the first key for a bone and attachment:
http://n4te.com/x/8502-HideMidAnim.zip

skeleton.setAttachment("gun", "gun-freeze");
skeleton.findBone("rear-upper-arm").setRotation(265);
state.setAnimation(1, "hide-attachment", false);

Implementation

The part of AnimationState responsible for this is the timelineMode. The first track entry on the lowest track number to key a property is given FIRST, which uses MixBlend.setup and that sets the setup pose before the first key.

That applies to all timelines except attachment timelines. For those, attachments need to be set so that deform timelines are mixed correctly, even when we ultimately don't want the attachments shown (eg when mixing out, depending on attachmentThreshold). If an attachment is set that we don't want shown OR an attachment timeline is before the first key, then the attachment is set to the setup pose. This is done using Slot attachmentState.

To change the behavior, those two areas would need to be modified. Maybe the MixBlend that FIRST uses could be configurable and the code that sets attachmentState = unkeyedState + SETUP could be avoided. However, a lot of testing would be required to ensure these changes do not cause problems for other AnimationState use cases (there are many!).

Conclusion

It is likely best to keep the current behavior. I recommend that instead of keeping state in the skeleton, set the state every frame after applying animations. Instead of letting an animation determine what is attached, keep that knowledge in the game state. To allow animations to manipulate game state, eg to change the equipped weapon at specific animation times, animation events can be used.

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

No branches or pull requests

2 participants