Raycast to pass through parts with transparency above 0

I want my raycast to work through parts with a transparency above 0 but to work normally with parts that don’t have any kind of transparency at all, how can I achieve this?

local function performRaycast(player)
	local character = player.Character
	if not character then
		return false
	end

	for _, targetPart in pairs(targetParts) do
		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		raycastParams.FilterDescendantsInstances = {player.Character}

		local raycastResult = workspace:Raycast(
			character.Head.Position,
			(targetPart.Position - character.Head.Position).unit * (targetPart.Position - character.Head.Position).magnitude,
			raycastParams
		)

		if raycastResult and raycastResult.Instance == targetPart then
			return true
		end
	end

	return false
end
1 Like

Raycasts take a FilterDescendantsInstances parameter that allows you to select/ignore certain parts for raycasting queries.

Since you’re already using Blacklist, which only queries parts inside the list, just add every Part you want to query that isn’t transparent to your blacklist:

-- No guarantee this will work, and also incredibly inefficient lol
local blacklist = {}
for _, part in pairs(workspace:GetDescendants()) do
  if part:IsA("Part") and part.CanQuery and part.Transparency == 0 then
    table.insert(blacklist, part)
  end
end
1 Like

Make a recursive function where if the raycast hits a part with Transparency > 0, it raycasts again but add the part to ignore list and start from the hit position.

local function recursiveRaycast(origin,target,raycastParams)
	raycastParams = raycastParams or RaycastParams.new() -- Incase none is provided

	local result = workspace:Raycast(origin,target-origin,raycastParams)
	if result then
		if result.Instance.Transparency > 0 then -- Condition to ignore part
			local filter = raycastParams.FilterDescendantsInstances
			table.insert(filter,result.Instance)
			raycastParams.FilterDescendantsInstances = filter
			return recursiveRaycast(result.Position,target,raycastParams) -- Raycast again from hit position
		end

		return result -- Did not ignore
	end

	return nil -- Nothing was hit
end

You need to pass the origin and the target position to the function. The RaycastParams is optional. You would use the function like this

local raycastResult = recursiveRaycast(
	character.Head.Position, -- Origin
	targetPart.Position, -- Target
	raycastParams -- RaycastParams
)

Btw, you can change the conditions in the if result.Instance.Transparency > 0 then line such as checking if material is Glass or both.

if result.Instance.Transparency > 0 and result.Instance.Material == Enum.Material.Glass then
3 Likes

Disable CanQuery in any transparent parts.

1 Like

but what if a transparent part in collidable?

1 Like

Don’t forget FilterType.

local function recursiveRaycast(origin: Vector3, target: Vector3, raycastParams: RaycastParams?)
	raycastParams = raycastParams or RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	
	local direction = (target - origin).Unit * (target - origin).Magnitude
	local result = workspace:Raycast(origin, direction, raycastParams)
	if result then
		if result.Instance.Transparency > 0 then
			local filter = raycastParams.FilterDescendantsInstances
			table.insert(filter,result.Instance)
			raycastParams.FilterDescendantsInstances = filter
			return recursiveRaycast(result.Position, target, raycastParams)
		end

		return result
	end

	return nil
end
1 Like

The FilterType is already set to Exclude by default that’s why I don’t set it to Exclude again.

print(RaycastParams.new().FilterType) -- Enum.RaycastFilterType.Exclude
1 Like

other than that, i slightly modified your code, notice the new “direction” variable?

I did not notice that. Why did you add that? That is the same as doing target - origin.

.Unit is taken by dividing the Vector by its magnitude. If you multiply it by its own magnitude, you basically canceled out the .Unit, making the Unit*Magnitude thing useless.

local direction = target - origin
local magnitude = direction.Magnitude -- The distance
local unit = direction.Unit -- Equal to direction / magnitude

local newDirection = unit * magnitude -- (direction / magnitude) * magnitude == direction