rewritten and better explained here: 2 Joint 2 Limb Inverse Kinematics
If you’re just looking to to basic knees and elbows you don’t really need anything much more complicated than cosine law. You can use circle intersection to do it too. If we’re doing it via law of cosines:
We’re basically just going to solve this triangle. We know lengths a, b, c, we just need to figure out angles A and C. To do that we can use the following:
As far as using this in roblox you can define the variables as:
b and a are the segment length of the arm/leg. ie think of b as the upper arm, and a as the lower arm.
c is a “flat” plane that we’ll use to solve our triangle on. So think of c as being the distance between the shoulder position and the target position.
So your values might look like
b = 1.255
a = 0.735
c = (origin - target).magnitude
A = math.acos((-a^2 + b^2 - c^2) / (2 * b * c))
C = math.acos((a^2 + b^2 - c^2) / (2 * a * b))
Now as far as using those angles goes you’d go about constructing a CFrame pointing from the shoulder position to the target, Rotating by angle (A + pi/2), and offseting the first arm piece outwards. Position your second arm piece rotate by angle (C - A) and you get offset outwards. If done right the end of the “arm” grabs the target point.
Things to consider with this approach:
If the length between the origin and target points is more than the length of both arms, your angles should be 0, 0.
if the length between the origin and target points is more than one arm length but less than the other arm length, you need to handle that case in a way that works best for you.
A “flat” CFrame.new(origin, target) for the base of your plane doens’t look natural, you’ll need some sort of rolling to have your limbs look realistic.
If you’d like an actual code example, this is what I use for Apocalypse Rising 2:
-- OriginCF is the CFrame of the shoulder, direction is important
-- TargetPos is the Vector3 position we're reaching to
-- l1 and l2 are both numbers that represent the length of the segments of the arm
local function solveIK(originCF, targetPos, l1, l2)
-- put our position into local space in regards to the originCF
local localized = originCF:pointToObjectSpace(targetPos)
-- this breaks if OriginCF and targetPos are at the same position
local localizedUnit = localized.unit
-- the distance to from originCF.p to targetPos
local l3 = localized.magnitude
-- build an axis of rotation for rolling the arm
-- forwardV3 is Vector3.new(0, 0, -1)
local axis = forwardV3:Cross(localizedUnit)
-- find the angle to rotate our plane at
local angle = acos(-localizedUnit.Z)
-- create a rotated plane to base the angles off of
local planeCF = originCF * fromAxisAngle(axis, angle)
-- L3 is between the length of l1 and l2
-- return an offset plane so that one part reaches the goal and "folded" angles
if l3 < max(l2, l1) - min(l2, l1) then
return planeCF * cfNew(0, 0, max(l2, l1) - min(l2, l1) - l3), -pi/2, pi
-- l3 is greater than both arm lengths
-- return an offset plane so the arm reaches its goal and flat angles
elseif l3 > l1 + l2 then
return planeCF * cfNew(0, 0, l1 + l2 - l3), pi/2, 0
-- the lengths check out, do the law of cosines math and offset the plane to reach the targetPos
-- return the offset plane, and the 2 angles for our "arm"
else
local a1 = -acos((-(l2 * l2) + (l1 * l1) + (l3 * l3)) / (2 * l1 * l3))
local a2 = acos(((l2 * l2) - (l1 * l1) + (l3 * l3)) / (2 * l2 * l3))
return planeCF, a1 + pi/2, a2 - a1
end
end
-- simple demo for how its called
local TARGET_POS = Vector3.new(0, 3, 0)
local SHOULDER_C0_VALUE = CFrame.new(1, 0.4, 0)
while wait() do
local shoulderCF = upperTorso.CFrame * SHOULDER_C0_VALUE
local plane, shoulderAngle, elbowAngle = solveIK(shoulderCF, TARGET_POS, 0.515, 1.1031)
shoulderMotor.C0 = upperTorso.CFrame:toObjectSpace(plane) * cfAngles(shoulderAngle, 0, 0)
elbowMotor.C0 = lowerC0 * cfAngles(elbowAngle, 0, 0)
-- keep the C1 values consitent, they shouldn't need to be set every frame
end
When it comes to modeling foot and hand movement, it’s best to just study the movements of the hands relative to the torso of a person. Figure out how to model those and use them for your target position. I won’t go into that because there are a bunch of different ways of doing it, but learning how to model ovals would be a good start.