R6 Inverse Kinematics

im kinda confused for the github script to we paste it in a module script in replicatestorage?

yeah, just copy and paste the code onto a module script in replicated storage

1 Like

Hey, thanks for the response.

I’m kind of stuck, I’m sorry I’ve never used IK before so I’m a bit lost. I’ve pasted the script into a module script in replicated storage. it doesn’t work even though im in r6.

In the github, do I also add in the 2 scripts in “How to use”?

thanks for your patience

1 Like

Potentially as the IK position Y goes up, limit its Z more and more

Wow, this is neat. I’ll try experimenting with this later, see that I could do.

is it possbile to use this module
for custom limbs
for example an custom arm that is attached to the player

1 Like

I did a similar approach to number 1.

I made so the client does the Ik and uses a unreliable remote to send the motor6d hips C0 to server and the server again applies the C0 to clients motor6d hips.

I’m not so sure with this approach as you said it could put stress to the server, So far it has worked fine at even 10 players in the server beyond 10 I have not tested.

1 Like

It doesn’t seem to work with the default roblox animations, Im trying to maintain player walking animations but have the arm animations change. Here’s my code, any idea what’s going wrong?

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local PlayerService = game:GetService("Players")

local Player = PlayerService.LocalPlayer

local Ik6 = require(ReplicatedStorage.Modules.R6IK)



Player.CharacterAppearanceLoaded:Connect(function()
	local leftarm = Ik6.New(Player.Character)

	RunService.Heartbeat:Connect(function()
		leftarm:ArmIK("Right", workspace.IkTestPart.Position)
	end)
end)
1 Like

This module sadly does not support animation playing on the same limb as what the ik is using

I had the player play a looped animation with the arms down to completely disable any arm movement with roblox animations

how do you do that? Im pretty new to all this programming stuff…

Hey i saw this recently i dont know if your still looking or an answer but i got this to work


You can adjust it way more heres the rewritten code all i added was clamps

Attributes setup
image

code (:sunglasses:)

local function SolveArmIK(originCFF, targetPos, l1, l2, C1Off, Side : "Left" | "Right")	
	-- build intial values for solving
	local originCF
	if Side == "Left" then
		originCF = originCFF*CFrame.new(0,0,C1Off.X)
	elseif Side == "Right" then
		originCF = originCFF*CFrame.new(0,0,-C1Off.X)
	end
	local localized = originCF:pointToObjectSpace(targetPos)
	local localizedUnit = localized.unit
	local l3 = localized.magnitude

	-- build a "rolled" planeCF for a more natural arm look
	local axis = Vector3.new(0, 0, -1):Cross(localizedUnit)
	local angle = math.acos(-localizedUnit.Z)
	local planeCF = originCF * CFrame.fromAxisAngle(axis, angle)

	-- case: point is to close, unreachable
	-- return: push back planeCF so the "hand" still reaches, angles fully compressed
	if l3 < math.max(l2, l1) - math.min(l2, l1) then
		return planeCF * CFrame.new(0, 0,  math.max(l2, l1) - math.min(l2, l1) - l3), -math.pi/2, math.pi

		-- case: point is to far, unreachable
		-- return: for forward planeCF so the "hand" still reaches, angles fully extended
	elseif l3 > l1 + l2 then
		return planeCF, math.pi/2, 0, l3

		-- case: point is reachable
		-- return: planeCF is fine, solve the angles of the triangle
	else
		local a1 = -math.acos((-(l2 * l2) + (l1 * l1) + (l3 * l3)) / (2 * l1 * l3))
		local a2 = math.acos(((l2  * l2) - (l1 * l1) + (l3 * l3)) / (2 * l2 * l3))

		return planeCF, a1 + math.pi/2, a2 - a1
	end
end

local function SolveLegIK(originCFF, targetPos, l1, l2, C1Off)	
	-- build intial values for solving
	local originCF = originCFF*CFrame.new(-C1Off.X,0,0)
	local localized = originCF:pointToObjectSpace(targetPos)
	local localizedUnit = localized.unit
	local l3 = localized.magnitude

	-- build a "rolled" planeCF for a more natural arm look
	local axis = Vector3.new(0, 0, -1):Cross(-localizedUnit)
	local angle = math.acos(-localizedUnit.Z)
	local planeCF = originCF * CFrame.fromAxisAngle(axis, angle):Inverse()

	-- case: point is to close, unreachable
	-- return: push back planeCF so the "hand" still reaches, angles fully compressed
	if l3 < math.max(l2, l1) - math.min(l2, l1) then
		return planeCF * CFrame.new(0, 0,  math.max(l2, l1) - math.min(l2, l1) - l3), -math.pi/2, math.pi

		-- case: point is to far, unreachable
		-- return: for forward planeCF so the "hand" still reaches, angles fully extended
	elseif l3 > l1 + l2 then
		return planeCF, math.pi/2, 0, l3

		-- case: point is reachable
		-- return: planeCF is fine, solve the angles of the triangle
	else
		local a1 = -math.acos((-(l2 * l2) + (l1 * l1) + (l3 * l3)) / (2 * l1 * l3))
		local a2 = math.acos(((l2  * l2) - (l1 * l1) + (l3 * l3)) / (2 * l2 * l3))

		return planeCF, math.pi/2-a1, -(a2 - a1)
	end
end

local function WorldCFrameToC0ObjectSpace(motor6DJoint,worldCFrame)
	local part1CF = motor6DJoint.Part1.CFrame
	local part0 = motor6DJoint.Part0
	local c1Store = motor6DJoint.C1
	local c0Store = motor6DJoint.C0
	local relativeToPart0 = part0.CFrame:inverse() * worldCFrame * c1Store

	local goalC0CFrame = relativeToPart0

	return goalC0CFrame
end

local R6IK = {}
R6IK.__index = R6IK

function R6IK.New(Character)
	local self = {}
	self.Torso = Character.Torso
	self.HumanoidRootPart = Character.HumanoidRootPart
	self.LeftArm = Character["Left Arm"]
	self.RightArm = Character["Right Arm"]
	self.LeftLeg = Character["Left Leg"]
	self.RightLeg = Character["Right Leg"]

	self.Motor6Ds = {
		["Left Shoulder"] = self.Torso["Left Shoulder"],
		["Right Shoulder"] = self.Torso["Right Shoulder"],
		["Left Hip"] = self.Torso["Left Hip"],
		["Right Hip"] = self.Torso["Right Hip"],
		["RootJoint"] = self.HumanoidRootPart["RootJoint"]
	}

	self.C0s = {
		["Left Shoulder"] = self.Motor6Ds["Left Shoulder"].C0,
		["Right Shoulder"] = self.Motor6Ds["Right Shoulder"].C0,
		["Left Hip"] = self.Motor6Ds["Left Hip"].C0,
		["Right Hip"] = self.Motor6Ds["Right Hip"].C0,
		["RootJoint"] = self.Motor6Ds["RootJoint"].C0
	}

	self.C1s = {
		["Left Shoulder"] = self.Motor6Ds["Left Shoulder"].C1,
		["Right Shoulder"] = self.Motor6Ds["Right Shoulder"].C1,
		["Left Hip"] = self.Motor6Ds["Left Hip"].C1,
		["Right Hip"] = self.Motor6Ds["Right Hip"].C1,
		["RootJoint"] = self.Motor6Ds["RootJoint"].C1
	}

	self.Part0s = {
		["Left Shoulder"] = self.Motor6Ds["Left Shoulder"].Part0,
		["Right Shoulder"] = self.Motor6Ds["Right Shoulder"].Part0,
		["Left Hip"] = self.Motor6Ds["Left Hip"].Part0,
		["Right Hip"] = self.Motor6Ds["Right Hip"].Part0,
		["RootJoint"] = self.Motor6Ds["RootJoint"].Part0
	}

	self.Part1s = {
		["Left Shoulder"] = self.Motor6Ds["Left Shoulder"].Part1,
		["Right Shoulder"] = self.Motor6Ds["Right Shoulder"].Part1,
		["Left Hip"] = self.Motor6Ds["Left Hip"].Part1,
		["Right Hip"] = self.Motor6Ds["Right Hip"].Part1,
		["RootJoint"] = self.Motor6Ds["RootJoint"].Part1
	}
	
	self.LeftUpperArmLength = 1
	self.LeftLowerArmLength = 1
	
	self.RightUpperArmLength = 1
	self.RightLowerArmLength = 1
	
	self.LeftUpperLegLength = 1
	self.LeftLowerLegLength = 1
	
	self.RightUpperLegLength = 1
	self.RightLowerLegLength = 1
	
	self.TorsoIK = false
	
	return setmetatable(self, R6IK)
end

function R6IK:ArmIK(Side : "Left" | "Right", Position:Vector3)
	if Side == "Left" then
		local OriginCF = self.Torso.CFrame*self.C0s["Left Shoulder"]
		local C1Off = self.C1s["Left Shoulder"]
		local PlaneCF,ShoulderAngle,ElbowAngle, l3 = SolveArmIK(OriginCF, Position, self.LeftUpperArmLength, self.LeftLowerArmLength, C1Off, Side)

		local ShoulderAngleCFrame, ElbowAngleCFrame = CFrame.Angles(ShoulderAngle, 0, 0), CFrame.Angles(ElbowAngle, 0, 0)

		local ShoulderCF = PlaneCF * ShoulderAngleCFrame*CFrame.new(0,-self.LeftUpperArmLength * 0.5,0)
		local ElbowCF = ShoulderCF*CFrame.new(0,-self.LeftUpperArmLength * 0.5,0)* ElbowAngleCFrame * CFrame.new(0, -self.LeftLowerArmLength*0.5, 0)*CFrame.new(0,(self.LeftArm.Size.Y-self.LeftLowerArmLength)*0.5,0)

		return  WorldCFrameToC0ObjectSpace(self.Motor6Ds["Left Shoulder"], ElbowCF)
	elseif Side == "Right" then
		local OriginCF = self.Torso.CFrame*self.C0s["Right Shoulder"]
		local C1Off = self.C1s["Right Shoulder"]
		local PlaneCF,ShoulderAngle,ElbowAngle, l3 = SolveArmIK(OriginCF, Position, self.RightUpperArmLength, self.RightLowerArmLength, C1Off, Side)

		local ShoulderAngleCFrame, ElbowAngleCFrame = CFrame.Angles(ShoulderAngle, 0, 0), CFrame.Angles(ElbowAngle, 0, 0)

		local ShoulderCF = PlaneCF * ShoulderAngleCFrame*CFrame.new(0,-self.RightUpperArmLength * 0.5,0)
		local ElbowCF = ShoulderCF*CFrame.new(0,-self.RightUpperArmLength * 0.5,0)* ElbowAngleCFrame * CFrame.new(0, -self.RightLowerArmLength*0.5, 0)*CFrame.new(0,(self.RightArm.Size.Y-self.RightLowerArmLength)*0.5,0)

		return  WorldCFrameToC0ObjectSpace(self.Motor6Ds["Right Shoulder"], ElbowCF)
	end
end

function R6IK:LegIK(Side : "Left" | "Right", Position:Vector3)
	if Side == "Left" then
		local OriginCF = self.Torso.CFrame*self.C0s["Left Hip"]
		local C1Off = self.C1s["Left Hip"]
		local PlaneCF,ShoulderAngle,ElbowAngle, l3 = SolveLegIK(OriginCF*CFrame.Angles(0, math.pi/2, 0), Position, self.LeftUpperLegLength, self.LeftLowerLegLength, C1Off)

		local HipAngleCFrame, KneeAngleCFrame = CFrame.Angles(math.clamp(ShoulderAngle,script:GetAttribute("lege"),script:GetAttribute("legs")), 0, 0), CFrame.Angles(math.clamp(ElbowAngle,script:GetAttribute("lege"),script:GetAttribute("legs")) , 0, 0)

		
		local HipCF = PlaneCF * HipAngleCFrame*CFrame.new(0,-self.LeftUpperLegLength * 0.5,0)
		
		local KneeCF = HipCF*CFrame.new(0,-self.LeftUpperLegLength * 0.5,0)* KneeAngleCFrame * CFrame.new(0, -self.LeftLowerLegLength*0.5, 0)*CFrame.new(0,(self.LeftLeg.Size.Y-self.LeftLowerLegLength)*0.5,0)


		return WorldCFrameToC0ObjectSpace(self.Motor6Ds["Left Hip"], KneeCF)
		 
	elseif Side == "Right" then
		local OriginCF = self.Torso.CFrame*self.C0s["Right Hip"]
		local C1Off = self.C1s["Right Hip"]
		local PlaneCF,ShoulderAngle,ElbowAngle, l3 = SolveLegIK(OriginCF*CFrame.Angles(0, -math.pi/2, 0), Position, self.RightUpperLegLength, self.RightLowerLegLength, C1Off)

		local HipAngleCFrame, KneeAngleCFrame = CFrame.Angles(math.clamp(ShoulderAngle,script:GetAttribute("lege"),script:GetAttribute("legs")), 0, 0), CFrame.Angles(math.clamp(ElbowAngle,script:GetAttribute("lege"),script:GetAttribute("legs")) , 0, 0)

		
		local HipCF = PlaneCF * HipAngleCFrame*CFrame.new(0,-self.RightUpperLegLength * 0.5,0)
		
		local KneeCF = HipCF*CFrame.new(0,-self.RightUpperLegLength * 0.5,0)* KneeAngleCFrame * CFrame.new(0, -self.RightLowerLegLength*0.5, 0)*CFrame.new(0,(self.RightLeg.Size.Y-self.RightLowerLegLength)*0.5,0)
		
		
		return WorldCFrameToC0ObjectSpace(self.Motor6Ds["Right Hip"], KneeCF)
	end
end

return R6IK
4 Likes

Hey brother i found a solution to this too run ik on a seperate charecter that is like a viewmodel weld the viewmodel to the torso disable the physics on the viewmodel’s humanoid
And it works well
Also quick tip turn off can query and can collide and can touch on all of the viewmodel limbs

Hi @robert_stevey, I’m quite new to IK and I am trying to make a gun system that uses IK. I haven’t done much yet, but my problem is that the arms are taking the position of the first limb rather than second limb. The green balls are the right arm’s target position and the blue ones the left arm’s target position. Also, how do I increase the weight of the IK so that the animation doesn’t affect it much or at all? This is the script I have right now:

local R6IK = require(game.ReplicatedStorage.R6IK)

local character = script.Parent
local hrp:Part = character:WaitForChild('HumanoidRootPart')
local torso:Part = character:WaitForChild('Torso')

local rIKAtt = Instance.new('Attachment', hrp)
rIKAtt.Name = 'rIKAtt'

local ikSolver = R6IK.New(character)

game:GetService("RunService").PreRender:Connect(function()
	local RtargetPosition = (torso.Position + (torso.CFrame.RightVector * 1.2) + (torso.CFrame.UpVector * -0.4)) + (torso.CFrame.LookVector * 2.5)
	local Rp1 = Instance.new('Part', workspace)
	Rp1.Position = RtargetPosition
	Rp1.Anchored = true
	Rp1.Color = Color3.fromRGB(0, 255, 0)
	Rp1.Shape = Enum.PartType.Ball
	Rp1.Size = Vector3.new(0.5, 0.5, 0.5)
	Rp1.CanCollide = false
	Rp1.CanTouch = false
	Rp1.CanQuery = false
	
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {character}
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	raycastParams.IgnoreWater = true
	
	local RraycastResult = workspace:Raycast((torso.Position + (torso.CFrame.RightVector * 1.2) + (torso.CFrame.UpVector * -0.4)), torso.CFrame.LookVector * 2.5, raycastParams)
	
	if RraycastResult then
		print(RraycastResult.Instance)
		
		local Rp2 = Instance.new('Part', workspace)
		Rp2.Position = RraycastResult.Position
		Rp2.Anchored = true
		Rp2.Color = Color3.fromRGB(255, 0, 0)
		Rp2.Shape = Enum.PartType.Ball
		Rp2.Size = Vector3.new(0.5, 0.5, 0.5)
		Rp2.CanCollide = false
		Rp2.CanTouch = false
		Rp2.CanQuery = false
		
		ikSolver:ArmIK("Right", Rp2.Position)
	else
		ikSolver:ArmIK("Right", Rp1.Position)
	end
	
-----------------------------------------------------------------------------------------------	
	
	local LtargetPosition = (torso.Position + (torso.CFrame.RightVector * 1.1) + (torso.CFrame.UpVector * -0.4)) + (torso.CFrame.LookVector * 4)
	local Lp1 = Instance.new('Part', workspace)
	Lp1.Position = LtargetPosition
	Lp1.Anchored = true
	Lp1.Color = Color3.fromRGB(0, 0, 255)
	Lp1.Shape = Enum.PartType.Ball
	Lp1.Size = Vector3.new(0.5, 0.5, 0.5)
	Lp1.CanCollide = false
	Lp1.CanTouch = false
	Lp1.CanQuery = false

	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {character}
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	raycastParams.IgnoreWater = true

	local LraycastResult = workspace:Raycast((torso.Position + (torso.CFrame.RightVector * 1.1) + (torso.CFrame.UpVector * -0.4)), torso.CFrame.LookVector * 4, raycastParams)

	if LraycastResult then
		print(LraycastResult.Instance)

		local Lp2 = Instance.new('Part', workspace)
		Lp2.Position = LraycastResult.Position
		Lp2.Anchored = true
		Lp2.Color = Color3.fromRGB(255, 170, 0)
		Lp2.Shape = Enum.PartType.Ball
		Lp2.Size = Vector3.new(0.5, 0.5, 0.5)
		Lp2.CanCollide = false
		Lp2.CanTouch = false
		Lp2.CanQuery = false
		
		ikSolver:ArmIK("Left", Lp2.Position)
	else
		ikSolver:ArmIK("Left", Lp1.Position)
	end
end)

Hello, The code works great, but I can’t seem to replicate what you have in the picture where your legs follow the IK, only the arms for me.

Sorry for late response time zones are yucky :sob:
What i did was raycast to the ground and update it every runservice.heartbeat
For the arms i welded a second humanoid to the charecter and named it world arms
Disabled can query for all of them
And ran the ik on the specific arm when it gets used thats mostly it!
If you want some code examples feek free to ask.

Don’t even worry about timezones, rarely fall asleep anyway. But yes, code examples would be lovely, trying to learn to script.

i am in desperate need of help plsss :sob:

IKStuff.rbxl (80.6 KB)
This is a place file that will show how the ik will work with tools
and how it will work with feet
i hope this helps

1 Like

I put a resource right above this message

1 Like