Quantized Animations from Blender FBX not Importing Correctly

Having recently finished up some basic 3D animations in blender I was excited to see how they would turn out in-game and for the most part they don’t look half bad. Except there is a problem.

I’ve quantized all of my animations in blender, that is to say I set all keyframes to use constant interpolation so that I can emulate hand-draw animation by avoiding all inbetweening. However, it appears that some of these keyframes don’t import properly in Unity and I still occasionally see very quick blimps of inbetweening here and there. Usually only for a single frame of the animation itself. Just as a test I tried duping the animation, loading it into Unity’s animation timeline and resetting the keyframes and it does appear to fix the problem. The animation was fully quantized. However, this is a really ugly workflow that I’d rather avoid if at all possible.

Does anyone know what I could be doing wrong? I’m a complete beginner at 3D stuff and Blender in general so maybe there is something I’m just doing wrong in the tool itself? Or perhaps something in export or import settings needs to be adjusted? I’m really hoping this isn’t yet another thing I’ll have to spend several days writing tooling for just to automate the process. I already do that enough as it is lol

Alright, after putting things off for a few days while I worked on animations (All the while hoping I could come through with a solution to this. Ah, the gamedev lifestyle) I finally figured out how to solve this issue.

So the are a few steps to this that involve both Blender and Unity.

Step 1: Consider keying all bones for any frame that has keys in it. I can’t say for sure this did anything to help me but it didn’t hurt the end result. It might be that Blender already bakes the data. Or it might be that I just beefed up the file size for no good reason. But I’m not going back to undo what I did so I’ll just have to live with the mystery for now. If you are daring enough try leaving this as a last-ditch step if things still look weird.

Step 2: In blender, select all keyframes for all bones in the animation Timeline/Dopesheet, right-click and set Interpolation to Constant.

Step 3: When exporting your FBX from blender make sure ‘Bake Animations’ is checked at the very bottom and be sure to set ‘Simplify’ to 0.0. This seems to be doing some compression stuff that can muck things up.

Step 4: In the imported FBX file go to the Animations tab and set compression to Off. Again, this seems to be mucking things up. Those discrete values cannot afford to change even slightly.

Step 5: So you thought setting discrete keyframes in Blender was enough? Ha! What a nerd! Anyway, NOW you ALSO need to set the tangents of each animation curve that Unity generated to constant as well. And yes, before you ask, you do need to set both the interpolation in Blender AND the tangents in Unity. Doing one or the other will give crap results. Luckily for you I wrote a simple script to do just that on import so that you don’t have to waste hours of you life doing it by hand (or minutes of your life looking up how to write your own import script). Be sure you put the code in a file that is in an Editor folder.

If you need a way to choose when to import normally versus when to force discrete animations, I left a simple bool value that can be flipped in the code. More than likely you’d want to set up some kind of editor window to let you choose when it is one setting or the other but I’ll leave that as an exercise for you.

That’s it. Problem solved. For me anyway. Good luck to the rest of you out there!

EDIT: Forgot to mention there was one last piece of the puzzle. It might just be a ‘me thing’ due to how my project was set up but I found that animations still looked like crap when I had the editor window and the game view window in view at the same time. Probably had something to do with cameras and matrices and who knows what else that I’ve been messing with for this project. But if you find things are still weird, try having only the game view visible and see if that help.s

using UnityEditor;
using UnityEngine;

namespace SomeNamespace
{
    /// <summary>
    ///
    /// </summary>
    public class AnimationQuantizer : AssetPostprocessor
    {
        /// <summary>
        ///
        /// </summary>
        /// <param name="root"></param>
        /// <param name="clip"></param>
        private void OnPostprocessAnimation(GameObject root, AnimationClip clip)
        {
            if(AnimationQuantizerSettings.Enabled)
            {
                Debug.Log($"Quanitizing animation clip '{clip.name}'");
                var curveBindings = AnimationUtility.GetCurveBindings(clip);
                foreach(var curveBinding in curveBindings)
                {
                    var curve = AnimationUtility.GetEditorCurve(clip, curveBinding);
                    for(int i = 0; i < curve.keys.Length; i++)
                    {
                        //probably not worth doing ALL of these but hey, let's not take any chances at this point
                        curve.keys[i].inWeight = 0;
                        curve.keys[i].outWeight = 0;
                        curve.keys[i].inTangent = 0;
                        curve.keys[i].outTangent = 0;
                        curve.keys[i].weightedMode = WeightedMode.None;
                        AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Constant);
                        AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Constant);
                    }
                    AnimationUtility.SetEditorCurve(clip, curveBinding, curve);
                }
            }
        }
    }


    /// <summary>
    ///
    /// </summary>
    public static class AnimationQuantizerSettings
    {
        public static bool Enabled = true;
    }
}
3 Likes

Thanks for this friend, saved me a ton of trouble!