I'm building a 2D inverse kinematics system and can't figure out how to find all the joint positions. I have the math to make a typical IK set up with a single bend (e.g. arm, leg), but I get stuck when adding another bend.
How do I find the position of all joints for an inverse kinematic chain that is longer than 2 segments?
Here's an example of the planar solution I'm looking for: https://youtu.be/3sqd_CZNq7s?t=6s
I'm building this in Adobe After Effects so using an existing IK solver isn't going to work.
Here's my visual setup for reference:
What I'm aiming for is that when the blue box is moved (target) joints 2 and 3 bend appropriately to maintain their length. Joint 1 is static and doesn't move.
To make this work, I need x,y coordinates to be calculated in real time. No need to render anything on screen—just the position values for each joint.
var angle1, angle2, angle3, theta1, theta2, theta3, targetSqrDist; // joints var joint1 = thisComp.layer("joint 1"); var joint2 = thisComp.layer("joint 2"); var joint3 = thisComp.layer("joint 3"); var joint4 = thisComp.layer("joint 4"); // segment lengths var segment1Len = length(joint2.transform.position, joint1.transform.position); var segment2Len = length(joint3.transform.position, joint2.transform.position); var segment3Len = length(joint4.transform.position, joint3.transform.position); // target position var target = thisComp.layer("target"); var ix = target.transform.position - joint1.transform.position; var iy = target.transform.position - joint1.transform.position; // target square distance targetSqrDist = ix * ix + iy * iy; // Segment 1 angle1 = Math.max(-1, Math.min( 1, (targetSqrDist + (segment1Len*segment1Len) - (segment2Len*segment2Len)) / (2 * segment1Len * Math.sqrt(targetSqrDist)) )); theta1 = Math.atan2(iy, ix) - Math.acos(angle1); var s1X = joint1.transform.position + segment1Len * Math.cos(theta1); var s1Y = joint1.transform.position + segment1Len * Math.sin(theta1); // Segment 2 angle2 = Math.max(-1, Math.min( 1, (targetSqrDist - (segment1Len*segment1Len) - (segment2Len*segment2Len)) / (2 * segment1Len * segment2Len) )); theta2 = Math.acos(angle2); var s2X = s1X + segment2Len * Math.cos(theta2 + theta1); var s2Y = s1Y + segment2Len * Math.sin(theta2 + theta1); // Segment 3 angle3 = Math.max(-1, Math.min( 1, (targetSqrDist - (segment2Len*segment2Len) - (segment3Len*segment3Len)) / (2 * segment2Len * segment3Len) )); theta3 = Math.acos(angle3); var s3X = s2X + segment3Len * Math.cos(theta3 + theta2); var s3Y = s2Y + segment3Len * Math.sin(theta3 + theta2);
This code would be applied to each joint with a unique position value assigned to it, depending on the joint's location.