Aligning Object to Surface using CFrame:fromMatrix()

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.

7 Likes