Thanks for the help guys, after a little bit of testing I was able to find that WorldToScreenPoint is basically faster than any other method even if I don’t utilize half the things it returns. In contrast I tried this function to see what was more efficient and it was actually 0.00002 seconds slower under every condition (which I thought was weird because GetPartsObscuringTarget is supposed to be better than raycasting)

```
local ignorelist = {workspace.CurrentCamera,workspace.Vis}
function CFrameVisible(CF,Ignore)
local AspectRatio = workspace.CurrentCamera.ViewportSize.X/workspace.CurrentCamera.ViewportSize.Y
local vFOV,hFOV = workspace.CurrentCamera.FieldOfView,math.floor(workspace.CurrentCamera.FieldOfView*AspectRatio)
if ((workspace.CurrentCamera.CFrame+workspace.CurrentCamera.CFrame.LookVector).p-CF.p).Magnitude < (workspace.CurrentCamera.CFrame.p-CF.p).Magnitude then
local TargetCF = CFrame.new(workspace.CurrentCamera.CFrame.p,CF.p)
local offset = workspace.CurrentCamera.CFrame:ToObjectSpace(TargetCF)
local x,y,z = offset:ToEulerAnglesXYZ()
if math.abs(math.deg(y)) > hFOV/2 or math.abs(math.deg(x)) > vFOV/2 then
return false
else
local ilist = ignorelist
if Ignore ~= nil then ilist = Ignore end
local parts = workspace.CurrentCamera:GetPartsObscuringTarget({CF.p}, ilist)
if #parts <= 0 then
return true
elseif #parts >= 10 then
return false
elseif #parts < 10 then
local result = true
for i,v in pairs(parts) do
if v.CanCollide == true and v.Transparency <= 0.2 and (v.ClassName ~= "MeshPart" or v.CollisionFidelity == Enum.CollisionFidelity.Default) and (v.ClassName ~= "UnionOperation" or v.CollisionFidelity == Enum.CollisionFidelity.Default) then
result = false
break
end
end
return result
end
end
else
--Is behind them
return false
end
end
```