• RuntimesUnityBugs
  • Transition of Unity SkeletonMecanim is broken

Spine/Runtime version. 4.2.0
I'm using this free asset.

knights.zip
704kB

Transition between idle_3 <-> run_shield is broken when using SkeletonMecanim. It takes longer rotation.
With SkeletonAnimation, everything is fine.

I'm using same transition mix setting. (same duration for both)


  • Harald ответили на это сообщение.
    Related Discussions
    ...

    The issue you're experiencing with the transition between idle_3 and run_shield using SkeletonMecanim in Unity might be related to a known problem where transitions can have a delay or incorrect behavior. This was addressed in recent updates to the Spine runtimes. Specifically, a new Animation Update mode called InLateUpdate was added to help with such issues. You should ensure you are using the latest version of the Spine-Unity runtime, which includes this fix. You can download the latest 4.2-beta unitypackage from here. Additionally, check your transition settings in Mecanim to ensure they are correctly configured, as incorrect settings can also cause transition issues.

    Sorry bot but InLateUpdate doesn't help.

    grylloidea Transition between idle_3 <-> run_shield is broken when using SkeletonMecanim. It takes longer rotation.
    With SkeletonAnimation, everything is fine.

    The problem is not as trivial unfortunately. The issue lies with the two animations containing rotation values differing by 360 degrees, one being at around -37.26 while the other is at around 351.82:

    Animation "run_shield":

        "run_shield": {
            "bones": {
                 "shoulder_L": {
                        "rotate": [
                            {
                                "value": 23.95,
                                "curve": [
                                    0.1,
                                    23.95,
                                    0.3,
                                    -37.26
                                ]
                            },
                            {
                                "time": 0.4,
                                "value": -37.26,
                                "curve": [
                                    0.5,
                                    -37.26,
                                    0.7,
                                    23.95
                                ]
                            },
                            {
                                "time": 0.8,
                                "value": 23.95
                            }
                        ],

    .. vs. animation "idle_3":

        "idle_3": {
            "bones": {
                "shoulder_L": {
                        "rotate": [
                            {
                                "value": 351.82,
                                "curve": [
                                    0.117,
                                    351.82,
                                    0.35,
                                    356.39
                                ]
                            },
                            {
                                "time": 0.4667,
                                "value": 356.39,
                                "curve": [
                                    0.583,
                                    356.39,
                                    0.817,
                                    351.82
                                ]
                            },
                            {
                                "time": 0.9333,
                                "value": 351.82
                            }
                        ],

    Thus the easy fix would be to ensure that the animations key the same local rotations, not differing by whole 360 degree rotations.

    You can also mimic the same undesired behaviour in SkeletonAnimation with AnimationState via ShortestRotation = true:

    var entry = skeletonAnimation.AnimationState.AddAnimation(0, "run_shield", true, transitionTime);
    entry.ShortestRotation = true;

    This will always evaluate the rotation direction differently, i.e. each frame, see the documentation here. Otherwise when false, the direction is evaluated only once and then the direction is kept during the whole transition.

    Unfortunately SkeletonMecanim just uses Animation.Apply instead of the stateful AnimationState which provides much more flexibility and is thus recommended over SkeletonMecanim wherever possible.

    Thanks for the detailed answer! Problem solved.
    How did you debug such glitch? Any tips?

    @grylloidea Glad it helped!

    Regarding debugging: unfortunately can't provide anything helpful here: knowing the runtime internals helps a lot obviously, especially what can be configured with animation blending helps. Also forum postings in the past where rotation issues typically boil down to either:

    • keying world vs local rotation incorrectly when you want to exceed 360 degrees or not.
    • TrackEntry.shortestRotation should be set or not when during a transition the shortest rotation direction is suddenly changing (at the 180 degree edge)
    • animation dipping due to an animation being held or not (see TrackEntry.holdPrevious).

    Unfortunately many of the configuration options are not possible with SkeletonMecanim. In your case it was just looking like a difference of 360 degrees between keys, as the angles of both animations are not apart by 180 degrees. Looking at the values in the JSON file was then confirming that.