maddalihanumateja / aframe-portals

Implements the components required to create portals within an aframe scene
MIT License
12 stars 0 forks source link

Portals for AFrame

Image showing three portals. One just acts as a reflector. Entering it in VR will "reflect" the user back on the same path in the opposite direction. The other two are linked and entering one will have the user exit from the other.

Purely for aesthetic purposes, I thought it would be interesting to build a website with an interdimensional space as the homepage having portals leading to other pages. AFRAME provides links that look like portals and that provide a preview of the space you are about to enter. But you still have to click or select the portal in some way to actually be taken to the destination. I thought to myself, wouldn't it be nice if entering the link seamlessly takes you to the destination of the portal. Take a look at this non-euclidean rendering engine by @HackerPoet and his YouTube video that I was influenced by. He, and many other developers, have referenced the game Portal and how you would just render a camera to the texture of a render target (the face of the portal). This felt doable in AFRAME.

I decided to make portals with one side (the face) showing a view of the destination and the other (the frame) being an opaque side that doesn't show a preview. Entering the portal through the face was supposed to take you seamlessly to the destination. In order to do this, I had to figure out

Here's a link to the final glitch project.

Generating the view of the destination

As mentioned earlier, I decided to use the popular method of using an additional camera, positioning and orienting it appropriately and rendering it to the texture of the portal face. I got cues on how to do this from the mirror example for three.js that uses a reflector class. Just had to change the positioning of the external camera so the portal showed the view at the destination instead of acting like a mirror. I did run into @stemkoski's mirror example at first and tried adapting it. What I quickly realised was that the portal view didn't seem realistic. The scale of the objects in the portal view didn't seem to change at all based on the position of the user. After fiddling around a lot with using CubeCameras for this with subpar results, I ended up stumbling onto this stackoverflow post. It had a clear example on jsfiddle that helped me understand the process of rendering to a mesh texture from a PerspectiveCamera. Now that I knew how to render the portal view, I had to figure out how to position and orient the camera for the portal view. This was pretty simple.I just needed to imagine that if I was in front of portal 1 whose destination was portal 2 and my position coordinates with respect to portal 1 were (x,y,z) then the view on portal 1's face would be as though I was at (-x, y, -z) with respect to portal 2 (so I would be on the opposite side of the destination portal's face). Orientation was a bit trickier. After drawing a few vector diagrams and making sure I understood what the orientation of the portals in AFRAME meant, I concluded that I only needed to rotate the portal camera around the y axis and keep the x and z rotations the same as the player's camera. The final y rotation of the portal camera if the user was in fron of portal 1 with destination being portal 2 was (user world orientation - portal 1 world orientation)+(PI/2 - portal 1 world orientation)+(PI/2 + portal 2 world orientation). Something to keep in mind when rotating the camera of the user: directly manipulating the camera.object3D.rotation property doesn't change the orientation of the user camera. This seems to have to do with the look-controls component of the camera. I found a stack overflow post that helped me figure out a way to rotate the camera by changing the pitch and yaw attributes of the look-controls component. There's probably a better way to do this by using a camera rig as suggested in AFRAME documentation.

Teleporting when I collide with the portal

If you've used the physics-collider component from aframe-physics-extras you might have noticed that it gives you the same src and target for collisions. So if player collided with portal 1, I would get player as both source and target which doesn't give me any information about where to teleport. In another case, I'd get portal 1 as both source and target. But this wouldn't be useful for when I use networked-aframe for a multi-user app. It would also be helpful to know if entities other than the users have passed through the portal (e.g. like when throwing a ball through a portal and catching it at the other end). I decided to use the aabb-collider component instead which gave me the source and target of the collision without issue.

The next problem was the collider boundaries. Just teleporting myself the location where I'd positioned the portal camera resulted in me colliding with the portal at the destination and getting stuck in an endless loop. So I decided instead to have the user teleport to a location slightly ahead of the portal face. I tried playing around with the fov of the portal cameras and the final location where the player gets teleported to but this could definitely be better. Ideally, you would need to make sure the position and orientation of the user didn't change jarringly after teleportation i.e. the initial view after teleportation should be almost the same as what was displayed on the portal face before teleportation so it feels like a seamless process. I did the best I could but it didn't turn out as good as I wanted.

Additional notes