How to get all parts player can see?

Before you answer, YES I am aware I can use WorldToViewportPoint, but this doesn’t solve the issue, as this still returns parts that, even though are within the bounds of the camera, are occluded. I want to return all parts the players camera can see, but only the parts they can actually see with their eyes, not parts behind those. And no I couldn’t just raycast to each part visible because the corner of a part could be visible, but the center occluded

I’ve tried lots of things including raycasts but my math is horrible, and I can’t figure out a way to raycast the entire screen.

If anyone has any ideas it would be greatly appreciated. Thanks!

Roblox doesn’t have a method that gives that much detail. Your ideas are the closest I can think of to doing it in a performant method. Out of curiosity though why do you need it? Maybe there is a way to fake it with a good enough accuracy for your use case relatively cheaply?

if he doesn’t have too many parts, he could add a proximity prompt to every model/part and have RequiresLineOfSight toggled true. Or maybe lidar sensor it

The player is in a room, and gets teleported seamlessly to another room without them noticing a change. But in order to do that, I need to make sure they aren’t looking or seeing the part of another room.

Ohhh noo definitely not. Are there any LIDAR sources though?

Sort of a goofy idea that may lead nowhere, but considering that its possible for you to find the vertices of every part, perhaps try getting the 2D projection of the parts, and then seeing if the parts you want to check are completely covered? I’m not exactly sure how this would work, but theres definitely ways to check if 2D things are covered and ways to find the vertices of 3D objects in roblox. (Though im not sure if its possible to reconstruct the 2d projections in the correct order. You could probably use their distance to the player to decide on what goes on top.)

edit: actually, im not sure if its possible to get all vertex (and even if it is, its still assuming that all objects are shapes that have vertices lol)

Working under the assumption this is cell based (or simple shapes) you can fairly easily solve for it geometrically. Consider it a 2D projection with 2 lines representing the camera.

Then start at the left edge of the camera and solve for the wall it would hit, now just go to the edge of the wall and keep solving the edge over and over until you intersect the right side. Now every edge is your answer.

It’s a bit involved, but should net you the answer you want.

it could be comming soon as this is related to occulusion culling? maybe make a feature request for now

Just an idea but try using the dot product between a players head or camera and smth else to get started

You can determine how to make the script understand whether the player is looking at a certain part in the world or not.

You have to make hitboxes, and make a function that whether the player is looking at a certain hitbox. For example, place this hitbox against a wall, and if the player sees this hitbox, then he is looking at the wall and not at another part of the map.

And make a teleport function, after the hitbox is in sight.

((to determine if there is a hitbox on the screen or not, use this)))

local Angle = 0.7 -- change to increase (smaller number, min = -1) or decrease (bigger number, max = 1)

local unit = ((workspace.Part.Position - Character.Head.Position) * Vector3.new(1,0,1)).Unit
local HeadLookVec = Character.Head.CFrame.LookVector * Vector3.new(1,0,1)
local IsFacing = HeadLookVec:Dot(unit) > Angle

if IsFacing then
	print(IsFacing)
end

If the script doesn’t work or doesn’t fit, try this

local Workspace = game:GetService(“Workspace”)
local RunService = game:GetService(“RunService”)

local Part = game.Workspace:WaitForChild(“your part”)
local Camera = Workspace.CurrentCamera
local MaxDistance = 50

RunService.RenderStepped:Connect(function()
	local Vector, IsVisible = Camera:WorldToScreenPoint(Part.Position)
	if IsVisible and Vector.Z <= MaxDistance then
		local cameraPosition = Camera.CFrame.Position
		local direction = (Part.Position - cameraPosition).Unit * MaxDistance
		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {Camera, script.Parent}
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

		local raycastResult = Workspace:Raycast(cameraPosition, direction, raycastParams)

		if raycastResult then
			if raycastResult.Instance == Part then
				print(“facing Part”)
			else
				print(“object obstructs view”)
			end
		else
			print(“no parts in the path”)
		end
	end
end)

Why don’t you get the corners of the camera (red lines) and make a cone shaped part (green lines) and use workspace:GetPartsInPart() to get all parts that are in the green part.
this way you will also get the parts that are partially visible too like the blue one here.
Untitled

this is how i do it in my viewfinder game and it works great. additionally you can add overlapParams to only look for specific parts.

I can make a small test place for you if you want.

3 Likes

Pick a spot that isn’t possible.

I think this is a good Idea, but wouldn’t this also detect parts that are occluded?

So have a bunch of ray casts across the FOV?

Camera:GetPartsObscuringTarget()

You can teleport the player if this returns anything but nil, make castPoints the position of invisible parts in the center of each adjacent room

I found a temporarily solution, but it’s quite hacky and I don’t know how much I like it. Basically, I get the dot product of the center of each node relative to the players camera. If they’re looking generally in the center of the current node their in, then I teleport them, as there’s no way they could he looking at other nodes if they’re already looking forwards the center