I've searched the internet for portal implementation in 3D, and I found a piece of code that I just don't understand. What is the purpose of this function and how does it work for updating the portal camera ?

func move_camera(portal: Node) -> void: var linked: Node = links[portal] #this is the other portal var trans: Transform = linked.global_transform.inverse() \ * get_camera().global_transform var up := Vector3(0, 1, 0) trans = trans.rotated(up, PI) portal.get_node("CameraHolder").transform = trans var cam_pos: Transform = portal.get_node("CameraHolder").global_transform portal.get_node("Viewport/Camera").global_transform = trans

I'm having to reverse engineer a bit from looking at the script, but it appears that each portal has under it at least a Spatial called "CameraHolder" as well as a https://docs.godotengine.org/en/stable/tutorials/viewports/viewports.html, which itself has a camera as a child. There is presumably also a mesh with a ViewportTexture that renders the actual view through the portal.

A Viewport is not itself a portal; it's more like a closed circuit TV screen. Its view will not update just because you're looking at whatever surface it renders to from a different angle. That's the purpose of this function: it computes the transform for the portal's camera based on the root camera's global transform and the other portal's global transform. I haven't actually worked out the math myself, so I don't know why the "local" portal's global transform isn't involved. I think that's what "cam_pos" is supposed to be, but cam_pos doesn't appear to be used. It's possible the last line should have "cam_pos" instead of "trans".

Let me try making this work myself and I'll let you know what I find.

The code in this repository is pretty cool for portals: https://github.com/19PHOBOSS98/Godot---PortalInstance

The video it’s from:

I played around with it a bit and it was really promising, from what I remember at least (it was months ago).

Edit: not sure if it’s the same code you are using or not, but having another implementation may help with figuring out what is going on.

Why does it use a $DummyCam instead of the actual camera, and what is the link between them ?

This is my try at making a portal view : <iframe width="851" height="480" src="https://www.youtube.com/embed/BDJpO0o8Iuk" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

The camera of the viewport seems to update nicely when I just move the player. However, when I rotate my camera, the viewport camera seems to rotate a bit off. Also, I cannot rotate my portal "exit" camera in the editor, that would make everything not work.

This is my code : var linked: Node = $PortalExit var portal = $Portal var camera_trans = $KinematicBody/CameraPivot/SpringArm/Camera.global_transform var trans: Transform = linked.global_transform.inverse() * camera_trans trans = trans.rotated(Vector3(0, 1, 0),PI) portal.get_node("CameraHolder").transform = trans var cam_pos: Transform = portal.get_node("CameraHolder").global_transform portal.get_node("Viewport/Spatial").global_transform = cam_pos

Answering the question : The trans variable holds the transform from the camera to the portal exit. The CameraHolder node is used to "link" the transform to the portal. I managed to fix the rotation issue and also implemented the "teleportation": <iframe width="851" height="480" src="https://www.youtube.com/embed/7Z3l81KwgGo" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

2 years later