How would I align a part to surface normal using 4 points/raycasts?

I have a part with a BodyGyro and I want to be able to align it to a raycast surface normal. I normally know how to do this, but for extra accuracy I want it to be done with 4 raycasts on the corners of the part. How could this be achieved? I have seen people do this with 1-3 raycasts but never 4.

I may not fully understand what you’re needing here, but couldn’t you just take the average of all of the surface normals that the raycasts collided with?

local average_normal = (normal1 + normal2 + normal3 + normal4) / 4
-- The following code assumes that you've already defined your part and BodyGyro.
-- If not, you would need to set those up.

local part = game.Workspace.Part -- Substitute with your actual part
local bodyGyro = Instance.new("BodyGyro")
bodyGyro.Parent = part

-- These values should be adjusted based on the size and shape of your part
local raycastDist = 10 
local raycastOrigins = {
    Vector3.new(-0.5, 0, 0.5),
    Vector3.new(0.5, 0, 0.5),
    Vector3.new(-0.5, 0, -0.5),
    Vector3.new(0.5, 0, -0.5)
}

-- Store the World Root workspace
local workspace = game:GetService("Workspace")

-- Use the new Raycast API
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = {part} -- Ignore the part you're aligning

local function alignPartToSurface()
    local normals = {}

    for _, origin in pairs(raycastOrigins) do
        local worldOrigin = part.CFrame:PointToWorldSpace(origin)
        local direction = Vector3.new(0, -raycastDist, 0)
        local raycastResult = workspace:Raycast(worldOrigin, direction, raycastParams)

        if raycastResult then
            table.insert(normals, raycastResult.Normal)
        end
    end

    -- Check if there were valid hits
    if #normals > 0 then
        -- Average normals
        local normal = Vector3.new(0, 0, 0)
        for _, n in pairs(normals) do
            normal += n
        end
        normal = normal / #normals

        -- Align to averaged normal
        local primaryAxis = Vector3.new(0, 1, 0)
        bodyGyro.CFrame = CFrame.new(part.Position) * CFrame.lookAt(part.Position, part.Position + normal, primaryAxis)
    end
end

-- Run this function every frame
game:GetService("RunService").Heartbeat:Connect(alignPartToSurface)

This script calculates the world space origin for each ray cast based on the current CFrame of the part, then fires the raycasts downward. you will be firing the raycasts from each of the four corners of your object, colliding with the terrain, and using the average of the normal vectors of each collision point to calculate the orientation for your BodyGyro.

Doesn’t seem to work for me whatsoever

Okay, I managed to fix it. Thank you very much!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.