R15 IK Foot Placement

Oh, hmm…
I’ve never been good with IK, sorry…

I wouldn’t use the surface normal since this is prone to glitches if your foot is over multiple surfaces. I’d fire a downwards ray at the toes position, then just get the angle between the heel & wherever that hits.

2 Likes

In case anyone gets stuck where I did, here’s some more info from WhoBloxedWho

4 Likes

I have been messing with this for a while, but I can’t seem to get it to work…

local fromAxisAngle = CFrame.fromAxisAngle
local acos = math.acos
local max = math.max
local min = math.min
local cfNew = CFrame.new
local forwardV3 = Vector3.new(0, 0, -1)
local pi = math.pi
local cfAngles = CFrame.Angles

wait(2)

local upperTorso = workspace.ViewModel.UpperTorso
local shoulderMotor = workspace.ViewModel.RightUpperArm.RightShoulder
local elbowMotor = workspace.ViewModel.RightLowerArm.RightElbow
local lowerC0 = elbowMotor.C0

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

game:GetService("RunService").RenderStepped:Connect(function()
	--local shoulderCF = upperTorso.CFrame * shoulderMotor.C0
	local shoulderCF = shoulderMotor.Part0.CFrame
	local plane, shoulderAngle, elbowAngle = solveIK(shoulderCF, workspace.Front.Position, shoulderMotor.Part0.Size.Y, shoulderMotor.Part1.Size.Y)

	shoulderMotor.C0 = upperTorso.CFrame:toObjectSpace(plane) * cfAngles(shoulderAngle, 0, 0)
	elbowMotor.C0 = lowerC0 * cfAngles(elbowAngle, 0, 0)
end)
4 Likes

If you’re trying to keep the arm from moving a point past its length. @systack quoted @WhoBloxedWho Regarding this right before your post.

You will want to change this condition statement.

elseif l3 > l1 + l2 then 
   return planeCF * cfNew(0, 0, l1 + l2 - l3), pi/2, 0

To

elseif l3 > l1 + l2 then
   return planeCF, math.pi/2, 0
1 Like

I figured out how to keep it at a fixed point. However, if you look at the gif, the arm isn’t grabbing the block exactly how it should.

Could it possibly be the lengths in which the function is solving with (l1 and l2)? I’ve noticed instead of using the two values 0.515 and 1.1031 you are using both part’s Size.Y.

I am using the code provided by @LMH_Hutch. It works alright assuming that the joints are all lined up.

But they aren’t. I am cframing the hand to the weapon, and using the wrist position from the hand as the targetpoint, but the wrist position from the lower arm does not connect to it. Anyone have suggestions on how I can take attachments into account?

you could use attachments as target points just set the goal to Attachment.WorldPosition

That is what I am doing, but all of the other attachments in the parts that make up the arm are not lining up with the target point. The code assumes I am trying to line up the arm. I am not trying to line up the arm, but trying to line up the attachment in the arm.

1 Like

Oh so you are using attachments instead of motor6ds ? If then even i tried it and it kept glitching out

1 Like