Cells & Portals in VRML

Holger Grahn

 




Introduction

VRML 97 currently lacks tools for enabling visibility managment for indoor environments.

An ideal browser implementation could analyze the scene graph and apply occlusion culling algorithms during rendering, but this seems currently not feasible given the dynamic nature of a VRML scene graph.

A well known occlusision culling technique are Cell & Portals.
The idea in short: given a set of rooms (Cells) connected by windows and doors (Portals), for a given room if a window is not visible, the room viewed through the window is not visible either. That means cellsnot currently visible need not to be rendered nor checked for collision and selection.

Details

As a compact description the reader is refered to the paper: Faster 3D Game Graphics by Not Drawing What Is Not Seen Kenneth E. Hoff III. ACM Crossroads, 1997.

Figure Figure

Node definitions :

 

Cell {
    exposedField    SFVec3f bboxSize    -1 -1 -1
    exposedField    SFVec3f bboxCenter  0 0 0
    exposedField    MFNode children     []
    eventIn     MFNode addChildren
    eventIn     MFNode removeChildren
    exposedField    MFNode portals
    exposedField    SFInt32 content     0
    }


Portal {
    exposedField    SFBool enabled      TRUE
    exposedField    SFBool ccw      TRUE
    exposedField    SFNode coord        NULL
    exposedField    SFNode cell         NULL
}


CellGroup[ {
    exposedField    SFVec3f bboxSize    -1 -1 -1
    exposedField    SFVec3f bboxCenter  0 0 0
    exposedField    SFInt32 range       -50
    exposedField    MFNode cells        []
    exposedField    MFNode children     []
    eventIn     MFNode addChildren
    eventIn     MFNode removeChildren
    eventOut    MFNode activeCells
}


BspTree {
    exposedField    SFRotation plane    0 0 1 0
    exposedField    SFNode front        NULL
    exposedField    SFNode overlap      NULL
    exposedField    SFNode back         NULL
}


A Cell Portal graph is routed by a CellGroup node. The list of cells is listed in the cells field of the CellGroup.

The Portal helper node defines the "window" geometry and points to the Cell seen.

CellGroup

Cellgroup is a grouping node similarily to Group.

The cells field specifies the list of cells composing the CellGroup. The nodes must be Cell nodes.

The children field may specify a list of children nodes consisting out of a BspTree Tree with Cell nodes as leaves. Nodes contained in the children field are not rendered in a linear way, they are used to find the initial starting cell, the cell containing the current viewpoint.

The activeCells eventOut is set to the list of currently visible cells. activeCells[0] is the starting cell, which contains the viewer.

The range field allows to limit the cell recursion depth. The Cell tree is recursivley traversed up to the level abs(range). If range is negative the browser can automatically lower the range depending on system performance.

bboxSize bboxCenter addChildren removeChildren children have the same semantic as in the Group node.

 

Cell

Cell is a grouping node similarily to Group. The children field contain the geometry of the room.

The portals field specifies the list of Portals for the Cell

bboxSize bboxCenter addChildren removeChildren children have the same semantic as in the Group node.

The content field is for application use. A possible use is to define content types like water, closed space, normal space having different meaning of the application. (e.g. User can not walk into a Cell containing water.)

Portal

Portal specifies the portal's geometry aCell is a grouping node similarily to Group. The children field contain the geometry of the room.

The field enabled controls portal processing. If enabled is TRUE processing the Portal is active and will be check for visibility, if enabled is FALSE the Portal is not active, the portal is treated unvisible.

The field coord specifies a Coordinate node containing the 3D Polygon of the Portal.

The ccw field specifies the handedness of the polygon, see IndexedFaceSet ccw field for explanation.

The field cell points to a Cell node, its the cell which is seen throug the Portal.

BspTree

BspTree node is helper node structuring scene graphs in disjoint sets separated by a 3D plane.

The field plane specifies the plane.

 

Example:

 

Implementation notes:

C++/Javascript Pseudo Code:

 


// context variables

viewpoint;  	// the viewpoint position (eye) in local coordinates
viewFrustrum;   // current view frustrum, initially set of 5 planes: sides and far plane
clipVolume;     // temp culling frustrum for Cell
mode;       	// current traversal mode for BspTree / Cell


function CellGroup::traverse() 
{
    clipVolume = viewFrustrum; // initially what can be seen must be inside the current view frustrum

    activeCells.length = 0;


    // mark all cells as not visible
    for (i=0;i<cells.length;i++)
        cells[i].clipVolume=emptyVolume;
 
    // find the cell containing the viewpoint, ideally there is only 1
    // and check/add all cells connected through portals 
    findActiveCells(children);


    push viewFrustrum;

    // render each active cell, but use the cell's (smaller) frustrum
    // for object and portal culling 
    for (i=0;i<activeCells.length;i++) {
        setViewFrustrum(activeCells[i].clipVolume); 
        activeCells[i]->traverse();
    }
    pop viewFrustrum;
}


function findActiveCells(children) 
{
    // like normal traverse with special action for BspTree & Cell node

    mode = findActiveCellsTraverse;
    traverse(children);

    mode = normalTraverse;
}

function Cell::traverse() 
{

    if (mode == findActiveCellsTraverse) {  
            // once reaching here, cell is complete or partly visilbe
        // we add it to the list of active cells of the parent CellGroup
        addToActiveCells(this);

        // record / update the cell's clipVolume
        this.clipVolume = union(this.clipVolum,clipVolume);

        for (i=0;i<portals.length;i++)
            portals[i]->traverse();

        return  stop_traversal;     
    } else 

        traverse(children);
}

function Portal::traverse() 
{
    var resultPoly;
    if (!enabled) return; // portal is not enabled, so can't view into cell
    if (!cell) return; //  portal does not point to a cell, so nothing visible

    // if Portal polygon is backfacing, cell can't be seen
    if (isBackfacing(viewpoint,PlaneOf(coord,ccw)) return;

    // if Portal polygon totally clipped by current clipVolume, cell can't be seen
    if (!ClipPolyAgainstFrustrum(coord,clipVolume,resultPoly)) return;
    
    push clipVolume

    // create new smaller frustrum through edges of result poly, viewpoint and zfar plane
    clipVolume = buildClipVolumeForPoly(resultPoly); 

    cell->traverse();
    pop clipVolume;
}

function BspTree::traverse() 
{
    if (mode == findActiveCellsTraverse) {
        status=PointPlaneStatus(viewpoint,plane);

        if (status == INSIDE) traverse(front)
        else if (status == OUTSIDE) traverse(back)
        else traverse(overlap)

    } else //  generic mode 
        status=ViewfrustrumPlaneStatus(viewfrustrum,plane);
        // optionally check viewfrustrum against againts plane & cull children
        if (status == INSIDE) {
            traverse(overlap)
            traverse(front)
        } else 
        if (status == OUTSIDE) {
            traverse(back)
            traverse(overlap)
        } else{
            traverse(back)
            traverse(overlap)
            traverse(front)
        }
    }
}

traverse(MFNode v)
{
    for (i=0;i<v.length;i++)
        v[i]->traverse();

}

traverse(SFNode v)
{

   if (v) v->traverse();

}

function PointPlaneStatus(p,plane) 
{
    f = p.x * plane[0] + p.y * plane[1] + p.z * plane[2] + plane[3];

    if (f<0) return INSIDE;
    if (f>0) return OUTSIDE;
    return OVERLAP;
}

 

Issues:

The Cell->Portal->Cell structure introduces an arbitrary cyclic graph of nodes. Should Portal use an SFInt32 instead of SFNode to reference the target cell by number in the parent Cell group ?

If the CellGroup node is going to be deleted from browser memory the browser can set all portals fields of the Cell nodes refered by he cell field to NULL, in order to break any cyclic node references.

If the same cells is viewed through several portals instead of computing cell.clipVolume = union(cell.clipVolume); cell.clipVolume can be set to the initial (viewFrustrum) clipVolume. Also the content author could avoid some cases "several portals" to the same cell, by defining a larger portal polygon covering several geometric windows.

The BspTree node definitions should better be :

BspTree { 
    exposedField SFVec3f normal  0 0 1 
    exposedField SFFloat distance 0 
    exposedField SFNode front    NULL 
    exposedField SFNode back NULL 
} 

Portal Node: In addition to Cell the nodes Switch Group LOD are allowed in the cell field if they contain Cell nodes.

A nice feature would be to predefine some Cell content types, e.g. content = -1, the Browser does not allow to navigate into this area, content = -2, the space is water, navigationSpeed is set to half speed.

A specific problem is the authoring of the Cell Portal structures. Games like Quake have tools for subdividing the game level in bsp tree sorted convex subspaces and building the visibility structure. In other approaches authors need to indicate the different cell's and flag portal poygons.

 

Examples for BS Contact 4.4 and up:

8*8 script generated in-door grid scene : roomsobj_portal.wrl

16*16 script generated out-door scene (with visibilityLimit) : roomsobj_portal_outside.wrl

The culling rate can be observed using the F7 key, one number represents the number of primitives (IndexedFaceSet's) displayed after all culling. (ViewFrustrum, Cell & Portal culling.)

Output from from roomsobj_portal with tracking of the user : roomsobj_portal_out.wrl using the activeCells eventOut from CellGroup.
The name of the cell the user is inside and the number of totall rendered cells is printed to the console.

For comparison scenes using only BspTree but not Cells & Portals :
8*8 script generated in-door scene : rooms_bsp.wrl
12*12 script generated in-door scene with fog: rooms_bsp_1212.wrl


References:

  1. Faster 3D Game Graphics by Not Drawing What Is Not Seen Kenneth E. Hoff III. ACM Crossroads, 1997.
  2. Portals and Mirrors: Simple, Fast Evaluation of Potentially Visible Sets David P. Luebke and Chris Georges Department of Computer Science University of North Carolina at Chapel Hill
  3. Fipcode.com Building a portal engine
  4. Visibility Computations and Hidden Surface Removal at unc
  5. Adding Regions to VRML Bernie Roehl
  6. Unreal zones Epic games
  7. Contact BSP Tree node

Example structure:

This is the scene graph for set of 2*2 rooms connected with doors:


 CellGroup {
     cells [
         DEF C0_0 Cell {
             children [
                 
             ]
             portals [
                 DEF PC1_0 Portal {
                     coord Coordinate {point [70 14.5 28,70 14.5 42,70 0 42,70 0 28]}
                     cell DEF C1_0 Cell {
                         children [

                         ]
                         portals [
                             DEF PC1_1 Portal {
                                 coord Coordinate {point [112 14.5 70,98 14.5 70,98 0 70,112 0 70]}
                                 cell DEF C1_1 Cell {
                                     children [
                                        
                                     ]
                                     portals [
                                         DEF PC1_0_1 Portal {
                                             coord Coordinate {point [98 14.5 70,112 14.5 70,112 0 70,98 0 70]}
                                             cell USE C1_0
                                         },
                                         DEF PC0_1 Portal {
                                             coord Coordinate {point [70 14.5 112,70 14.5 98,70 0 98,70 0 112]}
                                             cell DEF C0_1 Cell {
                                                 children [
                                                     
                                                 ]
                                                 portals [
                                                     DEF PC0_0 Portal {
                                                         coord Coordinate {point [28 14.5 70,42 14.5 70,42 0 70,28 0 70]}
                                                         cell USE C0_0
                                                     },
                                                     DEF PC1_1_1 Portal {
                                                         coord Coordinate {point [70 14.5 98,70 14.5 112,70 0 112,70 0 98]}
                                                         cell USE C1_1
                                                     },

                                                 ]
                                             }
                                         }
                                     ]
                                 }
                             },
                             DEF PC0_0_1 Portal {
                                 coord Coordinate {point [70 14.5 42,70 14.5 28,70 0 28,70 0 42]}
                                 cell USE C0_0
                             }
                         ]
                     }
                 },
                 DEF PC0_1_1 Portal {
                     coord Coordinate {point [42 14.5 70,28 14.5 70,28 0 70,42 0 70]}
                     cell USE C0_1
                 }
             ]
         },
         USE C0_1,
         USE C1_0,
         USE C1_1
     ]
     children BspTree {
         plane 1 0 0 -70
         front BspTree {
             plane 0 0 1 -70
             front USE C0_0
             back USE C0_1
         }
         back BspTree {
             plane 0 0 1 -70
             front USE C1_0
             back USE C1_1
         }
     }
 }