Ok, so to start off, what I am trying to do is find all of the parts in the 3d game world that a 2d UI Frame would theoretically contain based off of the camera's rotation, field of view, and such if the 2d UI Frame was given a 3d coordinate, and a depth-axis that extends back about 1000 studs.
The method I have coded to do so involves creating two rays at the upper and lower corners of the UI Frame, and creating a Region3
from there, and using the function Workspace:FindPartsInRegion3()
to get all of the parts that the UI Frame would theoretically contain if it were converted to a 3d Region3
with the conditions previously stated above.
Here is my code:
local function GetPartsInUI(ui) local cam = game.Workspace.CurrentCamera; local min_corner = ui.AbsolutePosition; local max_corner = ui.AbsolutePosition + ui.AbsoluteSize; local r1 = cam:ScreenPointToRay(min_corner.X, min_corner.Y, 5); local r2 = cam:ScreenPointToRay(max_corner.X, max_corner.Y, 5); local pos1 = CFrame.new(r1.Origin, (r1.Direction - r1.Origin).unit); local pos2 = CFrame.new(r2.Origin, (r2.Direction - r2.Origin).unit); pos1 = pos1 - (pos1.upVector * 999); --increase the imaginary depth axis by about 1000 studs local pos1_sum = pos1.p.X + pos1.p.Y + pos1.p.Z; local pos2_sum = pos2.p.X + pos2.p.Y + pos2.p.Z; local reg3 = Region3.new((function() local rt = {}; if pos1_sum > pos2_sum then rt[1] = pos2.p; rt[2] = pos1.p; else rt[1] = pos1.p; rt[2] = pos2.p; end return unpack(rt); end)()); local parts = game.Workspace:FindPartsInRegion3(reg3, nil, math.huge); return parts; end
My problem is that half of the time the parts inside of the UI Frame are not recognized to be inside of the Region3.
I am assuming that this is either due to my setting up of the position (pos1 and pos2) variables, or an issue with the rays returned from the :ScreenPointToRay()
function.
With all of that being said, please tell me what am I doing wrong, and how can I improve upon this???
Thanks
The first problem is that the view of a camera's in Roblox is not represented by a square/rectangle, but rather by a square viewing frustum.
The second problem is that region3's are 1) squares/rectangles, 2) cannot be rotated, and 3) have limitations on their size.
We are somewhat lucky when it comes to the frustum because Roblox actually gives us most of the tools we need to do this without getting into the math.
local draw = require(game.Workspace.draw); -- just a module I made for drawing stuff local camera = game.Workspace.CurrentCamera; local vps = camera.ViewportSize; -- could adjust these as the corners for your UI local r0 = camera:ViewportPointToRay(0, 0); local r1 = camera:ViewportPointToRay(0, vps.y); local r2 = camera:ViewportPointToRay(vps.x, vps.y); local r3 = camera:ViewportPointToRay(vps.x, 0); for k, v in next, {r0, r1, r2, r3} do -- this function just draws a ray draw.ray(v.Origin, v.Direction*10, game.Workspace); end;
In the above we can see the frustum from our camera's view port.
Now that you know the shape and have data on it you can use something like SAT or GJK collision detection to see if a part is within the frustum. However, my recommendation if you go this route is to first use a broad region3 to lower the amount of parts you have to test.
Good luck!