i realised the same thing, and testing it, i found that you would lose such a tilt.
so i went and created the “Correction factor”, which works as follows:
you perform vector3.dot()
on the normal and RightVector.
you multiply this value by 90 - this gets you how much rotation you need to apply before tilting with FromMatrix. (this value is in degrees btw.)
You take your part’s cframe, rotate it on the y-axis by that value using cframe.angles()
and get a rotated cframe.
you then use this rotated cframe’s vector properties to create a new CFrame.FromMatrix()
finally, you rotate that matrix cframe by the rotation angle multiplied by -1, to get rid of this ultimately unwanted rotation.
here’s my code:
part = script.Parent
params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {part}
while true do
task.wait()
result = workspace:Raycast(part.Position, (part.CFrame.LookVector * 5) + (Vector3.yAxis * -200))
if result then
StartingCFrame = part.CFrame
local FinalFrame:CFrame
determiner = part.CFrame.RightVector:Dot(result.Normal)
RotationAngle = 90 * math.abs(determiner) -- our correction angle
StartingCFrame *= CFrame.Angles(0,math.rad(RotationAngle),0) -- rotated starting CFrame
MidFrame = CFrame.fromMatrix(
StartingCFrame.Position,
StartingCFrame.RightVector,
result.Normal,
result.Normal:Cross(StartingCFrame.RightVector).Unit * -1
) -- aligned CFrame, with incorrect rotation
FinalFrame = MidFrame * CFrame.Angles(0,math.rad(RotationAngle * -1),0) -- restores our initial rotation in respect to the slope.
part.CFrame = FinalFrame -- applies this final matrix to the part (rather than applying at each calculation)
end
end
This should give accurate, albeit more approximate tilt, which works with most situations.
Hope this clears things up! this topic was of great help to my game.