Calculating Horizontal FoV from Vertical FoV

I’m trying to get the horizontal FOV given the camera FOV and Camera Aspect ratio so I can place parts in every corner of the screen.

local camera = game.Workspace.CurrentCamera
local cameraCFrame = game.Workspace.CameraNode.CFrame

game.Workspace.CurrentCamera.CameraType = Enum.CameraType.Scriptable

local cameraConnect = game:GetService("RunService").RenderStepped:Connect(function()
	camera.CFrame = cameraCFrame
end)


local function getHorizontalFov(vFov)
	local viewportSize = game.Workspace.CurrentCamera.ViewportSize
	local aspectRatio = viewportSize.X/viewportSize.Y
	
	local cameraHeightAt1 = math.tan(math.rad(vFov) * .5)
	return math.deg(math.atan(cameraHeightAt1 * aspectRatio) * 2)
end


local function createViewModel()
	
	local vFOV = camera.FieldOfView
	local hFOV = camera.FieldOfView --getHorizontalFov(vFOV)
	print(vFOV, hFOV)
	local corners = {
		topLeft = cameraCFrame * CFrame.Angles(math.rad(vFOV/2), math.rad(hFOV/2), 0) * CFrame.new(0,0,-15),
		topRight = cameraCFrame * CFrame.Angles(math.rad(vFOV/2), -math.rad(hFOV/2), 0) * CFrame.new(0,0,-15),
		bottomLeft = (cameraCFrame * CFrame.Angles(-math.rad(vFOV/2), math.rad(hFOV/2), 0)) * CFrame.new(0,0,-15),
		bottomRight = (cameraCFrame * CFrame.Angles(-math.rad(vFOV/2), -math.rad(hFOV/2), 0)) * CFrame.new(0,0,-15)
	}
	
	for corner,coordinateframe in next, corners do
		local part = Instance.new("Part")
		part.Anchored = true
		part.Size = Vector3.new(1,1,1)
		part.CFrame = CFrame.new(coordinateframe.Position)
		part.Parent = game.Workspace
	end
end


createViewModel()

Here is my result using my horizontal FOV calculation(Camera is set to the red node, didn’t show with camera on the node because you cant see any of the parts at all)

And here is the result using the default FOV (as in not calculating horizontal, default 70 for both. Would probably work for box monitors)

If you don’t know why these are placing directly on the corners, let me know, any help appreciated <3

2 Likes

Consider using Camera:ViewportPointToRay and Camera:ScreenPointToRay

Both are very similar, but Camera:ScreenPointToRay accounts for the Topbar CoreGui offset.

I think below is what you’re trying to do.

local RunService = game:GetService("RunService")
local Camera = game:GetService("Workspace").CurrentCamera

local ViewportSize = Camera.ViewportSize

RunService.RenderStepped:Connect(function()
	local Rotation = Camera.CFrame - Camera.CFrame.p
	TopLeftPart.CFrame = CFrame.new(Camera:ScreenPointToRay(0, 0, 1).Origin) * Rotation
	TopRightPart.CFrame = CFrame.new(Camera:ScreenPointToRay(ViewportSize.X, 0, 1).Origin) * Rotation
	BottomLeftPart.CFrame = CFrame.new(Camera:ScreenPointToRay(0, ViewportSize.Y, 1).Origin) * Rotation
	BottomRightPart.CFrame = CFrame.new(Camera:ScreenPointToRay(ViewportSize.X, ViewportSize.Y, 1).Origin) * Rotation
	CenterPart.CFrame = CFrame.new(Camera:ScreenPointToRay(ViewportSize.X/2, ViewportSize.Y/2, 1).Origin) * Rotation
end)

1 Like

Huge necro, but I thought I’d answer since it’s the first thing that appears on google.

You can calculate the horizontal FOV given the AspectRatio and the VerticalFieldOfView like so:

local Camera = workspace.CurrentCamera
local AspectRatio = Camera.ViewportSize.X / Camera.ViewportSize.Y
local VerticalFieldOfView = Camera.FieldOfView

local HorizontalFieldOfView = math.deg(math.atan(math.tan(math.rad(VerticalFieldOfView) / 2) * AspectRatio) * 2)

print(HorizontalFieldOfView)

In the case of a viewport frame, your Camera.ViewportSize will be your Frame.AbsoluteSize instead.

9 Likes