Portals and Transformations

Started by
6 comments, last by JasonHise 17 years, 11 months ago
I want to implement a portal system to create windows between two separate locations. My plan is to represent a portal as a position, right, and up vector for the portal itself, and a position, right, and up vector for the position of the window which the portal would map to. A picture may help here: p is the location of the portal and w is the location of the window being mapped. To implement this I would like to create a transformation which would map objects from window coordinates to portal coordinates (so that the position, right, and up of the window would be moved to overlay the position, right, and up of the portal). I would then use the portal itself to define the view frustum which I would use to render the scene to a surface, which I could texture map to the portal location when rendering the rest of the scene. I need some help with the math here. How do I derive this transformation? And how do I determine the near plane distance, left, and bottom components of the view frustum? (edit: the point 'w' in the picture should be on the opposite side of the window) [Edited by - 0xCHAOS on April 29, 2006 12:01:49 AM]
Advertisement


You could use a simple dot product on all vertices of your portal, if any of them fall within your FOV then the portal is active.

Portals are used to determine if what they have behind them is visible. So:

There are three major checks to perform before determining this:

-You are infront of the portal, eg: the portal is facing you and you're in the 'sector' that it should be facing you from (mind you portals work from both sides).

-A visible portal overlaps a portal that lies on the other side of the sector that is behind it, this means the portal on the other side is also visible (as well as whatever is behind it). This is more what you're talking about.

-Any part of the portal is within your field of view.


Now, in my opinion, view frustums are unnecessarily complex. You're trying to determine the sides of the screen extending into space along your FOV. This precision is generally unnecessary. You can replace this with a simple dot product of the delta between camera origin and target origin and the normal of the camera's angles. Through some simple trial and error you can determine a value that suits your needs for determining whether or not something is (approximately) within your 'view frustum'.

Now, Doom3 is a good example of John Carmack's take on portal systems for performing what you're describing.

What he did was take the portal geometry, and construct a screen-space axis-aligned 2D bounding box for each portal in the field of view. This made it VERY easy to do approximate overlapping tests to determine if what was visible through one portal included another portal.

I am unaware of what you already know about such things, so forgive me for stating anything you were already aware of. I am only trying to help, and I hope this does :)

Perhaps I failed to explain my idea correctly. I am not trying to do visibility testing here. I am trying to create a teleporter, so to speak. If you look at the picture above, you will see that the smiley face is visible as looking back at you because it is facing the X on the left wall. There is only one smiley face in that picture, visible from two different angles due to the teleporter. If I were to walk through the window in the back, I would come out the X on the wall to the left. I hope this clarifies what I meant.

(edit: posted in reply to a post that was deleted)

[Edited by - 0xCHAOS on April 29, 2006 3:18:17 AM]
Assuming the portal (red) frame is given in global co-ordinates
FPg
where the index P means "portal" and g means global, and F means a transformation matrix build from rotation and translation.

Any element given relative to the portal frame is then transformed into global co-ordinates (I'm using column vectors here) by
vg := FPg * vPl
where the index l means local.

Anything local to the window (blue) frame is given as
vWl
where the index w means "window", so that it would appear in global co-ordinates as
vg := FWg * vWl

Now you have simply transform that into global co-ordinates not by using the blue frame's transformation but the red one's:
vg := FPg * vWl

In fact, anything local to the window frame could be used as is also local to the portal frame.

If, on the other hand, the stuff behind the window is given in global co-ordinates you first have to transform it back into window local co-ordinates, so that
vg := FPg * (FWg)-1 * vWl
and
FPg * (FWg)-1 *
denotes the overall transformation.


EDIT: Please have in mind that the above formulas use column vectors (e.g. suitable for OpenGL) but have to be transposed for row vectors (e.g. D3D).
If you want to know the the view frustum, you could treat the corners of the window as local elements and transform them into global co-ordinates as shown in my previous reply (and perhaps then, if you need to do so, into camera local co-ordinates). However, be aware that you get an oblique projection in general for rendering a texture, because the portal's plane is most often not co-planar with the camera's plane.

You could, however, take into account to simply render the scene stuff behind the portal (after having rendered the scene in front of the portal) if you consider the transformations given in the above reply. So, if you want, you may compute a view frustum for scene oriented culling only, avoiding the need of a front and back clipping plane and to adapt the projection for a texture.
The difficulty with just translating the relevant geometry to behind the portal is that I may have two portals which look in to the same space.



In this example, the camera can see a portal in room B that links to room C, and a portal in room C that links to room B. I can't map the geometry for both rooms B and C to that lower right hand corner at the same time. This is why I need to use separate renders for each portal.

I'm still having some trouble with the math. I think that I could translate by -w to get the point to the origin, perform the rotation to align the axes, and then translate by p to move everything to the right location. But I don't know how to assemble that middle rotation step.

With regard to the frustum, would it be reasonable for me to make the camera directly face the plane on which the portal lies so that it isn't a sheared projection?

(For the curious, I'm trying to model being on the surface of a hypercube, and need portals to join the sides of eight cubic rooms to each other, which is why the case shown above is important)
Okay, you couldn't use one single reference frame in D for both renderings from B and C. Is it possible to locate several frames in D w.r.t. the reference frame of D? Hmm. I currently don't see the consequences of the "hyper cube", but perhaps it may work ...

Say you locate a reference frame FDg in the upper left corner of D, and locate a frame FD1l at the left window of D and another one FD2l at the top window. Both these are given local to FDg, so that
FDig := FDg * FDil for all i

When looking through B into D, you have to relate the local geometry (see my pre-previous reply) inside D to FD2l, and map that by using the corresponding frame FB2l like so
FB2l * ( FD2l )-1
to yield in the geometry given in the local frame of B.

Similarly,
FA1l * ( FB1l )-1
maps the local geometry in B to the local frame of A.

So, for each portal crossed you get a two part transformation. Concatenate them and multiply with A's global frame
FAg * { FA1l * ( FB1l )-1 } * { FB2l * ( FD2l )-1 }
and you may have done the job for the one investigated path (the curly braces should only show what parts come from the both particular portals). Equivalently you could go the other path.


As already stated, this method needs that each outgoing portal has a frame and a corresponding incoming frame in the neighboured room.

[Edited by - haegarr on April 29, 2006 11:06:17 AM]
Yay, I got it working. Each room in the hypercube is a different color. The hypercube rendered to a recursive depth of 3:



Eventually, I should probably disable lighting on the portals themselves to make it a bit more realistic, and adjust the resolution of the portals based on distance. But the hard part is done. Thanks for the help.

This topic is closed to new replies.

Advertisement