Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Daniel Erdmann's "Fast IK" (formerly known as SimpleIK)

Discussion in 'Assets and Asset Store' started by JoeStrout, May 19, 2020.

  1. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    There doesn't seem to be a forum thread for this, and the author has not responded to my email after a couple of days, so in the spirit of open-source, I'm taking the initiative and creating a thread to discuss this:

    https://assetstore.unity.com/packages/tools/animation/fast-ik-139972



    It's a free and open-source implementation of the FABRIK algorithm for inverse kinematics. Given a chain of joints (e.g. an arm), it will figure out the right combination of joint angles to get the end (e.g. the hand) where you want it. The implementation is basically just one C# file.

    Discuss! :)
     
  2. ditzel

    ditzel

    Joined:
    Aug 6, 2016
    Posts:
    3
    Hi,

    I am very busy at the moment. But feel free to raise a pull request on GitHub
     
  3. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I found this video very helpful in explaining the benefits and capabilities of the FABRIK algorithm:



    It claims that adding constraints is relatively simple (as is supporting branched structures with multiple end effectors). These are features I'd really like to see, as in many cases joints can only move in one axis or within certain limits.

    @ditzel, I know you're busy, and I'm not complaining — you've made some great code here and generously shared it for free. My hope is that we users can take it further, and as you said, make a pull request if we manage to improve it!
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I also found this write-up which does a very nice job of explaining the FABRIK algorithm. (If you prefer videos, the same guy made this one, which is referenced in the FastIK code. But it doesn't go into as much detail as the PDF.)

    And there's also the original paper, which is quite readable (as is the sequel).

    ...And the basic FABRIK algorithm is shockingly simple. I always thought it was some deep black magic involving solving big systems of linear equations. Nope. It's really easy! :)
     
    Last edited: May 19, 2020
    salvolannister likes this.
  5. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    So having absorbed all that, it turns out that joint constraints are quite simple too: you simply apply the constraint at each step, as we work our way up or down the chain. In other words, FABRIK will pick a candidate position for a joint, and at that point we need to simply check whether that position is out of range for the joint, and if so, change it to the closest position in range.

    All the complexity in the papers comes from describing those joint constraints, not applying them. In many cases there is an easier way to describe it. For example, if your bone is a 1 DOF rotary joint, like an elbow, then it is completely described by the normal to its plane of motion. The attached joints could be forced into compliance by simply doing a Vector3.ProjectOnPlane. FABRIK will continue to work, and might simply need a few more iterations to find a legal solution.

    In the code, there are a couple of for loops, starting on lines 158 and 167, which implement the forward and back phases of the iteration. We might apply constraints by simply calling some virtual "EnforceConstraints" method with the joint number and which direction (forward or back) we're working on. Then we could subclass the solver and write a bit of code to apply whatever constraints we have. (If a Pole is being used, that might throw a monkey wrench into things, as it changes the point positions after the solver is done; I'm not sure yet how to deal with that.)
     
    Last edited: Sep 13, 2021
  6. daniel_lochner

    daniel_lochner

    Joined:
    Jun 9, 2016
    Posts:
    170
    Hey there, I hope you’re all doing well!

    I am currently using FastIK in my third-person shooter game to ensure the player's left hand grips each weapon correctly.

    The only issue I am having is that whenever I try to swap between different weapons, the left hand snaps to the next weapon's grip after changing the target.

    Would it be possible to add a "weighting" parameter? That way, I could use a coroutine to first fade the effects of FastIK out when putting the weapon away, and then fade the effects back in when taking the next weapon out! I have tried my luck at modifying the script to achieve this, but haven't had much success so far.

    Thanks!
     
    paul-velocity likes this.
  7. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    One thing you could do is have your IK target be an empty GameObject, rather than the actual weapon grip. Then use Vector3.MoveToward on its position to move that thing from the old grip, to some neutral position, and then to the new grip over time.
     
  8. daniel_lochner

    daniel_lochner

    Joined:
    Jun 9, 2016
    Posts:
    170
    Hmm, I see what you're saying, but isn't there some way to modify the actual script to accommodate for this? @ditzel Any chance you could shed some light on this? :)
     
  9. dtConfect

    dtConfect

    Joined:
    Sep 30, 2013
    Posts:
    1
    Hi all,

    I've been working a bit with IK recently and this implementation has been very helpful in getting my head around some parts of FABRIK - particularly how to go about doing the calculations in root space to avoid weird variations in the solution generated when the root object is rotated differently.

    I'm not sure if this is just me misunderstanding quaternion maths, but the implementation of GetRotationRootSpace here doesn't sit right with me: surely we should be returning Inverse(rootRotation) * currentRotation, not Inverse(currentRotation) * rootRotation, thus mirroring the implementation of SetRotationRootSpace.

    Changing that results in some errors which can be addressed by modifying the //set position & rotation formulae to invert the starting target rotation and not the current target rotation or the starting bone rotation, but I'm not sure if that's me fixing some code that was compensating for an error elsewhere, or if I'm overlooking something deliberate.

    I'm also trying to work out how to add basic constraints to a FABRIK implementation but I don't find the papers all that easy to read.
     
    JoeStrout likes this.
  10. petey_bee

    petey_bee

    Joined:
    Sep 22, 2020
    Posts:
    1
    @JoeStrout do you have any good examples of adding constraints? I'm having a problem where the bone structure in my model don't use the hinge joing constraints that I've set. Thanks for checking this out and helping!
     
  11. nicmarxp

    nicmarxp

    Joined:
    Dec 3, 2017
    Posts:
    406
    I made this using Unity's IK and CCD solver and have this problem. Is there any difference in using FastIK to solve this? I want the drill to keep pointing to the right and just smoothly rotate the first axis, instead of "flipping" everything to point into the middle.

    I got similar results using the FabrikSolver2D.

    I just want it to rotate the bones in small increments to reach the desired target, not recalculate everything. Any ideas and will FastIK help? :)

     
  12. santynolole

    santynolole

    Joined:
    Apr 10, 2021
    Posts:
    2
    Hello, i have a problem, i am trying to make a physics based enemy with this, but when i try to build it it says error
     
  13. nodayshalleraseyou

    nodayshalleraseyou

    Joined:
    Dec 5, 2017
    Posts:
    2
    I had an error while building as well. Moving the "#if UNITY_EDITOR" on line 236 and placing it on 233 outside of OnDrawGizmos() fixed the problem for me.
     
  14. Lesnikus5

    Lesnikus5

    Joined:
    May 20, 2016
    Posts:
    131
    I tried to make weighting for IK. In the FastIKFabric.cs i added Vector3.Lerp in the SetPositionRootSpace function and Quaternion.Lerp in the SetRotationRootSpace function. In general, there is an effect, but there is jerking. It is as if Lerp is acting through the frame, alternating with full IK power. I don't have time to do this, because I did it for fun. But if anyone has any ideas on how to fix this, I would gladly accept the advice.

    Here are two functions to replace, plus a variable ikForce to adjust. Maybe someone wants to figure it out.

    Code (CSharp):
    1.  
    2.         [Range(0, 1)]
    3.         public float ikForce = 1;
    4.  
    5.         private void SetPositionRootSpace(Transform current, Vector3 position)
    6.         {
    7.             if (Root == null)
    8.                 current.position = position;
    9.             else
    10.                 current.position = Vector3.Lerp(current.position, Root.rotation * position + Root.position, ikForce);
    11.         }
    12.  
    13.  
    14.  
    15.         private void SetRotationRootSpace(Transform current, Quaternion rotation)
    16.         {
    17.             if (Root == null)
    18.                 current.rotation = rotation;
    19.             else
    20.                 current.rotation = Quaternion.Lerp(current.rotation, Root.rotation * rotation, ikForce);
    21.         }
    You probably tried to do the same with the same result?
     
  15. edejeramy

    edejeramy

    Joined:
    Feb 6, 2021
    Posts:
    1
    Whenever I try to export my game with fastikfabrik script it gives me this :( upload_2021-9-16_19-10-17.png
     
  16. Lesnikus5

    Lesnikus5

    Joined:
    May 20, 2016
    Posts:
    131
    This:
     
  17. battou

    battou

    Joined:
    Jan 25, 2011
    Posts:
    213
    Any ideas how to add angle and axis constraints to this code?
     
    ttw1993 and inmim like this.
  18. ditzel

    ditzel

    Joined:
    Aug 6, 2016
    Posts:
    3
    Hi Folks,

    I just managed to have some time to fix the bug coming up during update. I will go through your comments and see, if I can upgrade it any further.

    Best regards!
     
    JoeStrout and inmim like this.
  19. inmim

    inmim

    Joined:
    Aug 23, 2019
    Posts:
    24
    This is a great simple solution for some simple industrial robots I'm trying to emulate. Where I work, I cannot use blender nor import objects so I have to hand type your script and using just simple cubes and cylinders to act as robot arms. one issue I'm running into (and probably more of a basic "I stupid, not knowing" aspect) your Rotator works great, but when I try to recreate it in the stand alone environment, the "cubes"/arms are all wonky. The green mesh matrix showing is perfect. Using the pole works just as expected, and when playing in editor, the green matrix looks fine. Its just my cubes move to different positions. what have I done wrong?
     
  20. Klausbdl

    Klausbdl

    Joined:
    Aug 12, 2013
    Posts:
    64
    Hi all. I'm having a weird issue with the package. No matter how much I rotate the ik Target, on play the hand always starts at the same rotation, no matter how much I change the ik Target before hitting play. How do I solve that?
    Sem nome.png

    Edit:
    I did a quick fix, but I dont know if its the better solution. If it works, it works am I right
    Code (CSharp):
    1. //set position & rotation
    2. for (int i = 0; i < Positions.Length; i++)
    3. {
    4.     if (i == Positions.Length - 1)
    5.         Bones[i].rotation = Target.rotation;
    6.     //SetRotationRootSpace(Bones[i], Quaternion.Inverse(targetRotation) * StartRotationTarget * Quaternion.Inverse(StartRotationBone[i]));
    7.     else
    8.         SetRotationRootSpace(Bones[i], Quaternion.FromToRotation(StartDirectionSucc[i], Positions[i + 1] - Positions[i]) * Quaternion.Inverse(StartRotationBone[i]));
    9.     SetPositionRootSpace(Bones[i], Positions[i]);
    10. }
     
    Last edited: Dec 7, 2023