Portal Clipping Options

I am currently in the thinking stages of implementing a portal system. The main thing I’m undecided on is how to clip anything that is drawn through the portal. So far I’ve come to the conclusion that there are three possible ways of doing this:

  1. Write a CPU clipper. No gl related problems, but creates extra tris/polys and isn’t being done on the card. Probably the most time consuming option.

  2. Stencil buffer. Either mask the area to be drawn to, or mask the area that won’t be drawn to. Possibly fill rate intensive and if I were to implement stencil shadows may cause problems (although 1 bit for portal masking and the other 7 for shadows should be enough (?) ).

  3. glClipPlane. All taken care of by OpenGl, just define the clip planes as created by the eyepoint and the edges of the portal. Problem (on Nvidia cards at least) is that defining extra user clip planes (other than the 6 created by the view frustum) uses texture units as clipping is a fragment operation ( 2 clip planes per texture unit ? ).

All possible options. Personally I’m leaning towards the stencil option as I’d like to keep the textures units free so I don’t have worry about managing them doing things other than texturing (although it is essentially texturing). I understand that clip planes can be manually created by using the correct texture setup, but haven’t managed to find a decent summary on how this works. If someone could explain that would be great. (I know there is an Nvidia demo on this (cullfragment), but it uses vert progs and the code is a little sparse on comments both of which make it hard to understand exactly how it works.)

So, anyone out there who has done this sort of thing before what advice do you have. What worked for you and how would you do it if you had to write a similar thing now? What issues am I not considering? I know portal recursion could be a problem, but if I only draw the contents of one portal at a time it shouldn’t present too much of a sticking point, and also put some sort of cap on the recursion.

Probably best to set the scene a bit as well. The sort of portals I’m mainly going to be implementing include indoor/outdoor boundary portals, possibly room/room indoor portals (less vital perhaps), the occasional mirror portal and ‘magic doorway’ or warp portals. These will be human placed rather than algorithmically generated per quake/halflife etc, which as I understand, generated lots of portals based on level geometry and used them to calculate the PVS.

How about

  1. use the Z buffer

?

Here’s the algorithm for a portal renderer which will be very efficient for current hardware (which does accelerated Z occlusion). It’s pseudo-code, and it assumes walls are objects in the sector just like actors and decoration. Use your imagination :slight_smile:

renderSector( player->curSector, cameraFrustum );

void renderSector( Sector * s, Frustum f ) {
foreach o s->objectList {
if( intersects( o, f ) ) {
renderObject( o );
}
}
foreach p s->portalList {
Sector * s2 = p->otherSector( s );
Frustum f2 = intersect( boundingrect( p ), f );
if( !f2.isEmpty ) {
renderSector( s2, f2 );
}
}
}

If you want to do mirrors, you should set up the camera before recursing, as mirroring will probably be a property of your portal object.

Using the z-buffer approach will work in the majority of cases, but one situation I had envisage was a free floating warp portal on a landscape. Drawing the landscape around and behind this portal will fill the z-buffer, however anything that is through the portal and closer than the landscape behind the portal will not be z culled to the boundaries of the portal. I think q3 had warp portals similar to this (although they weren’t on a landscape).

Agreed on the mirror portals, they should store a transform that is applied to the current view settings to produce a mirrored effect, e.g. just draw the current sector from a different position and orientation.