Converting 3D position into 2D screen position

So first I am aware that these functions exist

I am making this as a learning experience

local Camera = workspace.CurrentCamera
local Frame = script.Parent

while true do
	local ViewportSize = Camera.ViewportSize
	local AspectRatio = ViewportSize.X/ViewportSize.Y
	local VerticalFoV = math.rad(Camera.FieldOfView)
	local HorizontalFoV = 2*math.atan( math.tan(VerticalFoV/2) * AspectRatio )
	local RelativePosition = Camera.CFrame:Inverse() * workspace.Part.Position
	local Opp = RelativePosition.Y
	local Adj = RelativePosition.Z
	local VerticalAngle = math.atan(Opp/Adj)
	local HorizontalAngle = -math.atan(RelativePosition.X/Adj)
	local H_Percentage = HorizontalAngle/(HorizontalFoV/2)
	local Y_Percentage = VerticalAngle/(VerticalFoV/2)
	Frame.Position = UDim2.fromOffset(
		(H_Percentage * ViewportSize.X/2) + ViewportSize.X/2,
		(Y_Percentage * ViewportSize.Y/2) + ViewportSize.Y/2
	if math.abs(VerticalAngle) > VerticalFoV/2 or math.abs(HorizontalAngle) > HorizontalFoV/2 then
		print("not on screen anymore")

Currently what it does:

(the green dot should stay on the red part)

My logic is that I get the angle from the camera look vector and get a 0->1 percentage value of angle/FieldOfView, then multiply that percentage by the screen viewport size to convert it into pixels.

I don’t see where I am going wrong with this. Here the place file if needed
3D To Screen Projection.rbxl (39.4 KB)

GUI Inset property is set to false on the GUI, and the anchor point is 0.5,0.5.


You tryna make the little green square stay on the little red cube?

Yes the green square should stay on the red cube, since I need the pixel position

Bumping thread since problem is still unresolved

It gets even easier!
In general, try to get out of angles as quickly as possible.

3D To Screen Projection.rbxl (39.2 KB)