Ledge Climbing help

I’ve made a ledge climbing system and it worked perfectly fine up until i placed it in my actual map and found this annoying issue that im hoping to get fixed today…

See the ledge system works off of raycasts as most do, and in some parts of the map I have grass parts ontop of hills that are thin, the raycast picks them up instead of the hill part.

is there any way i can make the raycast ignore those parts without having to go through them 1 by 1 and group them?

Code Snippet:

local function partCheck(ledge, raycastParams)
	local vaultPartCheck = workspace:Raycast(ledge.Position + Vector3.new(0, -1, 0) + ledge.LookVector * 1, ledge.UpVector * 3, raycastParams)
	if vaultPartCheck == nil then
		return true
	else
		return false
	end
end


-->> Ray
	  local head = Character.Head
		
		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Exclude
		raycastParams.FilterDescendantsInstances = {Character:GetDescendants(), workspace.Zones:GetDescendants(), workspace.Players:GetDescendants(), workspace.NPCs:GetDescendants()}
		
		local vaultCheck = workspace:Raycast(HRP.CFrame.Position, HRP.CFrame.LookVector * 5, raycastParams)
		if vaultCheck then
			local localPos = vaultCheck.Instance.CFrame:PointToObjectSpace(vaultCheck.Position)
			local localLedgePos = Vector3.new(localPos.X, vaultCheck.Instance.Size.Y/2, localPos.Z)
			
			local ledgePos = vaultCheck.Instance.CFrame:PointToWorldSpace(localLedgePos)
			local ledgeOffset = CFrame.lookAt(ledgePos, ledgePos - vaultCheck.Normal)
			
			local magnitude = (ledgePos - head.Position).Magnitude
			if magnitude < 3 then
				if partCheck(ledgeOffset, raycastParams) then
					camShake:Start()
					warn("can climb, ", vaultCheck.Instance.Name)
					CreateTag("Accessory", "Stun", Character, 0.1)
					climbanim:Play()

					local Vele = Instance.new("BodyVelocity",HRP)
					Vele.MaxForce = Vector3.new(1,1,1) * math.huge 
					Vele.Velocity = HRP.CFrame.LookVector * 10 + Vector3.new(0,30,0) 
					game.Debris:AddItem(Vele,.15) 
				end
			end
		end

For the exclusion list in raycastParams, you can add your grass parts to it. To identify grass parts, simply loop through all of the workspace descendants and check if they have grass part properties, such as material, color, and name. Then if a descendant matches the properties, add them to the exclusion list. Your code needs to be modified a bit like so:

local exclusionList = {Character:GetDescendants(), workspace.Zones:GetDescendants(), workspace.Players:GetDescendants(), workspace.NPCs:GetDescendants()}

-- This is an example, you have to modify this to properly identify grass parts and make sure wrong descendants are not used
for _, descendant in workspace:GetDescendants() do
    if descendant.Name == "Grass" and descendant:IsA("BasePart") then
        table.insert(exclusionList, descendant)
    end
end

local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = exclusionList