CCDIKController - Alternate inverse kinematics method for Motor6D rigs

What would be the proper way to stop a CCDIKController? Even if I stop calling any functions, the arm keeps being animated weird even after I restore the C0 and C1 properties of the Motor6D object.
What’s weirder is that I don’t even have to call any methods for the weird behavior to occur - the moment I create a new CCDIKController object, the animation for the left arm becomes off:


My code is just this:
image
Is this expected behavior? Because even after calling :Destroy() this remains :confused:

I’m assuming the behavior has to do with how you reset the rotation here:
image
But it seems pretty hard to restore the original Motor6D behavior nevertheless

3 Likes

It’s probably due to the C0 and C1 resets I included when creating the CCDIK controller which @nurokoi pointed out since I reset the orientation to CFrame.new() which probably messed up the direction the animations were made in.

You can probably include a method to reset it to original orientation once the CCDIK controller is destroyed.

2 Likes

Yeah, I fixed it by just resetting the C0 and C1 values back to default right after creating the CCDIKController object. Would this cause any unexpected behavior when using the Controller’s methods later on? Because I’m thinking of wrapping the CCDIKController.new method to safely reset the C0 and C1 properties back to default right after creating the controller object.
image

EDIT: Yeah I see what you mean by what nurokoi pointed out now - it seems like I need to nullify all rotation right before calling any CCDIK methods to fix this behavior… Really weird workaround, but it’ll sadly have to do

2 Likes

I got it working image


Already said this but this module is really useful and easy-to-learn; I can’t imagine being able to do the same with a FABRIK-based one…

8 Likes

So, I’ve now ran into an issue where the CCDIK module iterates from seemingly the default resting position of the right arm - is there a way to change this behavior to iterate from the current arm’s position? Currently what I’m doing is lerping an arm onto a target, but if I keep lerping it once it reached that target once, the arm will start from it’s default position and rise quickly to the target position like so:


I can’t instantly iterate the arm after iterating it once because if the target goal moves slightly, the arm’s rotation would quickly snap towards the goal rather than smoothly interpolating towards it. I see properties such as CCDIKController.LerpMode, but I don’t know what they do and messing around with them doesn’t see to do much either.

Is there some solution to this, or do I need to alter the source to get the behavior I’d like? :confused:
There isn’t any method that returns the CFrame that the limb would be at either without actually changing the limb, so I can’t use a binary search to figure out the right step parameter to seamlessly lerp towards the end goal either.

EDIT: It seems like CCDIKIterateUntil fixes most of the problem in regards to random snapping - I don’t lerp after the first time (i.e when the arm reaches for the door), which also addresses my other issue above.
https://cdn.discordapp.com/attachments/785870115463626765/852636743148634122/LqelvIBfrc.mp4

7 Likes

Hey, I am attempting to make a mech similar to yours. Now my problem is not that I cant use the module but I’m unsure on how to make the legs move as if their walking.

This is what iv got. If my explanation isnt clear enough then basically I am trying to replicated the legs movement in your post “Haha mech go stomp”

[Haha Mech go stomp, any feedback?]

This is like my third post sorry if I am doing this thing really wrong lol.
Thanks in advance.

1 Like

Is this will work with R15 as well?

1 Like

A good method for this is to move the torso (main part which is not IK) forward. When the legs, which are IK, cannot reach the red cubes, move the red cubes forward to the original offset. Repeat. This will give the illusion of walking.

As for the module itself, great job! Looks so smooth!

2 Likes

Very cool module!

By the way, I believe you can put devforum links in model descriptions:

image

2 Likes

Should I create invisible fake legs so that the IK legs dont make the mech fall?

1 Like

Sure. Or, you can anchor the mech’s torso and lerp the CFrame to move it. For collisions, you would use :GetTouchingParts() and raycast to find the direction of collision. It’s a bit advanced, but would give you more control.

Or, alternatively, you can just use a humanoid with supports/fake legs

2 Likes

I cant anchor the torso due to Network ownership (for smooth player control) . Also I have been using humanoid. So from that I am going to create invisible legs for support .

Then I will find a good offset position for the red parts alternating with maybe a debounce system? Only thing I cant work out is going left and right. I am also assuming ill use CCDIKIterateUntil.

Thank you for the quick and helpful responses I am quite new to DevForums so this has given me a great first experience pro man.

1 Like

Yeah. Here’s some unity code you can translate into studio code to get you started.


From this video

Stepping horizontally would be similar except on a different axis.
For world space to object space, you can take the CFrame and do :ToObjectSpace

8 Likes

Thank you so much for taking time out your day to help me.

I am going to work out how to covert this into LUA luckily I have had experience with C#.

2 Likes

Hello! This module is just Awesome! But sadly the Github Page is missing :frowning:
And so I’ve got 0 idea on how to use this module, it’d be great help if you could fix it, or maybe add a tutorial here!

Thanks anyways for the module!

2 Likes

Theirs documentation and a tutorial in the 3rd post.

2 Likes

Update!

After I was contacted by someone who wanted a version which could be compatible with animations I have decided to officially push a version which fixes the error.

Before:

After:
Notice how the idle animations are moving the IK effected limb:

The only difference is that for it to work the iteration should be done within .Stepped.

--Stepped for the CCDIK to reset the .Transform property
RunService.Stepped:Connect(function()
    local goal = leftTarget.Position
    leftLegController:CCDIKIterateOnce(goal,0) --0 tolerance always try to iterate towards goal
end)

The explanation on how it works is that it will:

  1. Apply the .Transform animations onto the C0 instead

  2. Perform the usual move limb closer towards the goal

  3. Then apply constraints

In the proper order instead of:

  1. Perform the usual move limb closer towards the goal

  2. Then apply constraints

  3. Then animations are applied moving them out of the constraint range

CCDIK iterate step function fixed
function CCDIKController:_CCDIKIterateStep(goalPosition, step)
	local constraints = self.Constraints
	local useLastMotor = self.UseLastMotor and 1 or 0 --Makes it so that it iterates the only one motor in the table
	for i = #self.Motor6DTable - 1 + useLastMotor, 1, -1 do
		local currentJoint = self.Motor6DTable[i]

		currentJoint.C0 *= currentJoint.Transform -- apply animations to C0
		self:RotateFromEffectorToGoal(currentJoint, goalPosition, step)

		currentJoint.Transform = CFNEW()

		if constraints then
			local jointConstraintInfo = constraints[currentJoint]
			if jointConstraintInfo then
				if jointConstraintInfo.ConstraintType == "Hinge" then
					self:RotateToHingeAxis(currentJoint, jointConstraintInfo)
				end
				if jointConstraintInfo.ConstraintType == "BallSocketConstraint" then
					self:RotateToBallSocketConstraintAxis(currentJoint, jointConstraintInfo)
				end
			end
		end
	end
end
9 Likes

Fantastic stuff here. Great work!

1 Like

Is there a way to fix this issue with the arms

local leftupperArm = dummyMotor6Ds["LeftShoulder"]
local leftelbow = dummyMotor6Ds["LeftElbow"]
local lefthand = dummyMotor6Ds["LeftWrist"]

local rightupperArm = dummyMotor6Ds["RightShoulder"]
local rightelbow = dummyMotor6Ds["RightElbow"]
local righthand = dummyMotor6Ds["RightWrist"]
local leftArm = {leftupperArm,leftelbow,lefthand}
local rightArm = {rightupperArm,rightelbow,righthand}

local leftarmController = CCDIKController.new(leftArm)
local righrarmController = CCDIKController.new(rightArm)

RunService.Heartbeat:Connect(function()
local goal = workspace.Steer.CFrame * Vector3.new(0, 0.1, -(workspace.Steer.Size.Z * 0.5 - 0.2))
local goalr = workspace.Steer.CFrame * Vector3.new(0, 0.1, (workspace.Steer.Size.Z * 0.5 - 0.2))
leftarmController:CCDIKIterateOnce(goal, 0)
righrarmController:CCDIKIterateOnce(goalr, 0)
end)
3 Likes

Add constraints to make the arms bend the right way by using the :GetConstraints() function. Remember to create the Constraint Instances and attachment like the example in the test place.

5 Likes