Gods Palace
This is my thesis project from LBS and was made as a solo project. The game is based around "non-Euclidean" game mechanics such as seamless portals, relative gravity, the player growing/shrinking, and time travel.
In the GIF here, you can see one of the first puzzles. The player needs to open a door, but the door is in the ceiling relative to the button.
The player has a portal they can walk through to appear on the ceiling.
They pick up a cube, walk through the portal and put it on the button. The door now opens in the ceiling. The player walks back through the portal and can pass through the door. Now while at the door, the cube can be seen falling towards and weighing down the button against the ceiling!
Relative gravity, spooky!
During the project the biggest challenge was to make the portals in the game feel as seamless as possible. To achieve the final effect, I combined a few different tricks.
To render a portal surface, I compute the player cameras coordinates in the entry portals local space. I then reinterpret that local coordinate as if it was in the exit portals local space and convert back out to world coordinates. This leaves me with a position with the same offset from the exit portal as the player camera has from the entry portal. That means that if we put a camera at that point and render the scene it'll be the exact perspective needed for the entry and exit portals to align in screen space. Let's call that our portal camera. We can then place a quad in the doorway of the entry portal and make it display a render target from our portal camera. However, since the player camera and the portal camera renders are only going to align in screen space, we'll need the door quad to sample the render texture in screen space. this effectively overlays the renders with a mask in the portal doorway.
If we do the same thing both ways, the portal will already look quite convincing but if anything obstructs the view between the portal camera and the exit portal that will show up as a weird artifact in the entry portal. To deal with this we can use an oblique projection matrix to rotate the near plane of the portal camera to align with the exit portal face. This will completely solve that issue.
To make things go through the portals, we can simply dot the entry portals forward with a vector pointing from the entry portal to the player. When the sign of the dot product changes, we know we've went over to the backside of the portal, however slightly. If we now add the condition that we need to be touching the portal while the sign flips, we now know we've passed through the portal. We then just reuse the space conversions we already use for the portal camera to move the player over to the exit portal.
Some problems may occur with this though if we have a collider behind either portal. That would block us from entering the portal. A simple solution to fix this is to add some colliders on the borders of the portal that make any object who touch them stop colliding with anything in the scene besides those borders. While we’re in this state we can walk though whatever wall might be obstructing the backside of the portals and when you stop touching the border in the exit portal you regain normal collision again.
Another trick I learned is that instead of having a flat quad in the doorways we can replace them with inverted cubes with a higher render priority than the rest of the scene. If we then make these cubes the exact same thickness as we've set our camera near plane to cut at, we can avoid any brief transition frames where the player camera clips though the quad and allows a cleaner effect with minimal cube thickness.
There's lots of small little tricks like this and you can continue to stack them out to infinity to increase how convincing the effect is and improve the performance. If I where to continue listing all the minute fixes we can do we'd be here all day, so I’ll stop here and simply conclude that it was a very interesting problem to try and solve. Especially as there was little information about the subject on the internet at the time I wrote all this.