You have a start and target upvector:
local start = part.CFrame.UpVector
local target = Vector3.new(1, 1, 1).Unit
You can do this in a single rotation about an axis. The axis is perpendicular to both:
local axis = start:Cross(target)
And figure out the angle between the two
local angle = math.acos(start:Dot(target))
Then just rotate the CFrame by that amount
part.CFrame = CFrame.fromAxisAngle(axis, angle) * part.CFrame.Rotation + part.CFrame.Position
I’ll do some testing to check, but I’m pretty sure that would work. Ignoring cases like full 180 degree rotations or 0 degree rotations, for which you’ll have to write special cases.
Edit: left out one part, gimme a sec Fixed. Final function:
local function AlignUpVector(cframe: CFrame, up: Vector3)
local start = cframe.UpVector
local angle = math.acos(start:Dot(up))
local axis = nil
if angle < 0.00001 or angle > math.pi - 0.00001 then
axis = Vector3.xAxis
else
axis = start:Cross(up)
end
return CFrame.fromAxisAngle(axis, angle) * cframe.Rotation + cframe.Position
end
Example use:
local target = Vector3.new(1, 1, 1).Unit
part.CFrame = AlignUpVector(part.CFrame, target)
Edit: Modified function to take into account special cases