What algorithm will solve IK?

I’ve been trying to write an IK solver in Python since there are issues with Blender’s IK solver. I can’t figure out the algorithm for solving IK. I initially thought it was that on each iteration, I see what the distance that the end of the IK chain is to the target when I rotate each bone individually on the local +x, -x, +y, -y, +z, and -z axes by a small amount, then I rotate the bone along the axis where the distance is the shortest. However, when I ran this algorithm it got to the point where any rotation by any individual bone would take it further from the target. I probably could rotate multiple bones in ways that would bring it closer to the target, but I don’t know an algorithmic way of figuring that out that is not computationally intensive.

I’ve looked up descriptions of IK algorithms online but found them hard to understand. For example, Wikipedia describes the Jacobian inverse technique https://en.wikipedia.org/wiki/Inverse_kinematics#Approximating_solutions_to_IK_systems . I find it difficult to figure out which values are vectors and which are scalars. If they are vectors, I don’t know if there should be an element for each bone, or for each degree of freedom of each bone. It also lists functions p_0 and p_1, then a sequence of functions p_i. It sounds like p_0 and p_1 represent different functions from p_i, which is confusing when the same name is used for different functions. I tried the best I could to calculate the Jacobian, but it also requires the pseudoinverse. A way to calculate the pseudoinverse is (AAT)^-1AT (where A is a matrix and AT is its transpose) but this only works when A*AT is invertible (when I ran the program I got a Jacobian that was not invertible).

Does anyone know an algorithm for solving IK?

1 Like

I’ve been interested in writing a simple IK solver for some time now (not just for the sake of learning, I’ve actually been confronted to a situation where Blender’s rigging toolset fell short), but I haven’t investigated nearly as much as you have. I’m curious as to which limitations you have hit in Blender. To my knowledge the standard solver is much more flexible than the one bundled with Maya - it has per-bone stiffness parameters and per-axis locks which allows for super cool setups with minimal complexity. I’ve been able to replicate some of those in Maya but it’s convoluted (like really).
I’ll investigate this as much as I can in the coming weeks and let you know my progress, hopefully it’s not completely beyond me (high school level trigonometry is where I’m at).

Let me ping @clockmender who might just know more about this. I’m thinking of some others as well but their names evade me at the moment.

Cheers,

Hadrien

The problems I have with Blender’s IK solver is that it doesn’t interact well with constraints and drivers. One example is I have a constraint on the shoulder bone to rotate the shoulder as the arm is lifted over the head. The shoulder is the parent to the upper arm, so a constraint on the shoulder that refers to the upper arm would be a dependency cycle. To solve this I created another bone to act as a control bone which I use to rotate the arm. The shoulder’s constraint depends on the control bone and the upper arm bone has a copy rotation constraint to the control bone. However, the control bone is not part of the IK chain so the constraint on the shoulder only has an effect in FK mode.

I’d like to also have some other features in an IK solver, such as requiring the bones of an arm not to intersect the body and also to make more natural poses. Usually in a natural pose the elbow would be lower rather than higher so there could be a penalty function in the IK solver and the solver would try to minimize the penalty as well as the distance to the target.

I attached what I wrote so far in a .blend file (which I am releasing under the GNU General Public License). However, it does not refer to Blender’s library yet. This program writes to a file which I use for debugging, so if you want to run it you might want to remove the lines that open/write to a file, or change the path and filename of the file it writes to. There is a previous version which I attached to this thread: Write my own IK solver, but Quaternion math doesn't match Blender . I solved the issue with quaternion math I described in that thread.

iksolver.blend (555.1 KB)

Hi Hadrien my friend, sorry I am a bit late replying to this, but what with my current blender project and flying lessons and exams, I am a bit busy just now.

Hi also to @4096,

Anyway, on the the IK issues; I was at first very sceptical of ANY IK solver, until I understood the maths behind it. On thing that I went back to was Meccano models to understand how to constrain and move an IK chain. Doing something physically is far better than trying to do it mathematically as a first pass. If you build a human arm, the first thing to understand is what movements the arm is capable of, rather than what Blender allows you to do.

The shoulder joint is a ball and socket, so in theory it can move any way, but it is constrained by tendons that restrict the movement, also the two thoracic shoulder bones move with any shoulder movement, thus alleviating the constraints imposed by the tendons, hence we can do a lot with or arms at the shoulder. the elbow is another matter in that it is essentially a hinge, that can also articulate. So I built a rig in Meccano and imposed restrictions on it by using other parts until I could replicate the arms total possible movement. This I used to understand where I had to constrain the Blender armature.

First thing to remember - other constraints are all overridden by IK, so don’t bother with them. Second, pole target bones can be used to help the alignment of the arm within the IK system. Bones in the IK chain can have axes locked, or given a “stiffness” value, they can also be given limits to their rotation, so if you spend a serious amount of time measuring what your arm is capable of, you can apply this to the armature. It is surprising what you can achieve in terms of arm placement if you allow some bone Y axis rotation in the IK chain and then use this to twist the arm, thus controlling the final shape of the arm. Therein lies another issue; I do not always use the IK chain as the deforming bones on the mesh, I sometimes use an IK chain of non-deforming bones that effect the position of the deforming bones, but do not necessarily twist the deforming bone about it’s Y axis, for example.

I think you have three ways to go with this:

  1. Build a new IK solver, something that I personally am not prepared to consider, bearing in mind the vast amount of resource in terms of time and research I will need to get better than Blender’s own.

  2. Spend a lot of time keyframing many movements of the arm to get it into the right believable shape. Not a good idea if you don’t fully understand the limits of movement of a human arm.

  3. Study the human arm scientifically and build a database of all possible movements and understand the constraints on a human arm.

You say the IK solver doesn’t interact well with constraints, it doesn’t at all in reality is my experience. You also say it doesn’t interact well with drivers, that I dispute as I have used many drivers in IK constraints and they work well provided you don’t try to override the limits set in the IK chain.

Below is a picture of the characters from my latest project as an example, all the arms and legs are controlled by IK chains with pole targets. All the poses are achieved without any drivers, or other constraints - there are no constraints on any bones in these armatures, except for Copy Loc, Copy Rot on the hands (these are not in the IK chain and are not the IK targets) to stick them to the handlebars of the bikes they ride before this shot. To get them to pose like this I just set the influence of the constraint to 0 when they are off the bikes.

There are still tweaks to do in the image, one girl’s thumb is not right yet, but this is still WIP.

All things considered, I would work with what you have in Blender, after understand everything it is capable of, rather than trying to write another solver, unless you have vast amounts of time to dedicate to the task. Don’t try to limit the movements of an IK chain with other constraints - it doesn’t work.

Having said all that, I wish you well with the endeavour, but be mindful that the maths is going to get very complicated… @Hadriscus: school trig is not going to cover this my friend. :smile:

For the bikes in the project I designed an IK chain with drivers so that when you tilt the back end, the forks either extend of retract and the front wheel changes its distance from the back of course as a result. This involved calculating two RH triangles on the fly with no dependancy loops and using drivers to keep the bones of the IK chain in place. Even this is not simple and the parts only move in one plane, add the other two planes and life gets very interesting.

Cheers, Clock. :beer:

I modified my rig to replace the constraints along the IK chain with drivers and it seems to be working. I set up my rig so that both shoulders have three bones: ShoulderDriver, ShoulderManual, and just Shoulder. I have a constraint on Shoulder to add the rotation of ShoulderDriver and ShoulderManual. UpArm is a child of Shoulder, and Shoulder has a driver that depends on UpArm. I think this would be a dependency cycle but Blender is not warning me about a dependency cycle. Are dependency cycles involving drivers not an issue?

Without seeing the rig I could not comment, but it doesn’t sound like a loop of dependencies to me, having read your post several times! Using a driver does not introduce a dependency per se, even if you are using a child object property as a variable for the parent. I will set up something like this to test it and report back. It would be easier if you post a blend file with these bones in it, as you have set them up, for me to look at.

Cheers, Clock.

Here is my .blend file.

My drivers use the function “interval” which I have defined. The way it works is if I have interval(var,[(1,0),(0.5,pi/4),(0.1,pi/2)]), it returns 1 if var==0, 0.5 if var==pi/4, and 0.1 if var==pi/2. If var is between those values, it returns a weighted average, so if var==pi/16 it returns 0.25*0.5+0.75*1 = 0.875.

rig_20180909.blend (1.8 MB)