So given two attachments, how do I find the angle of twist between them similar to a ball socket constraint using CFrames:
I know for the UpperAngle it’s dependent on the attachments world axis between the joint and the axis attachment and hence I can enforce a CFrame based constraint like so:
UpperAngle constraint
local centerAxis = axisAttachment.WorldAxis
local currentCenterAxis = jointAttachment.WorldAxis
local angleDifference = VectorUtil.AngleBetween(currentCenterAxis,centerAxis)
local constraintUpperAngle = math.rad(jointConstraintInfo.UpperAngle) or math.rad(45)
--out of bounds constrain it to world axis of the socket
if angleDifference > constraintUpperAngle then
local axis = currentCenterAxis:Cross(centerAxis)
local angleDifference = angleDifference-constraintUpperAngle
local newCenterAxisWithinBounds = rotateVectorAround( currentCenterAxis, angleDifference, axis )
self.rotateJointFromTo(motor6d,currentCenterAxis,newCenterAxisWithinBounds,part0CF.RightVector)
end
Now I’m completely stumped about how to find the TwistUpperAngle and TwistLowerAngle, I’ve tried using swing twist decomposition but tbh I don’t really understand if the angle I’m getting is the same and it doesn’t work for limiting the movement of the Motor6D part1 leg.
Failed attempt
--local twistAxis = axisAttachment.WorldSecondaryAxis
local twistAxis = jointAttachment.WorldAxis
local axisCFrame = axisAttachment.WorldCFrame
local jointCFrame = jointAttachment.WorldCFrame
local jointRelativeToAxis = axisCFrame:ToObjectSpace(jointCFrame)
local function swingTwist(cf, direction)
local axis, theta = cf:ToAxisAngle()
-- convert to quaternion
local w, v = math.cos(theta/2), math.sin(theta/2)*axis
-- (v . d)*d, plug into CFrame quaternion constructor with w it will solve rest for us
local proj = v:Dot(direction)*direction
local twist = CFrame.new(0, 0, 0, proj.x, proj.y, proj.z, w)
-- cf = swing * twist, thus...
local swing = cf * twist:Inverse()
return swing, twist
end
local swing,twist = swingTwist(jointRelativeToAxis,twistAxis)
local x,y,z = twist:ToEulerAnglesXYZ()
--print(math.round(math.deg(x)),math.round(math.deg(y)),math.round(math.deg(z)))-- it's the y axis?
local constrainedX = math.clamp(math.deg(x),-45,45)
local newTwistCF = CFrame.fromEulerAnglesXYZ(constrainedX,y,z)
local newJointCFrameRelativeToWorld = axisCFrame*swing*newTwistCF
--Translate jointCFrame to part1 CFrame
local newPart1CFrame = newJointCFrameRelativeToWorld*jointAttachment.CFrame:Inverse() -- Uhh only works with attachments
local goalCFRotation = motor6d.Part0.CFrame:Inverse()*newPart1CFrame
goalCFRotation = goalCFRotation-goalCFRotation.Position
So anyone has any idea how the TwistLimits in the ball socket constraint work? What axis of the attachments is the limits based on?