I’m trying to make a script based on converting character limb CFrames from workspace to CFrame poses in an animation.
Right now, I’m having trouble getting the formula for converting the CFrame into the correct place in the animation, because if I just set the pose .CFrame to the CFrame I want, it doesn’t display the poses in workspace properly. If I could get help finding the correct formula for the script that would be appreciated,
-- This is what I have to far:
-- The array is sorted like {Head.CFrame, LeftArm.CFrame, RightArm.CFrame, Torso.CFrame, LeftLeg.CFrame, RightLeg.CFrame}
for keyframeindex, arrayofcframes in ipairs(keyframes) do
local keyframeindexmodel = folder:FindFirstChild(keyframeindex)
local keyframe = Instance.new("Keyframe")
keyframe.Time = animationtime
keyframe.Name = tostring(keyframeindex)
local rootPose = Instance.new("Pose")
rootPose.Name = "HumanoidRootPart"
rootPose.Weight = 0
keyframeSequence:AddKeyframe(keyframe)
keyframe:AddPose(rootPose)
local torsopart = keyframeindexmodel:FindFirstChild("Torso")
local torsopose = Instance.new("Pose")
torsopose.Name = torsopart.Name
torsopose.Weight = 1
torsopose.CFrame = arrayofcframes[4] --need help with this line
rootPose:AddSubPose(torsopose)
for arrayindex, cframe in ipairs(arrayofcframes) do
if cframe ~= nil then
local bodypart = keyframeindexmodel:FindFirstChild(bodyparts[arrayindex][2])
if bodypart.Name ~= "Torso" then
local pose = Instance.new("Pose")
pose.Name = bodypart.Name
pose.Weight = 1
local joint = getJointBetween(keyframeindexmodel:FindFirstChild("Torso"), bodypart)
pose.CFrame *= joint.Transform:Inverse() * joint.C1:Inverse() --and this line
rootPose:AddSubPose(pose)
end
end
end
animationtime += .016
end
return keyframeSequence
end
I don’t fully understand your problem statement, can you draw like a diagram of what CFrame you’re trying to convert and what the result should be relative to?
For solving into object space like for Motor6D C0 here is an example from my tutorial. The point from the link is that you would need to apply the :Inverses in a specific order to get the solution. Consequently, you should probably write the equation and try experimenting with it for poses instead of Motor6D C0 perhaps.
PartParent.CFrame * CParent * Transform == PartChild.CFrame * Child
--Is equivalent to:
--If Part0 is closest to the root part
Part0.CFrame * C0 * motor.Transform = part1.CFrame * C1
Now that it is clear that Animation editor modifies the .Transform values
we can solve for the .Transform
Part0.CFrame * C0 * motor.Transform = part1.CFrame * C1
--Inverse Part0 left side
C0 * motor.Transform = Part0.CFrame:Inverse()*part1.CFrame * C1
--Inverse the C0 leftside
motor.Transform = C0:Inverse()*Part0.CFrame:Inverse()*part1.CFrame * C1
--Since we want to modify the Part1 CFrame, which is the part that is moving. (example right arm for the right shoulder motor6d)
motor.Transform = C0:Inverse()*Part0.CFrame:Inverse()*someCFrameWeWant * C1
Turning it into a function with an example script:
local leftShoulder = script.Parent
local head = workspace.R6Dummy.Head
local function solveForTransform(desiredCF, motor : Motor6D)
local C0 = motor.C0
local Part0 = motor.Part0
local C1 = motor.C1
return C0:Inverse()*Part0.CFrame:Inverse()*desiredCF * C1
end
local goalTransform = solveForTransform(head.CFrame, leftShoulder)
local x,y,z = goalTransform:ToOrientation()
print(goalTransform.Position, math.deg(x),math.deg(y), math.deg(z))
So if we want the animation values to go to the head position of this R6 head, the function will output the values.
I believe you are using R6, R6 is weirder as the Motor6Ds have rotation.
Try this:
local function solveForTransform(desiredCF, motor : Motor6D)
local C0 = motor.C0
local Part0 = motor.Part0
local C1 = motor.C1
return C0:Inverse()*Part0.CFrame:Inverse() * desiredCF * C1:Inverse()
end
The edit makes the r6 rig not work as intended, no :Inverse() on the C1 seemed to work.
The only problem is that the torso position is offset from the position it needs to be.
The character starts around the spawn point, but the animation is offset to the right.
Alright, so essentially the animation is supposed to start when the timer hits 0, allowing for the script to start recording the players movements.
The first frame of the players’ movements was supposed to be around the spawn location, but was offset in the animation to the right. I need the character in the animation to be located at the same location as the players movements in the workspace, if that makes sense. Place file (2.3 MB)
However to make coding a bit easier the animation dummy should be set to 0,0,0 in workspace, then we can work from there (made an edit to the place file to set the animation dummy to 0,0,0).
The issue is not the CFrame function it is collisions.
Using collision groups seem to work and they end up overlapping and to me it seems to work as intended.
Code
--Set for dummy clones
for i,v : BasePart in pairs(dummyclone:GetDescendants()) do
if v:IsA("BasePart") then
v.CollisionGroup = "Dummy"
end
end
--Server script to create collision group
local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")
PhysicsService:RegisterCollisionGroup("Characters")
PhysicsService:CollisionGroupSetCollidable("Characters", "Characters", false)
PhysicsService:RegisterCollisionGroup("Dummy")
PhysicsService:CollisionGroupSetCollidable("Dummy", "Characters", false)
local function onDescendantAdded(descendant)
-- Set collision group for any part descendant
if descendant:IsA("BasePart") then
descendant.CollisionGroup = "Characters"
end
end
local function onCharacterAdded(character)
-- Process existing and new descendants for physics setup
for _, descendant in pairs(character:GetDescendants()) do
onDescendantAdded(descendant)
end
character.DescendantAdded:Connect(onDescendantAdded)
end
Players.PlayerAdded:Connect(function(player)
-- Detect when the player's character is added
player.CharacterAdded:Connect(onCharacterAdded)
end)
Also maybe the .Stepped loop setting can collide to false did the job, but I assume it’s the collision groups that made it work and record more accurately.