Editing ViewportFrames & Camera?

I’m attempting to adjust a ‘Portal’ effect to allow for two factors.
Portal & Portal2 - Allowing Portal to see everything from the point of Portal2

Provided by @EmilyBendsSpace

This is the result of my adjustments with two portals:

This is what I wish to achieve, though this only uses a single Portal with the Parts placed directly behind it.



local RunService = game:GetService("RunService")

local PlayerGui = game.Players.LocalPlayer:WaitForChild("PlayerGui")

local UNIT_Y = Vector3.new(0,1,0)

local UNIT_ZM = Vector3.new(0,0,-1)

local XZ = Vector3.new(1,0,1)

local YZ = Vector3.new(0,1,1)

local camera = game.Workspace.CurrentCamera

-- Setup viewport frame and camera

local surfaceGui = PlayerGui:WaitForChild("SurfaceGui")

local vpf = surfaceGui:WaitForChild("ViewportFrame")

local vpfCam = camera:Clone()

vpfCam.Parent = surfaceGui

vpf.CurrentCamera = vpfCam

-- Folder of portal parts we don't copy into the VPF

local portalFolder = game.Workspace:WaitForChild("Portal_NO_COPY")

-- Portal location, corners, edge centers, face center

local portal = portalFolder:WaitForChild("Portal")

local portal2 = portalFolder:WaitForChild("Portal2")

local tc = portal2.CFrame.p + 0.5 * portal2.Size * YZ

local bc = portal2.CFrame.p + 0.5 * portal2.Size * Vector3.new(0,-1,1)

local p = portal2.CFrame.p - portal2.Size.Z * 0.5 * portal2.CFrame.LookVector -- Portal face center, not part center (SurfaceGui is on Back face)

-- Unoptimized render loop. Much redundant calcs, wow.

RunService.RenderStepped:Connect(function(dt)

local camCF = camera.CFrame

local c2p = p - camCF.p

local c2pXZ = (c2p * XZ)

local c2pYZ = (c2p * YZ)

local levelCamCF = CFrame.fromMatrix(camCF.p, camCF.RightVector, Vector3.new(0,1,0), camCF.RightVector:Cross(Vector3.new(0,1,0)))

local csbc = levelCamCF:Inverse() * bc

local cstc = levelCamCF:Inverse() * tc

local v1 = (csbc*YZ).Unit

local v2 = (cstc*YZ).Unit

local alpha = math.sign(v1.Y) * math.acos( v1:Dot(UNIT_ZM))

local beta = math.sign(v2.Y) * math.acos( v2:Dot(UNIT_ZM))

local fh = 2.0 * math.tan(math.rad(camera.FieldOfView) * 0.5)

local hPrime = math.tan(beta) - math.tan(alpha)

local refHeight = hPrime / fh

local dpX = c2pXZ.Unit:Dot(-portal2.CFrame.LookVector)

local camXZ = (camCF.LookVector * XZ)

local scale = math.abs(camXZ.Unit:Dot(c2pXZ.Unit)) / (math.abs(portal2.CFrame.LookVector:Dot(c2pXZ.Unit)))

local tanarccos = math.sqrt(1-dpX*dpX)/dpX

local sc = scale * refHeight

local w = 1

local h = 1

local dx = math.sign(c2p.X * c2p.Z)*tanarccos

local dy = -c2pYZ.Y/c2pYZ.Z

local d = sc

-- Camera CFrame won't take values too much larger than 1, so normalizing the unprojection matrix by the largest component

local max = math.max(w,h,math.abs(dx),math.abs(dy),d)

w, h, dx, dy, d = w / max, h / max, dx / max, dy / max, d / max

vpfCam.CFrame = CFrame.new(0,0,0, w, 0, 0, 0, h, 0, dx, dy, d) + camCF.p

end)
2 Likes

Just FYI, the example code you’re working from there is from a place file I made just to show what the viewport frame calculations look like in the simplest case of a world-axis-aligned portal. Modifying the code for two portals to see each other is the easy part, you’d just have to multiply the viewport camera CFrame result by portal2.CFrame * portal1.CFrame:Inverse(), for (portal 1 to see from the point of view of portal 2).

The harder parts are generalizing the code to work with a portal that is rotated in world space. There are a couple of other spots where multiplication by the portal CFrame needs to be added. If I have a free moment, I can update this example to show this.

Also, If the portal doesn’t have the same point of view as the main game camera, the trick of letting the skybox “leak” through using VPF transparency is no longer valid, and you need a new workaround for the backdrop (not an issue if you’re indoors).

1 Like

I’ll be grateful for any help!
When using the Method above I get the same results as prior where the Camera result from P2 to P1 is warped.