Ray Terrain Rotation Not Working

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.
image
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.

1 Like

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
4 Likes

This worked amazingly. Thank you.