Inverse Kinematics Plane Angle

I created a pretty basic inverse kinematic system that follows some fairly simple logic:

  1. Solve the triangle created by the line connecting the shoulder to the target position, the upper arm, and the lower arm + hand
  2. Choose the plane in which the solved triangle will be placed
  3. Determine the locations of the 3 corners of the triangle using this plane
  4. CFrame the arm parts, which are anchored and not welded to anything, end to end based on these positions.

Code for steps 1-3:

P1 = ShoulderPos
--Solve for in-plane angle using cosine rule
local CosTheta = (TargetDist^2 + L1^2 - (L2+L3)^2)/(2*TargetDist*L1)
local Theta = math.acos(CosTheta)

local BendDistance = L1 * math.sin(Theta)
local StraightDistance = L1 * CosTheta

BendDir = TargetDir:Cross(Vector3.new(0,1,0))

if Side == "Left" then
	Normal = BendDir:Cross(TargetDir)
else
	Normal = TargetDir:Cross(BendDir)
end

--Find the points
P2 = P1 + StraightDistance*TargetDir + BendDistance * BendDir
--Find P3
local Dir = (TargetPos - P2).Unit
P3 = P2 + Dir * L2

The problem arises in step 2, choosing the plane. Currently the code is set to takes the cross product of the direction vector from shoulder to target and the global vertical, and use the resultant vector as direction the elbow joint displaces in, which along with the direction vector to the target, defines the plane.

As the vector from the cross product always lies in the horizontal plane, I thought the arms would remain level and I could apply an extra rotation as needed. Instead I get this:


The plane rotates in weird ways when the target position moves up and down. I’ve tried various different methods of defining the plane to little success, has anyone got any advice?

5 Likes