Attempting to modify a custom characters bone structure while keeping animations the same

The animations I was given to work with had the bone structure incorrectly set up, resulting in some slightly messed up animations when combining multiple at once. (A sword swing while walking)

Our animator isn’t available to fix it and I decided I’d try and figure out the math to fix it myself. Turns out it’s a bit harder then I thought. After writing everything up I realized CFrames were a lot more complicated then I thought.

I figured out they aren’t communitive.

I can almost explain what each of the elements in the CFrame represent, I can do the math to combine them, and I understand combining them is assuming the 1st CFrame is effectively the new world origin that the 2nd CFrame traverses through.

It’s still just a bit to complicated to wrap my head around I’m struggling to fix the issues with my code. I keep trying to simplify it in my head, but when I do I lose the necessary complexity added by rotation.

FixPoseRecursive = function(OldPose, NewPose, NewModelNode, NewParentHRPOffset)
	NewParentHRPOffset = NewParentHRPOffset and NewParentHRPOffset or CFrame.new()
	
	local OldModelNode = NewModelNode.Link
	
	--| Get CFrame in HRP's Space of the Object in the OldPose
	
	local TotalOffset = CFrame.new()
	local Current = OldModelNode
	
	--| Head up through the ancestors calculating total offset as you go
	while Current.Parent do
		local Bone = Current.Motor6D
		local OldPoseLink = OldPose:FindFirstChild(Current.Value.Name, true)
		
		TotalOffset = TotalOffset * Bone.C0 * OldPoseLink.CFrame * Bone.C1:Inverse()
		
		Current = Current.Parent
	end
	
	local HumanoidRootPartOffset = TotalOffset
	
	--| Find HRP Offset needed for the NewPose Object to equal the old pose HRP offset
	
	local ObjectOffset = NewParentHRPOffset * NewModelNode.Motor6D.C0 * NewModelNode.Motor6D.C1:Inverse()
	local OffsetDifference = ObjectOffset:Inverse() * TotalOffset
	
	--| Set the new pose's value
	CopyPoseInfo(OldPose:FindFirstChild(NewPose.Name, true), NewPose)
	NewPose.CFrame = OffsetDifference
	
	
	--| Handle Children
	
	for _, Child in ipairs(NewPose:GetChildren()) do
		FixPoseRecursive(OldPose, Child, NewModelNode.Children[Child.Name], TotalOffset)
	end
end

Perameters

  1. OldPose is always the HRP Pose for the old bone structure
  2. NewPose is a ChildPose of the New Structure set up previously, It’s recursively searched depth first.
  3. New Model Node was a Tree ADT I set up, It’s structure is identical to the Fixed Pose’s structure, just has useful links to motor6Ds and the old model’s structure.
  4. NewParentHRPOffset Is the offset I calculated in the previous step, It’s not calculated correctly but it’s intended to be the Parent’s - (In terms of the bone structure); HRP offset for the current keyframe.
    HRP is humanoid root part

Just calculating the OldHRPOffset for a direct child of the HRP results is a offset that is off by a bit (About most 0.005) I assume this is just precision lost from complex math, I don’t see how there can be an error at that stage but I’m not sure.

Here’s what it looks like:

Here’s what it’s supposed to look like:

I’d be faster at this point to just go into blender and learn how to re-wire the bones myself, I’ve seen it’s doable there. I’m just so far in I have to finish it this way, I plan to give this out as a community resource once it’s fixed.

2 Likes

Managed to solve it, I was doing the CFrame math wrong in a lot of places, mainly ordering issues, I ended up learning how matrix multiplication and algebra worked in order to find it.

There are some aparent rounding errors, 6 bones deep at 0.001 studs off I’m a bit worried about, but for now it’s good enough here’s the resource:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.