Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Imported Blender Animation Glitches for a Few Frames; Gone on Reimport

Discussion in 'Animation' started by SomeGuy22, May 22, 2022.

  1. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    722
    I have a .blend file used for animation which has a linked model/rig to a base .blend. This .blend file stores a bunch of actions and up until recently I've had no trouble using it to import animations for use in my game. But now, on Unity 2020.3.26f1 and using Blender 2.79a after having regenerated the Library folder (could be important for this) and made a build for 3 Platforms in a row, I've noticed that sometimes my animations get corrupt and freak out with random frames of nonsense movement.

    Take for example this animation in which the head glitches out upwards for a few frames before settling back:



    It does NOT happen at the loop point and is not due to rogue keyframes in Blender. As you can see in Blender, Frame 100 of this animation does not show the same glitch:



    The crazy thing is, this issue disappears once Unity re-imports it. All I've done is open and re-save the file in Blender and it's magically disappeared:



    To pre-answer common questions, this has happened before about a week or two ago with another one of my characters. The leg for that animation was glitching out downwards for a few frames before clearing up. At that time I solved it by re-saving and then also switching the anim. compression option to Keyframe Reduction rather than Optimal, just in case that was having an effect. Sadly I can't confirm if it fixes it since Optimal was the setting for this file I showed above.

    It shouldn't be affected by rotation/position/scale error since these jumps are way further than any error value, though in the past I have noticed some small shaky movements when these values were at default setting. The character is humanoid and I've already set up a custom mask to import all the bones that this character has. I can answer any questions you have about my setup.

    Seems similar to maybe this issue but otherwise I can't find anything like this online.

    The thing is this is easy to fix but hard to understand, and an overall scary bug to have. At any point it seems like any of my animations could be corrupted like this and although I can fix it just by saving the file, since there's no error report and the fact that this wasn't happening before, things like this could easily slip into the final release. In fact, this one made its way into the Beta release on my Steam app and it's the reason I found it in the first place. I have no idea how to even detect when this is happening other than manually looking through each animation and making sure they aren't corrupt. So this is starting to stress me out since I'm releasing this project in just a week or so.

    Appreciate any help and thank you for any guidance or info.
     
  2. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    722
    After saving the file to get rid of the problem I noticed later that it still happened for another animation in that file. So I'd guess that saving is not a permanent fix; in other words rebuilding the library is not some key event that corrupted everything only to be fixed later. It's possible that rebuilding the library or making builds triggered some sort of corruption that adds a random chance for animations to get corrupted on import, but this is still all a guess for now.

    Since I'm pressed for time and need solutions quickly I thought of a way to help catch this issue, though it's very annoying. I realized that making a script to detect glitchy behavior on import would take a lot of testing and that's not feasible given that the issue is so random. So instead I put together an automated testing scene which grabs all of the animators on my character prefabs and plays each animation one by one so I can preview a large amount of them at the same time and spot errors manually. I accomplished this by utilizing temp Override Controllers that are created at runtime and assigned to each character:

    Code (CSharp):
    1. foreach(CCharEntity e in entities)
    2.             {
    3.                 var newTest = new EntityControlTest();
    4.                 newTest.entity = e;
    5.                 newTest.anim = e.anim;
    6.                 newTest.baseController = e.anim.runtimeAnimatorController;
    7.                 var clipInfo = e.anim.GetCurrentAnimatorClipInfo(0);
    8.                 newTest.defaultBaseClip = clipInfo[0].clip;
    9.                 var s = e.anim.GetCurrentAnimatorStateInfo(0);
    10.                 newTest.defaultBaseSpeed = s.speed;
    11.  
    12.                 newTest.overrideController = new AnimatorOverrideController(e.anim.runtimeAnimatorController);
    13.                 e.anim.runtimeAnimatorController = newTest.overrideController;
    14.  
    15.                 //Set playback of entire animator to match the potential speed scale of default clip
    16.                 e.anim.speed = 1.0f / newTest.defaultBaseSpeed;
    17.  
    18.  
    19.                 data.entityTests.Add(newTest);
    20.  
    21.                 e.SetState(CCharEntity.EntityState.LockedInPos);
    22.             }
    I store the "current animator clip" because at Start() it will be the "default" clip used by the Animator on entry. The reason I need the clip is because the Override Controller matches on AnimationClip, not on State node. It's a little awkward especially if someone needed to override one state that has a shared clip with another one, but in this case it works out since I don't care about the other states. I simply want to replace the default state programmatically and let it loop so that I can preview the potentially broken animations.

    Then on each Update() I increment a timer for each test and if it exceeds the desired length I play the next animation. Okay, so where do these animations come from and how did I determine the length? All that info comes from the "base controller", the original one that I stored before the override came in. This is what happens when I play the next animation:

    Code (CSharp):
    1. void PlayNextTestAnimation(EntityControlTest test)
    2.     {
    3.  
    4.         test.animIterateIndex++;
    5.         if(test.animIterateIndex >= test.baseController.animationClips.Length)
    6.         {
    7.             test.animIterateIndex = 0;
    8.         }
    9.  
    10.         test.currentAnimProg = 0.0f;
    11.  
    12.         var thisClip = test.baseController.animationClips[test.animIterateIndex];
    13.  
    14.         var frames = thisClip.length * thisClip.frameRate;
    15.         if(frames <= 40.0f)
    16.         {
    17.             test.currentWaitProg = thisClip.length * 3.0f;
    18.         }
    19.         else
    20.         {
    21.             test.currentWaitProg = thisClip.length * 2.0f;
    22.         }
    23.  
    24.         var baseOverride = new List<KeyValuePair<AnimationClip, AnimationClip>>();
    25.         var key = new KeyValuePair<AnimationClip, AnimationClip>(test.defaultBaseClip, thisClip);
    26.         baseOverride.Add(key);
    27.         test.overrideController.ApplyOverrides(baseOverride);
    28.     }
    The base runtime controller's animationClips property holds all the clips used by the state machine. So all that happens is I increment the index (wrapping to 0 if needbe), reset the progress, and set the length to wait for based on the new clip's length property. I also do a check to see if the animation is short (less than 40 frames) to run it 3 times, otherwise I run it 2 times just to be sure. To build the override list it requires that you hand a list of KeyValuePair to replace one animation with another. This is why I stored the default clip (entry point) and I'm able to match it with the current clip to inspect. Then I simply apply the overrides.

    I then place down groups of my characters on the same screen and do some extra test steps to help the process like changing the UI color when the test is complete and adding in default cam angles to preview it more easily. When it runs, all tests happen simultaneously and I can inspect a group. When I've cleared that group I switch to the next one and reset the tests. This helps to see if any glitching occurs and if so, I know to reimport the offending file. The key here is this scene can be accessed even in the build, so I can delegate this work off to testers once my version 1.0 has been released and make extra sure that everything in the game will work on arrival. Since this corruption gets bundled into the build I can be sure even if my files get corrupt later on that the built version will have no issues. This is at least a surefire way to know whether there are or aren't problems with the animations.

    Caveats: doesn't work for non-looping animations. Since the test relies on just switching the clip and not the state, it's as though the state time has kept going, past the loop point. Non-looping animations stay held at the last frame, so no luck in detecting anything there. Also, this only accounts for animations used in the character's controller. For other animations like those used in Cutscenes with Timeline, they won't be accounted for. This can be solved by just manually placing more controllers used solely for testing that have these missing animations or by putting down a testing Timeline that can be previewed in the scene.

    One last thing I did was change all of my .blend files with animation to use the Keyframe Reduction compression instead of Optimal. That way, if a corruption does occur I can at least eliminate that from being a cause. But currently I still have no info on why this happens or how to properly prevent it. Right now I'm simply hoping that it doesn't happen on final release and that I can catch it in time if it happens again. Would appreciate any insight into this, thanks.
     
  3. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    722
    Reporting in much later on October 7th and finding that the issue is still present, even after upgrading the project to 2021.3.9f1 (a whole new major version since I was on 2020 LTS last) and with the .blend file using Keyframe Reduction instead of Optimal, so that eliminates it from being a preventative measure. Here are screenshots demonstrating the problem:



    And the Blender animation:



    As you can see, on frame 19 in Unity the leg glitches out through the floor for 1 frame, but on frame 19 in Blender the issue doesn't happen at all.

    This time I was patient enough to save a zipped copy of the project while it's still broken so hopefully when it's reopened the issue will still be present for analysis. I'll assume again that by just saving the .blend file it'll cause the issue to go away for a bit but as I mentioned above I don't want to randomly have this sneak into my builds again. On that note I'll consider sending in a bug report with the project as an example if I can get a secure upload link. Hopefully with this reproduction project something can possibly be done about the problem... hopefully.
     
  4. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    722
    After submitting the bugged project through a bug report, the QA Team was finally able to reproduce the problem on their end. It's now been assigned on the issue tracker under this link:

    https://issuetracker.unity3d.com/issues/imported-blender-animations-have-gitches

    Issue ID:
    UUM-24660

    So I'm hoping that the problem can be resolved quickly once the source of the problem is identified. I just have one main worry which is that it's possible the problem stems from Blender instead of Unity. When you import a .blend file, Unity will actually run the Unity-BlenderToFBX.py script internally and ask Blender to provide an FBX file for import. That file is what is used, probably stored as an artifact somewhere in the Library folder. So it could also be that the FBX exported by Blender also experiences that issue, in which case there may not be much Unity can do to solve it.

    The way to confirm it would be to somehow read the FBX that got generated and see if it also has the glitch, but I've got no idea where it ended up or if it's even still intact in FBX form or got converted to some Unity-based arbitrary model format. A way to test it might be to run FBX exports from Blender until the problem occurs, but it's so random that I'm not sure how long it would take for the issue to pop up like that. If it did occur, then I could easily import the FBX file back into Blender and see if the glitch is baked into the file, which would answer the question.

    I might give it a shot just to see if it'll happen again but in the meantime Unity Team might be able to find out a lot more than I can. Here's hoping that it's easily solved and that we'll see the fix in an LTS patch soon!
     
  5. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    722
    Today Unity has closed the issue with this generic response:

    I can't say I blame them considering the rarity of the issue and the fact that it could be tied to an issue with Blender exporting as opposed to Unity's data. If so, this could be solved by using Blender 3.x instead of 2.x as the FBX exporter may have been updated in newer versions. Hopefully that's enough to resolve the issue if anyone else comes across it in the future.
     
  6. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    722
    And like magic immediately the issue has returned. This is in Unity 2021.3.22f1, still using Blender 2.79. Here is frame 15 of this new animation:


    And frame 16 where the toe randomly jumps out:

    And here is the .blend file showing that no such "jump" occurs on frame 16:


    So I guess I will have to continue manually checking every single animation and just rely on pure hope that it doesn't happen in the built game. I'm not sure what more can be done about this since I've gone through the entire bug reporting process and we can see where that ended up. Maybe Blender 3 will fix it in the future, but I can't upgrade when I'm nearing the end of a project. And there's not much more to be done on my end without being able to debug the auto-converted FBX for myself.

    I guess the real solution will probably be saying goodbye to Unity and embracing an engine that lets you fix your own problems when they arise. But unfortunately I will have to suffer the random instability for a bit longer.
     
  7. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    722
    I discovered the issue on another file but this time it's on one that was over a year old.


    I verified that the issue persisted on a build from a few months ago, but this tells me a few things: It must be reimporting that causes this glitch to occur, not just saving the file. That much was probably already obvious but this is just confirmation of that fact, since I performed a project wide reimport when upgrading to 2021 LTS. That must've been when this issue was created since I didn't see it on builds older than that point. But that doesn't narrow anything down as the animation I explained in the post above was brand new; created just a day or two ago. So the issue still exists on 2021.3.22f1.

    EDIT: I also got this log in the warning when I reimported:

    Seems this is a feature of Unity that can actually tell you when an inconsistent result is generated from the same input, which is exactly what happens here. Not sure if this can actually help track down the source of the corruption.
     
    Last edited: Sep 30, 2023