MathJax example

Spline IK solver

This project contains an implementation of the multichain IK solver in Houdini using VEX scripting language. The algorithm is based on this article.

In short, a multichain inverse kinematics solver is a computational algorithm used in robotics and computer graphics to calculate the joint angles of a robotic arm or a character model given a desired end-effector position and orientation.

The setup is simple, extremely lightweight and supports rotation constraints.

Here is a basic implementation. If you'd like to run the script inside one of your projects, simply copy and paste the code below inside a detail wrangle and use the node setup shown above. Full project files are available on my Patreon page.

View VEX code
drop down toggle arrow
 


vector goal = point(1,"P",0);
float max_bend_angle = chf("min_angle");
int iterations = chi("iterations");
vector position_array[] = {};

//initialize point position array
for(int i=0;i<npoints(0);i++)
{
    vector pos = point(0,'P',i);
    push(position_array,pos);
}
position_array = reverse(position_array);


for(int k=0; k<iterations; k++){

    for(int i=0;i<@numprim;i++)
    {
      int pts[] =  primpoints(0,i);
        
      vector root = position_array[2*i + 1];
      vector end = position_array[0];

      vector root_to_end = end-root;
      vector root_to_goal = goal-root; 
      float angle = acos(dot(normalize(root_to_end),normalize(root_to_goal)));
      
      vector4 rot_0 = dihedral(root_to_end,root_to_end);
      vector4 rot_q = dihedral(root_to_end,root_to_goal);
      
      if(angle>(max_bend_angle))
      {
        float bias = max_bend_angle/angle;
        rot_q = slerp(rot_0,rot_q,bias);
      }
      
     
      vector new_pos = set(0,0,0);
      
      //apply rotation to current prim and its 'children'
      for(int j=0; j<i+1; j++)
      {
        vector pt = position_array[2*j];
        vector pt1 = position_array[2*j+1];
        new_pos = qrotate(rot_q,pt-root)+root;
        
        position_array[2*j] = qrotate(rot_q,pt-root)+root;
        position_array[2*j+1] = qrotate(rot_q,pt1-root)+root;
      }
     
    }

}


//write positions to points
position_array = reverse(position_array);
for(int i=0;i<len(position_array);i++)
{
    setpointattrib(0,"P",i,position_array[i]);
}