Having trouble calculating this CFrame

I have two dummies, one in a pose and a neutral one. The dummy in the pose has its C1 properties of its Motor6Ds altered, and the default C0 value. What I need to do here is get the first dummy into the same pose, but by changing the C0 values instead. I’ve tried endlessly on this, but I’m not experienced enough with CFrames to do this by myself. The CFrame Math Operations page has the equation used for welds and Motor6Ds, which might be useful.

weld.Part0.CFrame * weld.C0 = weld.Part1.CFrame * weld.C1

Here is a place file with the two dummies in the picture if you want to try: help.rbxl (22.7 KB)


All Motor6Ds are being changed in the pose, even if just by a little bit. Once I finally figure out how to do this, it’ll come in use for other poses as well where the Neck and RootJoint move more, so it’s important that those two are still taken into account. This is for a custom animator. Any help is appreciated, I have seriously been trying this for around 4 hours.

2 Likes

I’ll bump this since nobody who knows about this stuff has apparently seen it.

Are you able to move the arm with C0 but just not into the same position as the other Dummy?
Did you see this post? Motor6D, Motor, Transform, Difference - #3 by sircfenner?

There is this equation that might give you more ideas:
Part0.CFrame * Motor6D.C0 * Motor6D.Transform = Part1.CFrame * Motor6D.C1

Maybe you can get C0 with…
C0 = (Part1.CFrame * Motor6D.C1) / (Part0.CFrame * Motor6D.Transform)
… and use that C0 value with the other Dummy. Or maybe not… would probably need to zero some of those or not use them… and can’t divide CFrames…hmm

I have no experience with this motor6D object, so just thinking of something you might try.

I don’t know how the Transform property works, I tried changing it and nothing happened.
The closest I’ve been able to get is getting the Torso/RootJoint into the right spot. Here’s what I did. I used SetPrimaryCFrame() on both dummys to move them to CFrame.new(), the identity CFrame. I did this so that I could just directly use the CFrame of the Torso instead of doing some voodoo magic with the C1 of the RootJoint. I ran this code and it got the dummy’s Torso in the right spot using C0.

workspace.Dummy1.HumanoidRootPart.RootJoint.C0 = workspace.Dummy2.Torso.CFrame*workspace.Dummy1.HumanoidRootPart.RootJoint.C1:Inverse()

I don’t think this method will keep working for the other joints since they’re connected to the Torso, not the HumanoidRootPart, and the Torso isn’t at the identity CFrame anymore.

I think I figured out a way to do it but its gonna take some unholy code, I’ll report back in a few minutes.

1 Like

Working with this rn

local motorOld = workspace.Dummy0.LeftUpperArm.LeftShoulder
local motorNew = workspace.Dummy1.LeftUpperArm.LeftShoulder

for i = 0, 100 do
	wait(.1)
	motorOld.C1 = motorOld.C1 * CFrame.Angles(math.rad(10),math.rad(1),math.rad(1))
	--motorNew.C0 = motorNew.C0 * CFrame.Angles(math.rad(-10),math.rad(-1),math.rad(-1))
	motorNew.C0 = motorOld.C1:Inverse()
end

Both dummys are rotating the joint the same way, but the placement of the 2nd is off.

Sorry you have to see this abominable code but I was tired and didn’t feel like using variables or just using a loop like I should’ve. Basically what I did was: position the RootJoint like I said above (make sure you already put both dummy models to CFrame.new()), change the PrimaryParts to the Torso to get the Torso to CFrame.new(), put the PrimaryParts back, then used the same method I did for the RootJoint on everything else.

workspace.Dummy1.HumanoidRootPart.RootJoint.C0 = workspace.Dummy2.Torso.CFrame*workspace.Dummy2.HumanoidRootPart.RootJoint.C1:Inverse()
workspace.Dummy1.PrimaryPart = workspace.Dummy1.Torso
workspace.Dummy1:SetPrimaryPartCFrame(CFrame.new())
workspace.Dummy1.PrimaryPart = workspace.Dummy1.HumanoidRootPart
workspace.Dummy2.PrimaryPart = workspace.Dummy2.Torso
workspace.Dummy2:SetPrimaryPartCFrame(CFrame.new())
workspace.Dummy2.PrimaryPart = workspace.Dummy2.HumanoidRootPart
workspace.Dummy1.Torso["Right Hip"].C0 = workspace.Dummy2["Right Leg"].CFrame*workspace.Dummy1.Torso["Right Hip"].C1
workspace.Dummy1.Torso["Left Hip"].C0 = workspace.Dummy2["Left Leg"].CFrame*workspace.Dummy1.Torso["Left Hip"].C1
workspace.Dummy1.Torso["Right Shoulder"].C0 = workspace.Dummy2["Right Arm"].CFrame*workspace.Dummy1.Torso["Right Shoulder"].C1
workspace.Dummy1.Torso["Left Shoulder"].C0 = workspace.Dummy2["Left Arm"].CFrame*workspace.Dummy1.Torso["Left Shoulder"].C1
workspace.Dummy1.Torso["Neck"].C0 = workspace.Dummy2.Head.CFrame*workspace.Dummy1.Torso["Neck"].C1

Honestly looking at my own code right now I can hardly explain what I’m looking at and I’m already forgetting how this mess works, but there’s 100% an actual way to do this but I just did it the only way I could think of.
Leaving the solution unmarked because this doesn’t deserve to be it.

:smiley:
Hey, if it produces the results you are after then it’s a step in the right direction! gg.

1 Like

Little test script I was playing with. It only handles rotations to C1s. That CFrame.new constructor that uses the whole matrix was the only way I was able to get it to convert the C1 rotations to C0 without messing up the position of parts on the second Dummy. Something to explore further I guess. There’s prob a more elegant way to do that. I was testing with R15s, but should work with any Motor6D rig.

Anyway, maybe this helps, maybe not. Was educational for me! I wouldn’t mark this one either (even if it turns out to be useful). With luck, someone who has experience with these things will show up and share some insights.

Best of luck with the custom animator moving forward! Look forward to seeing the progress.

-- Set variables for Dummies
local Dummy_orig = workspace.Dummy0   -- model with changes to C1
local Dummy_new = workspace.Dummy1    -- update this one to same thing but with changes to C0

------------------------------------------
-- This part grabs all the motors in the Dummy_orig and moves the
-- C1 CFrames for each motor around a bit (to have something to test against)
local motors = {}
-- get a list of the motors in the Dummy_orig
for _,child in pairs(Dummy_orig:GetDescendants()) do
	if child:IsA("Motor6D") then
		table.insert(motors, child)
	end
end
-- and jumble the model up a bit
for i = 0, 10 do
	wait(.1)
	for _,motor in pairs(motors) do
		motor.C1 = motor.C1 * CFrame.Angles(math.rad(2),math.rad(0),math.rad(1))
	end
end
------------------------------------------

------------------------------------------
-- This last part makes Dummy_new match final pose of Dummy_orig 
-- by changing only C0s

-- Assumes dummys are built the same (although it should error if not)
for _,child in pairs(Dummy_orig:GetDescendants()) do
	if child:IsA("Motor6D") then
		-- Get all the position and rotation components for old C1:inv
		local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = child.C1:Inverse():GetComponents()
		
		-- Find the matching motor in the new Dummy
		local copyToMotor = Dummy_new:FindFirstChild(child.Name, true)
		assert(copyToMotor, child.Name.." could not be found")
		
		-- Create new C0 for Dummy_new using just rotation parts of old C1:inv
		x,y,z = copyToMotor.C0.Position.X, copyToMotor.C0.Position.Y, copyToMotor.C0.Position.Z -- not translating C0
		copyToMotor.C0 = CFrame.new(x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22)
	end
end