Portal Prototype

I am planning to recreate the well known game of Portal. It will be implemented using a custom C++ engine, using DirectX11 and the Effects Framework. This project serves as a test environment for me to learn how to make working portals in an existing game engine, Unity in this case.

Rendering the portals

I opted for the render texture approach, meaning each portal has a camera and a render target. Every frame, the camera's transform is updated according to the new main camera's transform. The cameras then get rendered onto the portal's render target before the main camera. The textures are assigned to the linked portal's screen material, to be displayed on the other portal. The UV's of the portal's screen are aligned based on their screen-space position, so the portal appears aligned and non-deformed.

Teleporting the player

The portal has a trigger box covering the inside opening. Every object that can travel through the portal inherits from a base traveler class. This trigger box allows the portal to track those travelers that can potentially cross the portal, and knows if this happens by comparing on which side of the portal the traveler is versus previous frame. If the side is different, the traveler has then crossed the portal, gets moved to the output portal, according to both portal's transforms, and is now tracked by the output portal, until he leaves the trigger box.

Fix artefacts

One issue that spoils the illusion is the near clipping plane of the player's camera clipping through the portal's screen, revealing what's behind the portal. To fix this issue, when the player enters the portal's trigger box, the portal's screen become thick enough on the back side so the camera cannot clip through it. This screen needs then to be double sided, so the texture is also visible once inside the screen. With the trigger fitting completely inside the portal's frame, it is not possible for the projected texture to be seen outside of the portal frame.

Add a clone and slice it

Another important part of the illusion is to have a visual representation of the traveler on the other side of the portal. The first time a traveler enters a portal trigger, a clone gets created and cached for future uses. The clone and the original traveler get sliced as well, so they do not remain visible on the other side of the portal's screen.

Oblique projection

One final issue with the portal's camera, being pushed away from the portal to give the correct perspective, is that other scene object can become visible on the portal's rendering. To prevent this, oblique projection is used to align the near clipping plane of the portal's camera to be aligned with the portal's screen, so every object that could block the view gets clipped away.

Future Work

This implementation does not support recursive portals at the moment. Recursive portal is the case where one portal is visible through the other portal, creating a potentially infinite recursion of portals. To manage this case, additional render target and render passes are required per recursion. This is a relatively expensive operation and has to be limited to a maximum recursion depth.

I will also look into another approach to render the portals, using the stencil buffer. This approach allows to render the scene in a single pass. Starting from the main camera, all opaques are rendered. Rendering the portal increases the stencil buffer. Once done, the opaque pass gets restarted with the correct camera transform, only writing to pixels where the stencil buffer is equal to 1. Once no portal is visible, or the maximum recursion has been reached, transparent objects can now be rendered, starting from the deepest portal back to the main camera. This video explains both approaches, as well as the encountered issues, and was used as a reference.

Walkthrough Demo

The project is available on GitHub!