• RuntimesUnity
  • Improper Transitions Between Animation Tracks

It sounds like the issue you're encountering with the head/neck bone rotation during animation transitions might be related to how the animations are being mixed or set in Unity. Here are a few steps and considerations that might help you resolve the problem:

  1. Check Animation Cleanup: Ensure that Animation Cleanup is disabled when exporting your skeleton from Spine. This setting can remove keys that are identical to the setup pose, which might cause issues when transitioning between animations.

  2. Preview in Unity: Verify if the animation looks correct in the Preview section of the Inspector window in Unity. If it looks correct there, the issue might be with the implementation in Unity. If it does not look correct, there might be an issue with the export from Spine.

  3. Mix Duration: Since you mentioned that setting the mix duration to a value greater than 0 shows the head rotating to an incorrect angle, it might be worth experimenting with different mix durations or explicitly setting the mix duration for specific transitions to see if it resolves the issue.

  4. SetToSetupPose: Ensure that the setToSetupPose method is not being called inappropriately in your code, as this can reset bones to their setup pose, potentially causing unexpected behavior during transitions.

  5. Check for Implementation Issues: Review the code where you are setting animations. Ensure that the SetAnimation method is being called correctly and that no other code is interfering with the animation state.

  6. Additional Keys: Make sure that all necessary keys are present in your animations. Sometimes, missing keys can cause bones to interpolate to unexpected positions.

If these steps do not resolve the issue, it might be helpful to send a minimal Unity project that demonstrates the problem to Esoteric Software for further investigation.

ExNull-Tyelor I have tested this with your Spine project and this seems to be a problem caused by the Inherit timeline. In the block animation, the Inherit of Rotation for the idle_neck bone is turned off at frame 0, and there is no Inherit timeline in block_to_idle, but at runtime, Inherit of Rotation is kept as is, so the angles are wrong.

This problem can be fixed by simply deleting the Inherit key in the block animation and moidying the idle_neck bone's rotation for it, but I'm not sure if it is correct that the Inherit state of the previous animation is remained to the subsequent animation, so I will check with the Spine team on this issue.

Instead of keying Inherit you can use a transform constraint on the idle_neck bone. This transform constraint will make the neck bone follow the chest bone similar to having it parented to it, but you can then set the Rotation Mix to 0 on the block animation, and rotate the neck so it looks correct.
The benefit of this is that Mix is not a Boolean (only on or off) so it will give you a smooth transition.

Thank you both for your replies!

I've sent this thread to the artist, and he solved the issue by explicitly keying Inherit for the Rotation of the neck bone on the block_to_idle animation based on the information you both provided.

Thanks again!

Hi, I am said artist. First, THANK YOU for clarifying this. I might have never guessed a lack of an inherit key in a separate animation to the be the cause of our failure. Am I to understand these Inherit keys are global to the entire skeleton, and not just individual animations? It seems that behavior might be inconsistent with other key behaviors, which I rely upon to return to the setup pose when each animation is played. It may also have implications for the Animation Cleanup feature.

Either way, this has been plaguing us for months because it's not something we can test for in the Spine editor nor the Preview pane. Perhaps adding the ability to chain animations in the Preview pane would help us and other developers when these problems arise.

I'd like to explain my choice of workaround for posterity, as all of your suggestions would have worked as well. Adding rotation keys to compensate for inheritance is something I do sparingly, as it's not safe for future animation changes. The transform constraint adds complexity and additional setup time, which is also very useful for the reasons you describe, but requires tree traversal in a file that's already massively complex. Being able to key inheritance is fast, stays within my tree selection, and is animation-safe between revisions. And now I'm armed with the specific knowledge that these keys work differently from other keys.

Thanks again!

Addendum. As I'm going through correcting these keys, I notice they don't support curves. They appear to be locked into linear interpolation, even though the setting is a boolean. Might be worth the Spine team's time to revisit these things.

The inherit keys are instant transitions, like attachment or draw order keys. When you mix from one animation to another, you can only have one inherit mode. This means the inherit mode is "wrong" for one of the two animations during the mix. After the mix the inherit mode is correct for the current animation.

Inherit keys only affect the animation containing the key, they don't work differently from other keys. By setting a key in the other animation, now both animations have the same inherit mode, so mixing between them won't have this inherit mode problem. If you mix to or from the setup pose, which has a different inherit mode, then you'll see the weirdness again.

You can see this happen in Preview. Turn off repeat, then click one animation, then the other.

Transform constraint has the benefit of being able to mix to/from it, but as you mentioned it has more setup and adds some clutter to the project.

You're right that inherit keys should not display interpolation lines between them in the dopesheet, as they are always an instant change. We'll fix that! They display correctly in the graph.

For other instant changes (attachment, draw order, event keys) we provide "threshold" properties like mixAttachmentThreshold. This allows you to control where in the mix to change from the mixing out animation's attachment keys to the mixing in animation's attachment keys. We will likely add a similar property for inherit mode. It will still be instant, but you can control at runtime where in the mix it changes.

    Nate Thanks Nate. On a subsequent look at this, I discovered keying Inherit Rotation was unexpectedly adding new bone Rotation keys. This is why it appeared the Inherit keys were linearly interpolated.

    My bad.

    I should ask: If our animation mix is set to zero in the runtime, but we're still seeing what I describe as "global inherit" behavior, does it imply a bug in the runtime? If the Inherit keys only affect the animation being played, I would expect swapping between animations to reset the inherit values to the setup pose.

    • Nate odgovara na ovo.

      The rotation is changed to keep the bone's same world rotation for convenience. I think that's commonly what people want. If we didn't change the rotation, it's somewhat tedious to do the math to do it manually.

      The rotation change causes a key to be set if auto key is on.

      FCSW_Ben If our animation mix is set to zero in the runtime, but we're still seeing what I describe as "global inherit" behavior, does it imply a bug in the runtime? If the Inherit keys only affect the animation being played, I would expect swapping between animations to reset the inherit values to the setup pose.

      The question as it's asked is hard to answer. "Global inherit" isn't defined and isn't standard terminology. Mix duration (zero or non-zero) doesn't affect keyed properties being stuck after an animation is mixed out.

      If you apply an animation and mix it out to another animation (which may be an empty animation) then the keyed properties should be returned to the setup pose values after the mix. If they don't, yes, it's a bug.

      Note if you use clearTrack or clearTracks or trackEnd then the skeleton will get left with whatever property values it had at that time. Mix to another animation (even if mix duration is 0) to get the setup values.

      I setup a runtime test with your skeleton. If I play block and then block_to_idle, I see the inherit mode from block persists. This is a bug and we've fixed in in spine-libgdx just now. It will be ported to the other runtimes soon!

      You are, as always, fast and thorough with your customer support and amazing at what you do. Thank you for looking into this!