So I’ve been experimenting with raycasting and tried to make a mushroom placement script, where there would be a mushroom that shoots a ray straight down and detects if there’s terrain under it.
When I do this, it works fine, but the rotation is way off.

Script:

local mushClone = game:GetService("ServerStorage"):WaitForChild("Place"):Clone()
mushClone.Position = Vector3.new(math.random(-265, 265), math.random(50, 270), math.random(-265, 265))
local RayCast = Ray.new(mushClone.Position, mushClone.CFrame.UpVector * -500)
local hit, pos, norm = workspace:FindPartOnRay(RayCast)
if hit and pos and norm then
mushClone.CFrame = CFrame.new(pos + (mushClone.CFrame.UpVector * 2.8), pos + norm)
mushClone.Parent = workspace
end

I’ve also tried multiplying pos by norm, but it still is off.
Any help would be greatly appreciated.

Let’s see. You wish to set the UpVector for the mushroom to be the Normalized Vector from the Raycasting result. The way to do it that I will present you now is the one used in this post.

A CFrame contains four vectors; The position, lookvector, upvector and rightvector. The directional vectors are all Unit Vectors (Vectors with a magnitude/length of 1) pointing in a direction perpendicular (90 degrees) to the other two vectors.

Because they are perpendicular you can get the other two vectors from a base lookvector and a upvector. To do this you would get the cross product of the vectors Vector3:Cross(Vector3) -- Returns Vector3 that is perpendicular to the two used

However, this new Vector3 that is returned is not a unit vector, but using Vector3.Unit gets that done for us.

So with these two functions in mind we can construct a Right Vector that is perpendicular to the original Look Vector and the new Up Vector, and then construct a new Look Vector that is perpendicular to the new Right Vector and the new Up Vector.

local UpVector = NewUpVectorHere
local RightVector = OldLookVectorHere:Cross(UpVector).Unit
local LookVector = RightVector:Cross(UpVector).Unit

With these three values you can use the CFrame.fromMatrix(Position, LookVector, UpVector, RightVector)

if hit and pos and norm then
-- norm = UpVector
local RightVector = norm:Cross(mushClone.CFrame.LookVector).Unit
local LookVector = norm:Cross(RightVector).Unit
mushClone.CFrame = CFrame.fromMatrix(pos + (mushClone.CFrame.UpVector * 2.8), LookVector, norm, RightVector)
mushClone.Parent = workspace
end