Re-Creating a Portal Effect,

What if you use some really complicated equation to figure out where the lighting is coming from and mirror that to an invisible part which creates the same shadow

2 Likes

I’ve been working on a way to create multiple portals with that system. I think you can understand how to make multiple ones by comparing this one I made with the one already provided in the demo. Basically, it just links portals like “Portal A to B,” “Portal C to D,” and you can keep going and make more. I’ve even developed a system that only shows the nearest pair of portals, but for now, it still needs some fixes, so I won’t post that.

Remember to make Portal C and D inside the “Portals” model for it to work.

local Players = game:GetService("Players")
local Lighting = game:GetService("Lighting")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Portal = require(ReplicatedStorage.Portal)

-- Define all four portals
local portalA = Portal.FromPart(workspace.World, workspace.Portals.PortalA, Enum.NormalId.Front)
local portalB = Portal.FromPart(workspace.World, workspace.Portals.PortalB, Enum.NormalId.Front)
local portalC = Portal.FromPart(workspace.World, workspace.Portals.PortalC, Enum.NormalId.Front)
local portalD = Portal.FromPart(workspace.World, workspace.Portals.PortalD, Enum.NormalId.Front)

-- Add skyboxes for all portals
portalA:AddSkybox(portalB:GetPart().Sky)
portalB:AddSkybox(portalA:GetPart().Sky)
portalC:AddSkybox(portalD:GetPart().Sky)
portalD:AddSkybox(portalC:GetPart().Sky)

-- Link portals in pairs (A-B and C-D)
portalA:Link(portalB)
portalB:Link(portalA)
portalC:Link(portalD)
portalD:Link(portalC)

-- World rendering and camera pass-through
local characterPortalSide = portalA
local prevPortalSide = characterPortalSide

local currentSkybox = characterPortalSide:GetPart().Sky:Clone()
currentSkybox.Parent = Lighting

local prevCamCF = workspace.CurrentCamera.CFrame
local prevCamFocus = workspace.CurrentCamera.Focus

RunService:BindToRenderStep("BeforeInput", Enum.RenderPriority.Input.Value - 1, function()
	workspace.CurrentCamera.CFrame = prevCamCF
	workspace.CurrentCamera.Focus = prevCamFocus
end)

RunService.RenderStepped:Connect(function(dt)
	local successTeleA = portalA:AttemptTeleport()
	local successTeleB = portalB:AttemptTeleport()
	local successTeleC = portalC:AttemptTeleport()
	local successTeleD = portalD:AttemptTeleport()
	
	if characterPortalSide == portalA and successTeleA then
		characterPortalSide = portalB
	elseif characterPortalSide == portalB and successTeleB then
		characterPortalSide = portalA
	elseif characterPortalSide == portalC and successTeleC then
		characterPortalSide = portalD
	elseif characterPortalSide == portalD and successTeleD then
		characterPortalSide = portalC
	end
	
	prevCamCF = workspace.CurrentCamera.CFrame
	prevCamFocus = workspace.CurrentCamera.Focus
	
	local cameraPortalSide = characterPortalSide
	
	for _, portal in pairs({portalA, portalB, portalC, portalD}) do
		local surfaceCF, surfaceSize = portal:GetSurface()
		local lp = surfaceCF:PointToObjectSpace(prevCamCF.Position)
		
		if lp.Z < 0.15 then
			continue
		end
		
		local success, cframe, focus = portal:GetCameraPassThrough()

		if success then	
			workspace.CurrentCamera.CFrame = cframe
			workspace.CurrentCamera.Focus = focus
			cameraPortalSide = portal:GetLinked()
			break
		end
	end
	
	-- Step characters and render for all portals
	portalA:StepCharacters()
	portalB:StepCharacters()
	portalC:StepCharacters()
	portalD:StepCharacters()
	
	portalA:Render()
	portalB:Render()
	portalC:Render()
	portalD:Render()
	
	if prevPortalSide ~= cameraPortalSide then
		currentSkybox:Destroy()
		currentSkybox = cameraPortalSide:GetPart().Sky:Clone()
		currentSkybox.Parent = Lighting
	end
	
	prevPortalSide = cameraPortalSide
end)

-- Physics step for all portals
local wasTouchingA = false
local wasTouchingB = false
local wasTouchingC = false
local wasTouchingD = false

RunService.Heartbeat:Connect(function()
	wasTouchingA = portalA:PhysicsStep(wasTouchingA)
	wasTouchingB = portalB:PhysicsStep(wasTouchingB)
	wasTouchingC = portalC:PhysicsStep(wasTouchingC)
	wasTouchingD = portalD:PhysicsStep(wasTouchingD)
	
	if not wasTouchingA and not wasTouchingB and not wasTouchingC and not wasTouchingD then
		portalA:SetTouching(false)
		portalB:SetTouching(false)
		portalC:SetTouching(false)
		portalD:SetTouching(false)
	else
		portalA:SetTouching(true)
		portalB:SetTouching(true)
		portalC:SetTouching(true)
		portalD:SetTouching(true)
	end
end)

-- Character rendering for all portals
local function onCharacterAdded(player, character)
	local cleanupA = portalA:WatchCharacter(player.Character)
	local cleanupB = portalB:WatchCharacter(player.Character)
	local cleanupC = portalC:WatchCharacter(player.Character)
	local cleanupD = portalD:WatchCharacter(player.Character)
	player.CharacterRemoving:Wait()
	cleanupA:Sweep()
	cleanupB:Sweep()
	cleanupC:Sweep()
	cleanupD:Sweep()
end

for _, player in pairs(Players:GetPlayers()) do
	if player.Character then
		task.spawn(onCharacterAdded, player, player.Character)
	end
	
	player.CharacterAdded:Connect(function(character)
		onCharacterAdded(player, character)
	end)
end

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		onCharacterAdded(player, character)
	end)
end)

I’d suggest to not make to many portals close to eachother :smile:

3 Likes

Hey pal, as I was looking for images for Non Euclidian reference portals for Roblox games to use as a presentation tool. I just want to know where you got that image, that looks hella classic

If you’re saying the image looks old, then remember that this topic is old - 2019 old. That post was from 2019.

1 Like

Sorry, I have no idea, it was so long ago! What I remember is is that it was from some sort of test so it wasn’t in a complete game or anything.

Actually I saw this thing too and so far I know there is a file of the place in Roblox, where you can test it or copy this system. It is a single cube with a properly set viewport frame, not 6 portals. Inside that viewport frame there is a whole map. That’s why it is not very efficient with large or more realistic maps.
I don’t know how to find it, but try to google about it.

I added raycasting to this portal system, so you can now shoot guns through them, or even shoot portals through portals. I also allowed for tracking other parts besides just those belonging to players, so any object can now go through the portals.

2 Likes

Thats super cool, has anyone solved the blur problem yet?

If you are talking about the blurring when getting close to the portal; unfixable.
It’s a result of Roblox’s wacky code, we can’t exactly change that.

aww, i guess we would have to wait on roblox for that then. But yet again since this is like the biggest post here (i think) then for sure someone would notice it.

Hello I am actually looking to use this portal system in my game! However the old portal world that was copy-able is no longer there and I cant find any code to get started on outside of the code within @EgoMoose github which has a ton of useful stuff but doesn’t include the teleportation side of things as I can find.

If anyone has the source code or access to a place that has this portal system, please let me know! It would be extremely helpful.

It is a viewportframe issue, and since they haven’t touched it for years, it doesn’t seem likely to be fixed recently.

You think they might make something better one day and then deprecate viewport frames?

who knows, but i hope they will… :folded_hands:

Very doubtfully, they have no reason to, and if why reinvent the wheel?
ViewportFrame updates will come, but it may take a fewwwwwwww more years.

Honestly I have no idea what new studio features they’re even working on, but because of what we have to work with compared to other engines a lot of the time we have to improvise don’t we?

Hello! Does anyone have anything helpful that can help me solve these portal issues?