Search Unity

  1. Are you interested in providing feedback directly to Unity teams? Sign up to become a member of Unity Pulse, our new product feedback and research community.
    Dismiss Notice

Write Defaults Confusion / Bug

Discussion in 'Animation' started by TitanUnity, Mar 16, 2016.

  1. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,674
    It's a bug, it should be deterministic and if the default value are not saved then it not deterministic.
    Could you log a bug with your project showing the issue please?

    This is high priority for us and should be fixed asap
     
    TextusGames and mcroswell like this.
  2. adamgryu

    adamgryu

    Joined:
    Mar 1, 2014
    Posts:
    124
    Hey, thanks for looking into this. This will be a really useful feature once it's fixed.

    I just made an example project and submitted a bug.

    To help clarify the problem, here's a GIF I made showing the bug in action.
    GIF.gif

    The ENTER button toggles between a spinning animation (the default) and a moving animation.

    The cube on the left is marked Animator.keepAnimatorControllerStateOnDisable = true.
    Notice that in spite of this, it forgets it's original position when the GameObject is disabled and re-enabled.

    Edit: Here's the bug report - https://fogbugz.unity3d.com/default.asp?1076483_ivcpr3om28aq3tqs
     
    Last edited: Aug 30, 2018
  3. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    168
    Hi,
    I'm also affected by this issue.

    I'd like to suggest simple solution:
    Instead of "remembering default values" which might not be easy, it would be completely sufficient to write default values just before the animator is disabled.

    Simply add checkbox to animator: Restore defaults on disable
    - this can be used with keepAnimatorControllerStateOnDisable to continue in fully deterministic manner
    - can be used without keepAnimatorControllerStateOnDisable to safely "reset" the object to "pre-animation" state when animator is disabled

    Now I have to scan object for animators before deactivation and call "WriteDefaultValues" manually (I can't even do it in OnDisable, because in OnDisable, WriteDefaultValues does nothing).
    The problem with my workaround is apparent when multiple different objects gets deactivated in different ways...e.g. when using object pools

    When looking for solution or workaround to this issue, I've found that a lot of people have similar problem.
    This could be huge help. Thank you!
     
    mcroswell, ModLunar and ihgyug like this.
  4. ihgyug

    ihgyug

    Joined:
    Aug 5, 2017
    Posts:
    189
    Manually using Animator.WriteDefaultValues() before turning the gameobject off seems to work to avoid this bug. I hope there will be a built-in way to do it tho.
     
    mcroswell, krzys_h, ModLunar and 2 others like this.
  5. happysunshineandthepoweroffriendship

    happysunshineandthepoweroffriendship

    Joined:
    Mar 20, 2018
    Posts:
    9
    This also solves the problem of bugged default positions that happens when using the Apply Anim Overrides method as described here

    https://docs.unity3d.com/ScriptReference/AnimatorOverrideController.html
     
  6. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    287
    I too, have suffered with this bug. However, I found some news on it. I tried all sorts of magic and trickery with Playables, AnimationStreams, and nothing helped 100%. However.. the answer was simpler than I thought... I think this is only available in Unity 2018.1 or 2018.2 and afterwards, but now that shouldn't be an issue! So what I found is:


    SOLUTION:

    Two parts: (you need to do both)
    Solution Part 1:
    Set animator.keepAnimatorControllerStateOnDisable to true. This does 2 things:
    1.1. When the Animator is re-enabled again, the state machine resume where it last left off.
    1.2. HOWEVER, IT ALSO "FIXES" THE DEFAULT VALUES!! It keeps them the same default values that they were in the VERY beginning of the game.

    Therefore, set animator.keepAnimatorControllerStateOnDisable = true as early as possible. During Awake() worked for me.

    Solution Part 2: Due to the side-effect of animator.keepAnimatorControllerStateOnDisable resuming the state machine where it last left off, there is the only last potential issue remaining: The object may resume in an unwanted state (animation-wise).

    To fix this, you can create 0-duration transition in the Unity editor from Any State to your chosen default state that you would like the object to return back to upon re-enabling, with a trigger parameter condition.
    Then in your MonoBehaviour, call animator.SetTrigger("Reset") or animator.SetTrigger(ResetId) during OnEnable() to immediately set the state machine back to the initial animation state.

    --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

    I was also wondering:
    Does this work with Root Motion?
    ANSWER: When Root Motion is enabled on the Animator, the root object's position and rotation's default values are changed to be updated with the object's new position and rotation. On the root of the hierarchy ONLY.
    The scale is not counted in this, and keeps its original default value.

    So, yes it does work with Root Motion. If you want the object to respawn at its original position/rotation, you'll have to use Awake and OnEnable again for that, but the values are not locked, since the Animator will only be moving the root using deltas from its current position/rotation.

    --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

    TLDR; Do both of the following:
    Solution Part 1: animator.keepAnimatorControllerStateOnDisable = true during Awake().
    Solution Part 2: animator.SetTrigger("Reset") during OnEnable(). Requires a 0-duration transition from Any State to your chosen default state w/ trigger parameter "Reset".

    Code (CSharp):
    1.  
    2.        public void Awake() {
    3.            animator = GetComponent<Animator>();
    4.            animator.keepAnimatorControllerStateOnDisable = true; //!!! (Solution Part 1)
    5.        }
    6.  
    7.        public void OnEnable() {
    8.            animator.SetTrigger(ResetId); //!! (Solution Part 2)
    9.        }
    10.  
    EDIT: For your information, I was using Unity 2019.2.5f1 when I successfully got this to work!
    EDIT 2: It seems this solution is not enough if you are mixing custom PlayableGraphs with the Animator in certain cases. My guess is it seems the graph will need to be cautiously constructed and maintained in order to avoid the AnimatorControllerPlayable from possibly resetting the default values.
     
    kelinchen and mcroswell like this.
  7. flyingspringrol

    flyingspringrol

    Joined:
    Apr 4, 2015
    Posts:
    2
    Alright ran into this problem today. Super rough bug to work with to be honest, almost had to reanimate about 20 hours of work which would have sucked.
    Essentially my workaround was to have a default state of "alloff": which has a keyframe for every object in my hierarchy turning it off. My code runs like this.
    Code (CSharp):
    1.             anim.Play("off", 0, 0.0f);
    2.             anim.Update(0.0f);
    3.             curr_anim_idx++;
    4.             PlayCurrentAnimation();
    For every animation, I then keyframe all the objects I need to 'turn on' for the scene (generally 10-20).
    This solves the problem.

    I don't know what I'd do if complex states/rotations were being messed with: I think having some serialization method of running through and saving each scene with it's necessary default values would be the way I'd do it.
    Curious to see how unity devs fix this in the future: it's a tricky problem, but it really does seem like you could fix it with code that identified objects as 'animatable', and then prevents them from being dumped from memory and having their default values removed.
    Essentially in the animator, when you 'toggle off' an object, underneath the hood, in the animator code, it just turns off all it's renderers/scripts. Shouldn't be impossible to fix, but of course I don't work with the unity code base. Does seem like the mecanim system needs a refactor anyway to support more than just rigged animations :).
     
    ModLunar likes this.
  8. KilatiF

    KilatiF

    Joined:
    Jan 8, 2019
    Posts:
    9
    This topic most useful and live for discussion about Write Defaults. Thx @ModLunar for your solution about reseting animator when gameobject was disabled. But I have another problem/question.

    Imagine, that you have 4 states:

    #1 - Default empty with write defaults
    #2 - Change color for first image (with write defaults)
    #3 - Change color for second image (with write defaults)
    #4 - Change color for third image (without write defaults)

    And I start this states in next sequence:

    - from #1 -> #2 (change color for first image)
    - from #2 -> #3 (change color for second image, first image color reset)
    - from #3 -> #1 (reset colors for both images)
    - from #1 -> #4 (change color for third image AND happens "magic" for me: colors for first 2 images return back)

    So, as I understand, when you go to state without write defaults, it's restore properties from ALL last frames of all animations, that you called before. Is it okay? I thought, that if you go to state without write defaults, it just not reseting to defaults and just keep values for properties, that this animation not using, AND NOT restoring ALL OTHER properties from ALL called states. Is it possible to fix somehow?

    Gif illustrate my example.

     
    Last edited: Oct 23, 2019
  9. KilatiF

    KilatiF

    Joined:
    Jan 8, 2019
    Posts:
    9
    Nobody can help?
     
  10. Moe_Baker

    Moe_Baker

    Joined:
    Oct 22, 2017
    Posts:
    29
    Came across this problem and this seems like the best solution, can you perhaps share some guidelines for that code or maybe share it? That would be very awesome.
     
  11. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    287
    From my experience in Unity 2020.1.15f1, this bug is still here.

    @Mecanim-Dev Any update on the bug report or bug itself?
     
    mcroswell likes this.
  12. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    420
    Yet another surpize...
     
  13. mcroswell

    mcroswell

    Joined:
    Jan 6, 2010
    Posts:
    71
    I've been trying to animate some Text Mesh Pro (TMP) settings and simply want to control the attributes after the animation finishes. That is, it (the Animator) transitions into another animation which doesn't use those attributes. I was hoping to use Write Defaults flag so then I could use code (normal MonoBehaviour) to modify those attributes.
     
    Last edited: Jan 15, 2021
    ModLunar likes this.
  14. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    420
    In unity 2019 Lts:

    private void Awake
    {
    GetComponent<Animator>().keepAnimatorControllerStateOnDisable = true;
    }

    keeps original default values.
     
    Whatever560 likes this.
  15. Metall_East

    Metall_East

    Joined:
    Feb 6, 2019
    Posts:
    2
    Write defaults still don't work in 2020.1.10f1 or am i doing something wrong?
     
  16. ASymShade

    ASymShade

    Joined:
    May 18, 2018
    Posts:
    3
    Using keepAnimatorControllerStateOnDisable with an entry state with no animation and Write Defaults set to true seems to be able to prevent this issue in recent Unity versions (previously, we would make other animations forcibly reset these changes if necessary). However, it is rather strange that this setting is exposed in the inspector in Debug Mode only (https://forum.unity.com/threads/ani...ndisable-should-be-shown-in-inspector.875872/). Is there some risk involved with using it that means it isn't usually intended to be set by animators in the way that the base Write Defaults is?
     
unityunity