Search Unity

Animator bug report clarification required

Discussion in 'Animation' started by dotsquid, Aug 23, 2017.

  1. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Some time ago I made a bug report about Animator which affects Physics2d simulation even if no actual animation is being played: https://fogbugz.unity3d.com/default.asp?938615_mnm3dnlhl0cpv9gk
    Here is how it looks like

    Pay attention to amplitude of the yellow hexagon when Animator is enabled/disabled.
    The project is in the attachment.

    However today I received an email in which it was said that this behaviour is by design:
    I can't express my strong feelings about this issue and this reply. Why on Earth does the Animator rewrite the Transforms which aren't being animated at that moment? And how to animate GameObjects which contain children being simulated by Physics?
    Here is how it looks in game prototype. Pay attention on the behavior of the pom-poms on the girl's hat:
     

    Attached Files:

  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    This has always worked this way, and it's always been a horrible design decision.

    It means that you run into issues like the one you're talking about, where not animating a thing doesn't mean that it animates. It complicates matters a lot.
    It also means that animations are not independent. If you add things to one animation, that'll change what a different animation moves.

    There's also (of course) no documentation about where the position of the transform that doesn't have any motions in the current motion comes from.

    This should definitely be an option on the animator ("animate transforms with no curves"), and should definitely be off by default.
     
    dotsquid likes this.
  3. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    That your point of view, but we made this decision for a good reason.

    The old legacy animation system only write properties that are animated for the current state, if you do a cross fade between a clip that animate A.color and another one that doesn't, the property A.color won't be blended and will keep the same value, so far so good, now if you crossfade into another clip that animate A.color it could create a discontinuity in the animation. When you start to add more and more clip you end up with a system that is not deterministic, depending on the order on which you play the clip you get different result.

    We had a lot of bug report which end up to be non deterministic behaviour because of this.The feedback from our user at this time was please make a deterministic animation system.

    So we made the animator component and implemented the write default values. The default values are setuped by the animator when it get activated, basically it does read all the animated property from the scene are store them internally, so when you blend two clip togheter if one of them doesn't have an animated values for a particular properties it simply use the default values to fade in and out, you can change this behaviour per state if needed to keep the value from the previous state but still all properties are always written every frame.

    https://docs.unity3d.com/Manual/class-State.html
     
    Last edited: Aug 23, 2017
    theANMATOR2b and neoshaman like this.
  4. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    You get a lot of bug reports about this too--it fixes one set of problems but introduces another. There are still improvements that can be made.

    It would help to have an AvatarMask on the Animator itself, which tells the animator to leave certain objects alone entirely. The problem (as I'm sure you know) is that joints in assets meant to be controlled by physics end up getting taken over by Animator, because since they're in the base asset they end up getting baked to animations as well, which is hard to prevent in many baking/animation export workflows.

    (That said, AvatarMasks are very awkward to work with: if you add a joint to an asset, separate AvatarMasks won't update automatically, and if you update them from the source, it loses the entire mask set and you have to create it all over again. I suspect I'll end up writing my own tool to generate them to make them more maintainable, so I can just list "include only these objects" or "include all objects except these" and auto-generate all masks like that.)

    I wonder if it's possible to work around this in script by recording an object's transform before Animator runs and then restoring it after. I'm guessing it's possible if the animator is in regular mode, but it might be trickier in animate physics--not sure if there are callbacks in the physics loop where they'd be needed.
     
  5. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    Here's a script that tries to work around this like I described above. It stores transforms before Animator runs, and then restores them afterwards. If I put this on an Animator who is clobbering an object's rigidbody motion, and add the object to the transforms list, the rigidbody starts working again.

    It won't work if the animator is in update physics. See: https://docs.unity3d.com/Manual/ExecutionOrder.html. The Animator update order in physics mode isn't described there, but it happens inside the "Internal physics update" block, and we'd need a callback inside that block which happens after Animator but before physics. Maybe there's a hack with Playables that could do this, but I haven't found one.

    Code (csharp):
    1.  
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MuteAnimatorForTransforms: MonoBehaviour
    6. {
    7.     public Transform[] transforms;
    8.  
    9.     struct SavedTransform
    10.     {
    11.         public Transform transform;
    12.         public Vector3 localPosition;
    13.         public Quaternion localRotation;
    14.         public Vector3 localScale;
    15.     };
    16.  
    17.     List<SavedTransform> savedTransforms = new List<SavedTransform>();
    18.  
    19.     void SaveTransforms()
    20.     {
    21.         savedTransforms.Clear();
    22.         foreach(Transform t in transforms)
    23.         {
    24.             SavedTransform savedTransform;
    25.             savedTransform.transform = t;
    26.             savedTransform.localPosition = t.localPosition;
    27.             savedTransform.localRotation = t.localRotation;
    28.             savedTransform.localScale = t.localScale;
    29.             savedTransforms.Add(savedTransform);
    30.         }
    31.     }
    32.  
    33.     void RestoreTransforms()
    34.     {
    35.         foreach(SavedTransform savedTransform in savedTransforms)
    36.         {
    37.             savedTransform.transform.localPosition = savedTransform.localPosition;
    38.             savedTransform.transform.localRotation = savedTransform.localRotation;
    39.             savedTransform.transform.localScale = savedTransform.localScale;
    40.         }
    41.     }
    42.  
    43.     void Update()
    44.     {
    45.         SaveTransforms();
    46.     }
    47.  
    48.     // Animator happens between these two calls.  https://docs.unity3d.com/Manual/ExecutionOrder.html
    49.  
    50.     void LateUpdate()
    51.     {
    52.         RestoreTransforms();
    53.     }
    54. }
    55.  
     
    dotsquid likes this.
  6. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Ok. I guess I understand the reasons.
    However I still have questions.
    1. If I undestand it right, the Animator writes all the properties which are animated by any Clip/State in the AnimatorController. If current Clip/State doesn't animate the property the Animator will just write the default value of that property which is captured... and here is the question.. when does it capture the default value?
    As far as I understand, it should capture it every frame. Otherwise we couldn't move our Transforms via the code if those Transforms are animated by some Clip.
    2. The next question comes out from the first one. Despite the fact that the Animator constantly writes the animated parameters which are not being animated at the moment, we still can alter them from our code (e.g. Transforms). So why Animator interferes with Physics?
     
  7. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    Animator doesn't capture every frame.

    See the ExecutionOrder link above. You can modify positions from code, but they'll be overwritten by Animator at its next update, which is "Internal Animation Update" if you're in the default animator mode. You can override Animator if you design around that, which is what I'm doing in the above code.
     
  8. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    When the animator is enabled/loaded.

    this is exactly what does happen, the only way to overwrite the animator is to modify thoses properties on a LateUpdate, but on the next frame they will get overwritten.

    When you setup your animator in AnimatePhysic, the animator start to get ticked on FixedFrame, the root motion stuff need to be evaluated before the physics to move the root rigidbody/character controller and then after the physics we do process the animation pose and write it into transfrom.


    Animator.ProcessRootMotion()
    Physics.Evaluate()
    Animator.ProcessAnimation()
    Animator.WriteProperties()
     
  9. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    Huh, surely animation needs to happen before physics, so animation on kinematic rigidbodies (foot) affects non-kinematic rigidbodies (ball) without being delayed by a frame?

    (I use third-party physics because I've never found Unity's built-in physics to be very usable. All of this is too black boxed and out of the developer's control...)
     
  10. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    @Mecanim-Dev thanks for the explanation. It seems it's a very deep and even philosophical topic but right now I have to solve a specific problem.
    In our game we have a girl who has a hat with pom-poms. These pom-poms are physical objects so they realistically jumps when the girl drives over road bumps. However we have to animate those pom-poms when the girl turns her head: more specifically we have to move the joint anchors of pom-poms.

    And here comes the mentioned problem: if we animate those pom-poms they stop behaving as we wanted. Note: the gif shows the correct behaviour because the movement of joint anchors is hard-coded. But surely we'd better animate them because it's much cleaner solution.
    So my question is how could we overcome this problem without hard-coding?
     
  11. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Animate virtual positions for them, and have the rigidybody objects follow along, without parenting.

    That looks super cute, by the way!
     
    theANMATOR2b likes this.
  12. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    You can try to manually update the animation system before the physics step.
    1.Disable the animator component, you don't want to use the builtin update loop because the animation write step happen after the physics.
    2. Create a mono bevahiour that will act as the UpdateManager for your animator component, override the FixedUpdate callback and from there call animator.Update(Time.fixedDeltaTime);

    By doing this you are completly changing how the animation system is updated and it should be more aligned with what you want to achieve
     
    theANMATOR2b likes this.
  13. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Thanks. Really nice tip. I even felt upset for a second I didn't reach upon this solution by myself.
    The only problem is that it does not work :C
     

    Attached Files:

  14. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    So...?
     
  15. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    Hi @dotsquid,

    I didn't have any time to look at this this week.
    Next week is our animation bug bash and I will allocate some time to find out a solution.
     
  16. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Thanks. I'll be waiting impatiently : )
     
  17. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    I'm not sure that Dev's suggestion would help. It would change the order of updates, but Animator would still be updating the transforms with rigidbodies on them, so it would still prevent physics from working.

    My answer was mostly ignored, but as far as I know it's the closest to a solution: undo the animator's effects on the transform so it doesn't interfere with physics. The transforms would still move, since their parent (the head, presumably) would still be animated, but the joints with dynamic effects applied to them wouldn't.

    I don't know if that would fix it by itself, since I've always found that Unity's builtin physics behave strangely and is hard to work with, but it's a piece of the puzzle.

    Baste's suggestion is to put the rigidbody transforms outside of the animated skeleton, and have a script that runs in FixedUpdate that moves the transforms (or a kinematic parent) so they follow. That would work too, though it would probably not work in animation/transition previews where the script wouldn't be running.
     
  18. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Hi, sorry for "ignoring". I actually did not ignore your answer and I did try your suggestion. But it didn't help, so I forgot to respond. I can upload a scene which uses your method if you'd like, but I believe you can check it with my original scene by yourself even quicker.
     
  19. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    Nobody's giving you a complete drop-in solution, you need to take the pieces people give you and put it together into a solution yourself.

    Your scene has animation on a dynamic object, which will never work and isn't the right way to influence a dynamic object with animation. Animation is going to put the object in a fixed position and won't combine with dynamics. You can animate a kinematic object that dynamic objects are attached to, or animate an invisible helper object and read the motion to apply it as force to a dynamic object, or (with some physics systems) animate an invisible non-dynamic copy of an object and use it as a goal for a dynamic object, but you don't put animation and physics on the same object.

    (For the simple effect in that GIF, I wouldn't touch Unity physics. I'd use something like https://www.assetstore.unity3d.com/en/#!/content/16743.)
     
    theANMATOR2b likes this.
  20. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    This scene is for demonstration only. If you pay attention you'll notice that the animation which alters the Transform of dynamic object is not being played; it's just there in the AnimatorController.
    In real case I disable physics simulation right before playing the animation.
     
  21. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    @dotquid
    Like NoiseFloorDev already said, you can't put animation and physics on the same object, both system will fight each other becasue there no built in solution that blend both result togheter. We are currently working on a solution for this with the c# jobs but it's far from be ready.

    So you will needs a hardcoded script to handle this case like you did. Or you could try to only animate the pompom with the legacy animation system which doesn't have this restriction

    I'm wondering why do you need to animate the end point of the pom-pom? could you just rotate the head and since both pom-pom are attached to the head they will follow?
     
  22. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Because I can't rotate a rigidbody2d along Y-axis.
     
  23. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    Or move along the X axis the anchor point?

    The constraint is you cannot animate and simulate with physics the same gameobject. There is nothing builtin in unity that will blend the physics and animation.

    The easiest solution that doesn't required any script is to animate the anchor point if you can since the anchor point is not simulated.

    Otherwise like @Baste proposed you can have a virtual pompom that is simulated and with a script in a LateUpdate transfer the simulation from the simulated pompom to the animated pompom.