Thanks, I can edit it keeping this in mind.
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
1 Like