Ray Intersection + Surface Normal

so I am making a wall climb system based off of this guys advice:

and what I am wondering is how i can get the “Surface Normal” of a part, and how to get the Intersection point of a ray? this is my attempt and it moved me backwards diagonally to the right

``````		local Root = Character:WaitForChild("HumanoidRootPart")
local WallRay = Ray.new(Root.Position, Vector3.new(0,0,5))

local hit,pos = workspace:FindPartOnRayWithIgnoreList(WallRay,ignorelist, false, true)

if hit then
if hit == Character:GetChildren() then return end
print(hit.Name)

local hitpart = Instance.new("Part")
hitpart.Position = hit.Position
print(hitpart.Position)

local teleportpart= Instance.new("Part")
teleportpart.Position = hit.Position - Root.Position
Humanoid:MoveTo(teleportpart.Position)

end
``````

TDLR; whats the formula to getting a rays intersection point and “Surface normal”

when i tried that i got the same result? am i being stupid?

``````		local Root = Character:WaitForChild("HumanoidRootPart")
local WallRay = Ray.new(Root.Position, Vector3.new(0,0,5))
local ignorelist = {workspace.Baseplate,Root}

local hit,pos,normal = workspace:FindPartOnRayWithIgnoreList(WallRay,ignorelist, false, true)

if hit then
if hit == Character:GetChildren() then return end
print(hit.Name)

local hitpart = Instance.new("Part")
hitpart.Position = hit.Position
print(hitpart.Position)

local teleportpart= Instance.new("Part")
teleportpart.Position = normal
Humanoid:MoveTo(teleportpart.Position)

end
``````

edit: i had my ray going backwards let me test now

edit2: nope… now nothing is happening; full code

``````local UIS = game:GetService("UserInputService")
local Players = game:GetService("Players")

local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")

local module = {}

UIS.InputBegan:Connect(function(Input,GPE)
if Input.KeyCode == Enum.KeyCode.Space then
if GPE then return end
local Root = Character:WaitForChild("HumanoidRootPart")
local WallRay = Ray.new(Root.Position, Vector3.new(0,0,-5))
local ignorelist = {workspace.Baseplate,Root}

local hit,pos,normal = workspace:FindPartOnRayWithIgnoreList(WallRay,ignorelist, false, true)

if hit then
if hit == Character:GetChildren() then return end
print(hit.Name)

local hitpart = Instance.new("Part")
hitpart.Position = hit.Position
print(hitpart.Position)

local teleportpart= Instance.new("Part")
teleportpart.Position = normal
Humanoid:MoveTo(teleportpart.Position)

end
end
end)

return module
``````

Something I’d noticed looking at your code, you’re comparing `hit` (an object) to `Character:GetChildren()` (an array). Perhaps you meant to use the `IsDescendantOf` method? The method returns a bool whether it’s a descendant within a parent.

``````print(game.Workspace.Folder.Part:IsDescendantOf(game.Workspace)) -- true
``````

Please lemme know if you have any questions. I hope this helped.

EDIT
Misread the code, oops. I thought it was because of the if statement that it wasn’t executing.

didnt change anything but thanks for the help

1 Like

I created an entirely new script that uses the newer, more recommended version of raycasting: `workspace:Raycast()`.

You never know when they’ll depreciate it, so it’s better to be safe.

Some context:

Part = what the ray will hit
Mover = the representation of where the ray hits
RayPart = new part to visualize the ray

``````local part = script.Parent
local rayP = RaycastParams.new() --used to set the interaction of the ray, sort of like the ignore list
rayP.FilterDescendantsInstances = {workspace} --ray will collide with any part in workspace
rayP.FilterType = Enum.RaycastFilterType.Whitelist --whitelist the above, only hit the ones we specificed, not all expect itself

local origin = Vector3.new(0, 15, 30) --create a ray somewhere
local direction = (part.Position - origin) * 50 --I just pointed it towards the part just for the current purposes

local rayResult = workspace:Raycast(origin, direction, rayP) --create a ray and get the result

local function cframe(pos, lookVector) --a function to set the cframe of a part

local modelUpVec = Vector3.new(0, 1, 0)
local rightVec = lookVector:Cross(modelUpVec)
local upVec = rightVec:Cross(lookVector)

return CFrame.fromMatrix(pos, rightVec, upVec) --this is replacing CFrame.new(pos, lookAt)

end

--visualize the ray
local dist = (rayResult.Position - origin).Magnitude
local rayPart = Instance.new("Part")
rayPart.Anchored = true
rayPart.CFrame = cframe((direction - origin) / 2, direction)
rayPart.Material = "Neon"
rayPart.Size = Vector3.new(0.1, 0.1, dist)
rayPart.CFrame = cframe(origin, rayResult.Position - origin) * CFrame.new(0, 0, -dist / 2) --make it go along the ray
rayPart.Parent = part

part.Mover.CFrame = cframe(rayResult.Position, direction) --put this part at the position of intersection
print(rayResult.Normal) --print the vector of normal it hit, aka, in whcih direction is the normal facing
``````

Now, put this in action:

The blue part is Mover. Now you can see that the ray just about hits the top normal, which I kept it facing straight up. Look at the output:

``````0, 1, 0 --a vector going up, which is right!
``````

Here is the file with the parts and script if you want to find out more:

RayCasting.rbxm (5.1 KB)

Hope that helps! If you have any questions, feel free to ask!

2 Likes

well what can i do with this relating to my questions

edit: so i want to set the primary part cframe to the blue part?

edit2: what should i do with direction to make it cast forward? (like im not gonna have this in a part, its inside a module of controls, so what do i need to do with the direction math to make the ray cast forwards from the root part

edit3: error;

edit4: thats me rushing it cause script.parent is a modulescript so disregard edit3