Inverse Kinematics (R15, Foot Placement)

Hello again.

I’m trying to do inverse kinematics on the player leg
I always did many codes to get it, i already read the R15 IK Foot Placement - #19 by complexo, but i really can’t understand it! if someone can help me i will be grateful for you help.

(Example): @vsnry image
image

1 Like

So I’m actually pretty familiar with trigonometry and geometry. So tan cos and sin have different formulas for each. You have to figure out your sides for example opposite, adjacent and hypotenuse.

Then as they stated you plug your numbers in based off of the chart above. Using the Pythagorean Theorem.

lrpoAZQ

Now you use the following a,b and c as a unknown value that now has a specific purpose. To help you plug them into the equation. I’d use mathway or some form of geometry/trigonometry calculator.

Then once done insert all your info into the code they’ve provided.


-- 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

Over all if you’re struggling with how to solve or set it up I’d use a outside website like Khan Academy or some sort of video/lesson to learn how to do it.

3 Likes

I will try that, thanks, probably i will be late.

So hmmm… lol
image

1 Like

I believe this is some sort of error in your code location possibly make sure it’s inserted in the correct place.

If you’re going to try and paraphrase my post please at least link the full thing. You’re missing important information from it.


TH8UqHm

lrpoAZQ

The labeled triangle image and the equations are references for solving the law of cosines. As stated in my thread:

We’ll be solving a 2 joint 2 limb system by adapting the Law of Cosines . For those unfamiliar the law allows us to take the lengths of a triangle and solve for its angles.

b = 1.255
a = 0.735
c = (shoulderPosition - goalPosition).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))

This table of values corresponds to the variable used in the law of Cosines equations. You can put that triangle and its labels into the context of an arm by relating the following:

  • Angle A is the angle of the shoulder
  • Angle C is the angle of the elbow
  • Vertex of angle A is the shoulder position
  • Vertex of angle B is the goal position
  • Length c is distance from the shoulder to the goal
  • Length b is the length of the upper arm
  • Length a is the length of the lower arm

The thread where I explain all of this does it in the context of an arm but it’s the same process with different joint names to translate it onto a leg. I’d really recommend reading over the thread and trying out the demo .rbxl file attached to the thread.

5 Likes

Hey, i tried it in ur place but i still getting error of position do you know what can i do? image
image

Do you have code snippets you could share? From the images it looks like it might be an issue with the segment lengths.

Yes, here is it.
i made some changes in script

Your lower and upper lengths look correct. I’m gonna assume you just swapped the shoulder joint for hip, elbow for knee, and wrist for ankle.

goalPosition doesn’t seem correct. Feeding a CFrame into V3.new() just gives (0,0,0). You should be setting this value to the position you want the “foot” to be planted at.

How can i do that? like “find the floor”, i already tried some scripts i did but it doens’t worked

Edit: I got it, now i just need to place it at floor cause it’s returning to the middle of map. ;-;
image

You can Raycast too. If you’re doing foot planting what you can do is cast a ray from the hip position to the “ground” position (a ~2 studs below the hip). Your foot position is the position the ray returns.

2 Likes