CCDIKController - Alternate inverse kinematics method for Motor6D rigs

Guess I was wrong lmao

image

1 Like

Great to see you still updating the module! Have 0 idea whats happening or what it does but looks cool lol.

2 Likes

When I play with the custom rig we have, the leg starts spazzing everywhere ignoring like 80% of the ball socket limits. Any Idea why?

Are you using the old version of the CCDIK module? If not then I haven’t tested it out the new C0 formula with the constraints. Then a Repro file will be necessary.

1 Like

Would you be willing to help out a little bit? We are trying to make the Footplacement work with walking animations on our custom rig but I’m not sure how to set up the constraints well, I tried ball sockets but our rig is a little complicated I think? we will check if we are using the old module. Do you have Discord?

Not an update unfortunately, just some disclaimers, issues, and tips.

The first issue is that the module was never intended to combine animations and CCDIK together. The resolving issue with the HumandMale_Model in the CCDIK file just happens to be a one in a chance fluke. What happens is that the animations is added on top of the IK which move the arm away from the goal which the IK algorithm hates and tries to fight back hence the spinning arm problem commonly seen.

Currently, there is no plan on combining IK and normal animations as it’s pretty complex, look at all these diagrams:

Also I recommend this video for additional customization over the IK with a modified CCD algorithm:

To achieve Bone priority / Motor6D priority/ which limb it iterates through more with the module you can modify the input Motor6D table.

So for example this motor6D table:

local leftArm = {leftupperArm,leftelbow,lefthand}

The algorithm will first move the left elbow, then the left upper arm ignoring the left hand as normally we don’t move our wrist when reaching out to grab an object as explained in the video.

*Unless you enable the useLastMotor property, ideal for R6 with only one limb. Though I find it a bit weird to use Inverse kinematics when there is only one limb to control which you might as well just do something like CFrame.lookAt, though I understand theres other benefits like end effector control via an attachment and the built in lerping functionality with the module.

--Within the module
function CCDIKController:_CCDIKIterateStep(goalPosition, step)
	for i = #self.Motor6DTable - 1 + useLastMotor, 1, -1 do

So to modify it we can do this:

local leftupperArm : Motor6D --Some motor6D instance
local leftArm = {leftupperArm,leftupperArm,leftupperArm,leftelbow,lefthand}

This will make the iteration prioritize the left upperArm 3 times more within the module.

5 Likes

I can’t get CCDIK to work in this example (with our without the constraints and attachments).
I tried using EndEffector which made it point correctly, but the issue is that the second part doesn’t move. Only the first one.
Some extra info if it helps in any way:

  • both are unanchored and are set to non collidable.
  • the Body is anchored (i plan on having it anchored)
  • the attachments that are at the same position are facing both the same way
  • I didn’t work either when I tried without the attachments (End Effect made a change though, now its more correct)
  • Not using the “step” parameter, nor the threshold (those arent the cause here)
  • Im using get constraints and, in heartbeat, IterateOnce

I was able to get one working with more points in a different model so I have a little experience with this module, but I still can’t get this to work.

Video link example:

https://medal.tv/games/roblox-studio/clips/wVDg9tD5yOAm6/d1337pDi29eD?invite=cr-MSxaeVQsMzcwOTA5MTks

InitTweenDebug showed this:

Hierarchy:

image

Motor6Ds and attachments:

I don’t know if it’s just not possible with only 2 parts but I’d really appreciate any help you people can give me. Thanks in advance.
Sorry for the 4 edits lol

1 Like

Set this property to true.

The explanation for the InitTweenDebug is that it’s only occuring from 1 Motor6D and the 2nd Motor6D is ignored.

The design choice is explained in the post above and the CCDIK video there.

2 Likes

Rotating arms?

I’m using armController:Destroy() upon the player going beyond a certain distance. Other than that, everything is the same as in the test game.

https://gyazo.com/f02913db42a26f6c1d4a05a94d7324f3

https://gyazo.com/5ae2d24de98b8ace3b641ac8ebf23fd5

1 Like

Sorry unable to replicate within the test place provided in my GitHub.

Are you using the latest CCDIK controller? This should have been fixed since this update post.

Otherwise please dm me your repro file so I can diagnose further.

3 Likes

Hello! Your module is really interesting and helped me out a lot!
I just have one question, after a part of the character finishes iterating, how would I go about putting it back into it’s original position? I’m making my game so I replace traditional animations with procedural ones. I’m just struggling to figure out how to put my arm back, if I extended it to reach and push a button?

2 Likes

For other people that can’t translate it, here ya go!

local Body = workspace.Body
local Leg = workspace.Leg

local Offset = Vector3.new(0,Leg.Size.Y / 2,0)

local currentPosition = Leg.Position
local newPosition = Leg.Position
local oldPosition = Leg.Position

local stepHeight = 1.5
local stepDist = 2
local speed = 5
local lerp = 0

local Params = RaycastParams.new()
Params.FilterDescendantsInstances = { Leg }

-- Had to modify this part a bit
local function Update(dT)
	Leg.Position = currentPosition + Offset

	local Result = workspace:Raycast(Body.Position,Vector3.yAxis * -500,Params)
	if Result then
		if (newPosition - Result.Position).Magnitude > stepDist then
			lerp = 0
			newPosition = Result.Position
		end
	end
	if lerp < 1 then
		local Goal = oldPosition:Lerp(newPosition,lerp)
		Goal += Vector3.new(0,math.sin(lerp * math.pi) * stepHeight,0)

		currentPosition = Goal
		lerp += dT * speed
	else
		oldPosition = newPosition
	end
end

while true do
	local dT = task.wait()

	Update(dT)
end

9 Likes

The documentation is no longer working. Is there still a tutorial?

The tutorial should still be there, just the hyperlinks in the inital page are broken:

https://datlass.github.io/Rbx-CCDIK/BasicSetupTutorial/

Prolly wont fix it, no motivation and the Github website files are missing.

FIX IT GRRR.
No but seriously, it would be very nice.

1 Like

Can this be used while using the animator built into studio? This is something that I could really use as the built in IK controller is limited and very broken.

can someone help me making this look good i added constraints but its worse now

https://gyazo.com/c26902560df0ebc6f98394085a38c125.mp4

Great module, I managed to get it to work with a viewmodel!
But the arm wont fully rotate like the target’s orientation, Is there any way around this?

External Media

Here’s the code/setup (520.1 KB)

1 Like

i get a feeling that the ccdikcontroller itself is broken nowadays

Hey, I tried using this module but for some reason using 2 arms/legs just makes them move and drift off of the joints.

--[[
    R15 with constraints and animations
]]
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CCDIKController = require(ReplicatedStorage.Source.CCDIKController)

local dummy = workspace.HumanMale_Model
local leftTarget = workspace.newTargetConstraints

local dummyMotor6Ds = {}

local dummyDescendants = dummy:GetDescendants()
for _,descendant in pairs (dummyDescendants) do
    if descendant:IsA("Motor6D") then
        dummyMotor6Ds[descendant.Name] = descendant
    end
end

local upperLeg = dummyMotor6Ds["LeftShoulder"]
local knee = dummyMotor6Ds["LeftElbow"]
local foot = dummyMotor6Ds["LeftWrist"]

local r1 = dummyMotor6Ds["RightShoulder"]
local r2 = dummyMotor6Ds["RightElbow"]
local r3 = dummyMotor6Ds["RightWrist"]

local leftLeg = {upperLeg,knee,foot}

local rightLeg = {r1,r2,r3}

local leftLegController = CCDIKController.new(leftLeg)
leftLegController:GetConstraints()
local rightLegController = CCDIKController.new(rightLeg)
rightLegController:GetConstraints()

--Stepped for the CCDIK to reset the .Transform property
RunService.Stepped:Connect(function()
	leftLegController:CCDIKIterateOnce(workspace.M4A1.Grip.Position,0.04)
	rightLegController:CCDIKIterateOnce(workspace.M4A1.BarrelHandle.Position, 0.04)
end)

This is what it looks like and the entirety of my code