Answered

Exported Animation offset

nory 2 years ago updated by Peter - Soxware Developer 2 years ago 1

Heyo,

first of all, thank you very much for developing this awesome tool. I greatly enjoy working with it and have tons of fun slowly discovering everything about animation.


Unfortunately, I'm running into a discrepancy between animations shown in UMotion and the exported animation, both as an .anim and as an fbx.


You can see the difference in the following screenshot, showing both the fbx in UMotion and the animation preview of a duplicate:

Image 1162


I've exported the fbx as a unitypackage, along with the corresponding UMotion project file, in case you want to have a look:

Ganymede3.asset
Ganymede06.unitypackage


I've tried playing with the animation import settings, but so far no configuration seemed to fix the issue. My suspicion is that the culprit is most likely found in some interaction between IK and the root of the object being rotated, but I haven't been able to pinpoint it, so far. Then again, I might also be on the wrong track and the issue is rooted in something else entirely.

As an added note, the FBX used here is the result of a VRM object being exported to FBX and consecutively rigged as a humanoid. I've considered whether this might play into it, but since the discrepancy also exists between the FBX in UMotion and the exported FBX with the animation, I'd imagine that it's likely not to be the cause.

In any case, I'd be incredibly helpful if you had any pointers.
If you need more information or the like, I'd be more than happy to provide.

UMotion Version:
1.28p03
Unity Version:
2021.3.2f1

Answer

Answer
Answered

Hi Nory,

thank you very much for your support request.

The problem you are seeing here isn't really related to UMotion, but to how the humanoid animation system itself works. The humanoid animation system is an animation re-targeting system. When Unity imports an FBX file configured as humanoid, it converts the actual authored animation into a "normalized" format that can then be played by the humanoid animation system on any other humanoid character even if the animation wasn't made specifically for that character. The system is designed to make animations look similar to the original authored animation, but they won't be precisely the same.

Hands being at wrong relative positions is one such problem humanoid can introduce. In order to compensate that error, humanoid has an internal corrective IK pass implemented that can correct wrong hand and foot positions. It's just not enabled by default (but you can preview it's effect when previewing the animation in the inspector window by enabling the IK toggle button).

More information about humanoid: https://blog.unity.com/technology/mecanim-humanoids

This blog post also covers the issue you are seeing with your hands at headline ("IK Solver").

In order to enable the corrective IK pass at you're game's runtime, you need to use scripting (only the foot IK pass can be enabled via Unity's animator UI). You can use this script (make sure to have "IK Pass" enabled in your Animator window):

using UnityEngine;
using UnityEditor;
using System.Collections;

    public class AnimatorHumanoidIK : MonoBehaviour
    {
        //********************************************************************************
        // Public Properties
        //********************************************************************************

        [Header("In order to use this, enable \"IK Pass\" in your Animator Controller!")]
        [Space(15)]
        public bool EnableFootIK = true;
        public bool EnableHandIK = true;

        //********************************************************************************
        // Private Properties
        //********************************************************************************
        
        //----------------------
        // Inspector
        //----------------------
        
        //----------------------
        // Internal
        //----------------------
        private Animator animator = null;

        //********************************************************************************
        // Public Methods
        //********************************************************************************

        //********************************************************************************
        // Private Methods
        //********************************************************************************

        private void OnAnimatorIK(int layerIndex)
        {
            if (animator == null)
            {
                animator = GetComponent<animator>();
            }

            float footIKWeight = EnableFootIK ? 1 : 0;
            float handIKWeight = EnableHandIK ? 1 : 0;

            animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, footIKWeight);
            animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, footIKWeight);
            animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, footIKWeight);
            animator.SetIKRotationWeight(AvatarIKGoal.RightFoot, footIKWeight);

            animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, handIKWeight);
            animator.SetIKPositionWeight(AvatarIKGoal.RightHand, handIKWeight);
            animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, handIKWeight);
            animator.SetIKRotationWeight(AvatarIKGoal.RightHand, handIKWeight);
        }
    }

----

If you do not plan to share your animation across multiple characters, I would highly recommend using "generic" instead. "Generic" is true "what you see is what you get" as the generic animation system plays the authored animation 1:1.

-----


My suspicion is that the culprit is most likely found in some interaction between IK and the root of the object being rotated, but I haven't been able to pinpoint it, so far.

Please note that the exported animation does not contain any custom IK code. The effect of UMotion's IK solver is completely baked into the final animation. Once exported, UMotion does not execute any IK code anymore. In order to preview what UMotion exported into your *.FBX file, you need to preview it as generic. Only generic shows you the actual authored animation. When configured as humanoid, Unity converts the actual animation of the FBX into it's humanoid format which can introduce imperfections like the ones you are seeing.

Please let me know in case you have any follow-up questions.

Best regards,
Peter

GOOD, I'M SATISFIED

Dear Peter,

thank you very much for your quick reply and in-depth explanation.

I was aware using humanoid rigs and corresponding animations creates a slight discrepancy, but not in this capacity. The script you posed definitely alleviated the issue somewhat, even though it still persists to a smaller degree.

So I went ahead and set up a generic rig, as you recommended and converted the existing humanoid animation using your Animation Converter Tool. The exported animations now fully correspond to how they are set up in UMotion.

Long story short: The issue is now solved. Thank you very much for your help, explanations and advice.

Satisfaction mark by nory 2 years ago
Answer
Answered

Hi Nory,

thank you very much for your support request.

The problem you are seeing here isn't really related to UMotion, but to how the humanoid animation system itself works. The humanoid animation system is an animation re-targeting system. When Unity imports an FBX file configured as humanoid, it converts the actual authored animation into a "normalized" format that can then be played by the humanoid animation system on any other humanoid character even if the animation wasn't made specifically for that character. The system is designed to make animations look similar to the original authored animation, but they won't be precisely the same.

Hands being at wrong relative positions is one such problem humanoid can introduce. In order to compensate that error, humanoid has an internal corrective IK pass implemented that can correct wrong hand and foot positions. It's just not enabled by default (but you can preview it's effect when previewing the animation in the inspector window by enabling the IK toggle button).

More information about humanoid: https://blog.unity.com/technology/mecanim-humanoids

This blog post also covers the issue you are seeing with your hands at headline ("IK Solver").

In order to enable the corrective IK pass at you're game's runtime, you need to use scripting (only the foot IK pass can be enabled via Unity's animator UI). You can use this script (make sure to have "IK Pass" enabled in your Animator window):

using UnityEngine;
using UnityEditor;
using System.Collections;

    public class AnimatorHumanoidIK : MonoBehaviour
    {
        //********************************************************************************
        // Public Properties
        //********************************************************************************

        [Header("In order to use this, enable \"IK Pass\" in your Animator Controller!")]
        [Space(15)]
        public bool EnableFootIK = true;
        public bool EnableHandIK = true;

        //********************************************************************************
        // Private Properties
        //********************************************************************************
        
        //----------------------
        // Inspector
        //----------------------
        
        //----------------------
        // Internal
        //----------------------
        private Animator animator = null;

        //********************************************************************************
        // Public Methods
        //********************************************************************************

        //********************************************************************************
        // Private Methods
        //********************************************************************************

        private void OnAnimatorIK(int layerIndex)
        {
            if (animator == null)
            {
                animator = GetComponent<animator>();
            }

            float footIKWeight = EnableFootIK ? 1 : 0;
            float handIKWeight = EnableHandIK ? 1 : 0;

            animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, footIKWeight);
            animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, footIKWeight);
            animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, footIKWeight);
            animator.SetIKRotationWeight(AvatarIKGoal.RightFoot, footIKWeight);

            animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, handIKWeight);
            animator.SetIKPositionWeight(AvatarIKGoal.RightHand, handIKWeight);
            animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, handIKWeight);
            animator.SetIKRotationWeight(AvatarIKGoal.RightHand, handIKWeight);
        }
    }

----

If you do not plan to share your animation across multiple characters, I would highly recommend using "generic" instead. "Generic" is true "what you see is what you get" as the generic animation system plays the authored animation 1:1.

-----


My suspicion is that the culprit is most likely found in some interaction between IK and the root of the object being rotated, but I haven't been able to pinpoint it, so far.

Please note that the exported animation does not contain any custom IK code. The effect of UMotion's IK solver is completely baked into the final animation. Once exported, UMotion does not execute any IK code anymore. In order to preview what UMotion exported into your *.FBX file, you need to preview it as generic. Only generic shows you the actual authored animation. When configured as humanoid, Unity converts the actual animation of the FBX into it's humanoid format which can introduce imperfections like the ones you are seeing.

Please let me know in case you have any follow-up questions.

Best regards,
Peter