Making a Part Cover the screen using ViewPortFrame

Hey, im trying to make a part in a viewport frame cover exactly my screen


here the part in grey ( red is the background of the viewport )
the part is facing the camera

i want the part size to be Vector3.new( X size of the screen , Y size of the screen , 1 )
im getting the size of the screen using ScreenGUI.AbsoluteSize with the screengui inset set to NONE

I know there must be some math to do this but i have tried for the past day finding something to do this and i couldnt find it .

sample of my code :


        local Screen = script.ScreenGui:Clone()
	
	local CameraClone = Instance.new("Camera")
	CameraClone.CFrame = CFrame.new(Vector3.new(0,1,-5),Screen.ViewportFrame.Part.Position)
	CameraClone.Parent = Screen.ViewportFrame
	Screen.ViewportFrame.CurrentCamera = CameraClone
	
	Screen.Parent = plrGUI

        Screen.ViewportFrame.Part.Size = PartSize

4 Likes

Can’t you just move the part forward to do that or do you specifically want to have to size it up?

i need it to size up by script because not every screen on every device is the same size

what i want is that every corner of the part is matching the corners of the user screen

1 Like

Try this

local Screen = script.Parent
local Viewport = Screen:WaitForChild("ViewportFrame")
local Part = Viewport:WaitForChild("Part")

local CameraClone = Instance.new("Camera")
CameraClone.Parent = Viewport
Viewport.CurrentCamera = CameraClone

local function get3DWorldPosition(screenX, screenY, depth)
	return CameraClone:ViewportPointToRay(screenX, screenY, depth).Origin
end

local function fitPartToScreen()
	local distance = 1

	local realSize = Viewport.AbsoluteSize
	local aspectRatio = realSize.X / realSize.Y

	local xMin = (1 - aspectRatio) / 2
	local xMax = (1 + aspectRatio) / 2
	local yMin = 0
	local yMax = 1

	local topLeft = get3DWorldPosition(xMin, yMin, distance)
	local topRight = get3DWorldPosition(xMax, yMin, distance)
	local bottomLeft = get3DWorldPosition(xMin, yMax, distance)
	local bottomRight = get3DWorldPosition(xMax, yMax, distance)

	local width = (topRight - topLeft).Magnitude
	local height = (topLeft - bottomLeft).Magnitude
	local centerPosition = (topLeft + bottomRight) / 2

	Part.Size = Vector3.new(width, height, 1)
	
	local baseCFrame = CFrame.new(centerPosition) * CameraClone.CFrame.Rotation
	Part.CFrame = baseCFrame * CFrame.new(0, 0, -Part.Size.Z / 2)
end

Viewport:GetPropertyChangedSignal("AbsoluteSize"):Connect(fitPartToScreen)
task.defer(fitPartToScreen)
3 Likes

Ty ! it does work, can you explain how does it work ? im trying to understand what your doing here !

If we were working in the Workspace using workspace.CurrentCamera, the process would be straightforward. It would be enough to get the screen size via Camera.ViewportSize, define the four 2D corners (0,0), (xMax, 0), (0, yMax), and (xMax, yMax), and project them into 3D space using Camera:ViewportPointToRay(X, Y, depth) to reconstruct the part.

However, inside a ViewportFrame, the camera behaves differently. While the Workspace camera handles full screen resolutions (like 1920x1080), the ViewportSize property of a ViewportFrame camera stays internally locked at a normalized ratio of (1, 1).

If we try to use the default (0, 1) values for the edges of the X-axis, the projected 3D positions will form a perfectly centered square instead of adapting to the container. This causes the points along the X-axis to become misaligned and pulled toward the center.

To fix this and find the actual 2D coordinates, we calculate the aspect ratio by comparing the GUI’s real size (Viewport.AbsoluteSize) with the ViewportFrame value of (1, 1) (calculated using a direct proportion / rule of three):

X = Viewport.AbsoluteSize.X / Viewport.AbsoluteSize.Y

Since the height (Y-axis) remains stable between 0 and 1, we only need to expand and center the range of the X-axis to compensate for the distortion. We achieve this by calculating the new boundaries (the default ones being 0 to 1):

  • xMin = (1 - aspectRatio) / 2
  • xMax = (1 + aspectRatio) / 2

With the X-axis properly adjusted, we can now correctly project the four true corners into 3D space using Camera:ViewportPointToRay() with the points (xMin, 0), (xMax, 0), (xMin, 1), and (xMax, 1).

Once we have obtained the four 3D vertices (topLeft, topRight, bottomLeft, bottomRight), we calculate the dimensions and the center position of the part:

  • Width: local width = (topRight - topLeft).Magnitude
  • Height: local height = (topLeft - bottomLeft).Magnitude
  • Center: local centerPosition = (topLeft + bottomRight) / 2

Finally, we align the part with the camera’s orientation using: local baseCFrame = CFrame.new(centerPosition) * CameraClone.CFrame.Rotation

To prevent half of the part’s thickness (depth) from clipping awkwardly into view, we offset the part backward by exactly half of its Z-axis thickness: Part.CFrame = baseCFrame * CFrame.new(0, 0, -Part.Size.Z / 2)



3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.