Inverse Kinematics?

I’ve never really been able to wrap my head around inverse kinematics, well I can, just using it with the proper Motor joints on the character just causes me issues. I’ve been toying with the script below but there’s just one problem. The hand and overall arm never actually points to the center of the actual part, always seems to be extremely far away. Now it’s understandable for animations to cause a bit of deviation but I can’t seem to come up with a fix of any sort.

Now, this script is basically the normal resource used for this topic, but of course has the same exact issue.

Script

LocalScript that goes inside of “StarterCharacterScripts” mostly lazy, with a part named “Front” in workspace.

local Pi = math.pi;
local halfPi = Pi/2;
local ForwardV3 = Vector3.new(0,0,-1);

local function solvearm(originCFrame,target,a,b)
	local localized = originCFrame:pointToObjectSpace(target);
	local localizedUnit = localized.unit;
	
	local axis = ForwardV3:Cross(localizedUnit);
	local angle = math.acos(-localizedUnit.Z);
	local plane = originCFrame*CFrame.fromAxisAngle(axis,angle);
	
	local c = localized.Magnitude;
	
	if c < math.max(a,b)-math.min(a,b) then
		
		return plane * CFrame.new(0,0,math.max(b,a)-math.min(b,a)-c), halfPi, Pi;
		
	elseif c > a+b then
		
		return plane, halfPi, 0;
		
	else 
		
		local theta1 = -math.acos((-(b*b) + (a*a) + (c*c)) / (2*a*c));
		local theta2 = math.acos(((b*b) - (a*a) + (c*c)) / (2*b*c));
		
		return plane, theta1 + halfPi, theta2 - theta1;
		
	end;
end;

local UpperTorso = script.Parent.UpperTorso;
local RightUpperArm = script.Parent.RightUpperArm;
local RightLowerArm = script.Parent.RightLowerArm;
local RightShoulder = RightUpperArm.RightShoulder;
local RightElbow = RightLowerArm.RightElbow;

local RightShoulderInt = RightShoulder.C0;
local RightElbowInt = RightElbow.C0;

local targetPos = workspace:WaitForChild("Front");

local Tp0 = CFrame.new((UpperTorso.CFrame * CFrame.new(1.25,0,-1)).p) * CFrame.Angles(0,math.pi/2,0);

while game:GetService("RunService").RenderStepped:Wait() do
	--targetPos.Position = 
	local PosSize = (targetPos.Size / 2).Magnitude
	
	local TargetPos = targetPos.Position;
	local ShoulderCF = UpperTorso.CFrame * RightShoulderInt;
	local Plane, ShoulderAngle, ElbowAngle = solvearm(ShoulderCF, TargetPos, RightLowerArm.Size.Y, RightUpperArm.Size.Y);
	if Plane then
		RightShoulder.C0 = UpperTorso.CFrame:toObjectSpace(Plane) * CFrame.Angles(ShoulderAngle,0,0);
		RightElbow.C0 = RightElbowInt * CFrame.Angles(ElbowAngle,0,0);
	end
	
end;

If anyone is able to help point out what I’m doing wrong or recommend anything it’d be fantastic! I’ve honestly spent years trying to get proper IK but it just doesn’t work with my brain.

4 Likes

You might take a look at what @Quenty did in his NevermoreEngine. He has a pretty nice library built around IK there. Here’s a link if you’re interested https://github.com/Quenty/NevermoreEngine/tree/version2/Modules/Client/IK

It may offer some insight as to what could be off with yours.

2 Likes

Sadly looking at it, and trying to mess with it didn’t seem to help. I just don’t really understand what I’m doing wrong, but thank you for trying at least. :slight_smile:

Also, the main issue has to due with pretty much every example or anything here on the forums, so if someone is able to help get it fixed. Then we can also hopefully get the community tutorial fixed for anyone else that has this problem in the future.

Properly going through the Math for Kinematics is much more helpful than reading some code examples IMO. Lecture Notes such as http://www.cs.columbia.edu/~allen/F15/NOTES/invkin.pdf and explains how to solve/express the system for multiple cases in which the simple 2 joint IK is unacceptable.