Search Unity

Question 2D IK - Bone chain involved in animations + script based Solver target movement = erratic

Discussion in '2D' started by MarsCitizen_1, Jan 27, 2021.

  1. MarsCitizen_1

    MarsCitizen_1

    Joined:
    Jun 2, 2016
    Posts:
    20
    Hello!

    Unity 2020.2.1 (which is awesome, great work!)
    Newest versions of Unity 2D Animation packages w/ the IK built-in.

    So, we have a typical human rig, including wrist/hand bones.

    upload_2021-1-27_11-3-12.png


    The solvers for the arms are CCD chain in the hand, using a chain of 4 to get back up to the shoulder / upper arm:

    upload_2021-1-27_11-5-35.png


    Like the title suggests, the Solver "target" is being moved in a Script (for aiming a weapon), as well as in some animations. When control is fully isolated (script only, or animations only), movement is fluid, perfect.
    When both are active during gameplay, we get some frantic motion. Initially, this was solved by moving the logic in the script so that instead of only updating solver.target on player input, to constantly setting position in Update() [yuck]. It seems however, the more animation states that I add which utilize the arms in some way, the more this conflict over "who has control" grows, and there's always a slight jitter of position/rotation happening -- even when those Animation states are not playing or being transitioned to/from.

    I realize my approach might be entirely crazy to begin with, but I had hoped that the Animator would "back off" so to speak - leave the limbs alone when they're not needed in a current Animation state.

    Just for full picture sake, this is how the solver.target is being moved in script:
    Code (CSharp):
    1. // rightHand is a Solver2D
    2. // newPos is a Vector3.
    3. rightHand.GetChain(0).target.transform.localPosition = newPos;
    I feel like there is a setting I'm missing, or another weird thought I had and I've found nothing online about this type of question:
    • Can I use 2 Solvers on the same limb chain?
      • One with a Solver.weight of say 0.5f, used in Animations to move solver.target
      • The other used in script, with Solver.weight = 1f (So that if the script is trying to move it, it takes priority).
    Would that work, or make things even more erratic?

    Thanks, Unity rocks my socks, keep up the great work! :)
     
  2. MarsCitizen_1

    MarsCitizen_1

    Joined:
    Jun 2, 2016
    Posts:
    20
    The multiple solvers is a no-go. The last in control of an effector just takes over.

    Then there is toggling solvers.enabled back & forth, I guess that's the solution?
     
  3. Ted_Wikman

    Ted_Wikman

    Unity Technologies

    Joined:
    Oct 7, 2019
    Posts:
    916
    Hello @drastikx2
    First off, thank you for your kind words, we are happy you enjoy creating in Unity!
    So from your message, I understand that you have one solver target being moved by both an animation clip and a script. Is that correct?

    Did you try your two Solvers solution? I gave it a go with a twist.
    I added two solvers under the root of a character, one to be controlled by an animation clip, and one to be controlled by a script. I made sure the "script" solver was located after the "animation" solver in the IK Manager 2Ds IK Solvers list. I also unchecked the Solve From Default Pose checkbox in the "script" solver.
    Both the solvers add themselves as the Target, so they don't have to fight over their positions.
    With this setup, the "animation" solver runs first, setting the effector to the position it should have this frame. Afterwards, the "script" solver runs and solves based on the position the "animation" solver decided on.
    With this setup, I could control an arm with my mouse, while it was still being animated with an idle "sway" animation.

    I also added a script to tweak the weight distribution between the "animation" solver and the "script" solver.
    Code (CSharp):
    1. codeSolver.weight = Mathf.Clamp01(weight);
    2. animSolver.weight = Mathf.Clamp01(1f - weight);
    Let me know how it turns out for you!

     
  4. MarsCitizen_1

    MarsCitizen_1

    Joined:
    Jun 2, 2016
    Posts:
    20
    Hi Ted, wow what a great response!

    First off, I did wind up at a solution. It involved multiple solvers, and toggling them on/off in script.

    I previously tried everything you mentioned, except I didn't specifically set the Script solver to not Solve From Default Pose while leaving that setting enabled for the animation solver. I will test that out of curiosity.

    I'm very interested on 2 things you did to get yours to work that way:
    • What Animator.updateMode did you set (normal/physics)
    • When did you update solver.target position in script [ Update(), LateUpdate(), input polling, etc ]?

    Thanks for such a thoughtful response! I don't see a way to mark this thread as "solved" but if there is, it definitely can be.
     
  5. MarsCitizen_1

    MarsCitizen_1

    Joined:
    Jun 2, 2016
    Posts:
    20
    Okay, your method worked perfectly as well. I think I had something slightly off the first time I tried it, perhaps the 2 solvers shared a target, which now I understand why that would not work.
     
  6. Ted_Wikman

    Ted_Wikman

    Unity Technologies

    Joined:
    Oct 7, 2019
    Posts:
    916
    Great that you got it to work!
    We update the IK Solvers in LateUpdate(), so updating the positions of the targets in LateUpdate() as well could potentially cause unwanted behaviour, such as one frame delay or that the IK Solvers solves with outdated target data. This all depends on the scripts execution order and what you do with the targets.
    Also note that the whole IK functionality is open source (it's all C# inside the 2D Animation package), so you can freely explore the code to learn more about it if you feel like it.

    Happy developing, and I look forward seeing what you are creating in the future!