Re: postCull callbacks aren't being called

New Message Reply Date view Thread view Subject view Author view

John Rohlf (jrohlf++at++tubes)
Wed, 19 Apr 95 13:34:10 PDT


>
> I'm implementing run-time cell-portal visibility in Performer. Here's the
> idea: the scene is divided into adjacent cells, which can only see each
> other through transparent portals that connect the cells. At the root of the
> scene is the pfGroup containing the viewer's cell. Under that cell are
> the portals of the cell, which I've implemented as pfGroups with pre-
> and post-callbacks attached. The precallback is called preCullPortal;
> it tests to see if the portal is visible; if so, the callback attaches
> the cell on the other side to the portal pfGroup with pfAddChild(), and
> returns PFTRAV_CONT. PostCullPortal() is responsible for removing the
> attached cell from the pfGroup that represents the portal.
>
> So here's my problem: after a nested series of prePortalCull() calls,
> postPortalCull() seems to be called only once, for the most recently
> visited portal node. As a result the cells attached to the rest of the
> portals never get removed, and those portals thereby inherit another
> child each frame. My question is, why might the traversal mechanism
> be skipping every postPortalCull after the first call? I've checked
> carefully and I'm quite sure that the correct callbacks are assigned
> to all the appropriate nodes. Any ideas?
>
> I know this probably isn't very clear. Here's the relevant portions of
> my code:
>
> typedef struct
> {
> int numverts; /* Number of verts in the portal */
> pfGroup *attached_cell; /* cell on the 'other side' */
> pfVec3 verts[MAXPORTALVERTS]; /* The actual vertices */
> } pfPortalData;
>
> long
> enterPortalCull(pfTraverser *trav, void *data)
> {
> pfChannel *chan; /* pfChannel derives from pfFrustum */
> pfGroup *node;
> pfPortalData *p = (pfPortalData *) data;
>
> if (!globalUsePortals) /* First, are portals enabled? */
> {
> DEBUG(("\tPortals aren't enabled; pruning.\n"));
> return PFTRAV_PRUNE;
> }
> node = (pfGroup *) pfGetTravNode(trav);
>
> chan = pfGetTravChan(trav); /* Get the current view frustum */
> if (chan == NULL) /* If this is an intersection, prune */
> {
> return PFTRAV_PRUNE;
> }
> ...
> /* First test the normal of the portal to see if its backfacing */
> ...
> /* Next test the portal to see if its visible */
> ...
> if (it's not visible)
> return PFTRAV_PRUNE;
>
> /* It's visible, go ahead and traverse the other side */
> pfAddChild(node, p->attached_cell);
> return PFTRAV_CONT;
> }

>
> long
> exitPortalCull(pfTraverser *trav, void *data)
> {
> pfPortalData *p = (pfPortalData *) data;
> pfChannel *chan;
> pfGroup *node;
>
> if (!globalUsePortals) /* First, are portals enabled? */
> return PFTRAV_PRUNE; /* I think this is ignored */
>
> chan = pfGetTravChan(trav); /* Get the current view frustum */
> node = (pfGroup *) pfGetTravNode(trav);
>
> if (chan == NULL) /* If this is an intersection, prune */
> return PFTRAV_PRUNE; /* I think this is ignored */
>
> pfRemoveChild(node, p->attached_cell);
> return PFTRAV_CONT; /* I think this is ignored */
> }
>
>
        You have found a bug in the traversal logic.
pfGetTravNode(trav) returns the last child of the group to postCull()
rather than the group itself (preCull() is OK). You could use

        node = pfGetChild(pfGetParent(pfGetTravNode(trav), 0), 0)

if you know that the portal group is always the first child.
         
        However, I suggest you try a different approach which does
not modify the scene graph during traversal. The culling traversal does
not understand all topological changes to the scene graph during the
traversal. We could make it a little more
aware but in general changing the scene graph during a traversal
is a bit risky as well as hard to define, e.g.:

pfGroup::cull()
{
        for (i=0; i<childList.getNum(); i++)
                childList[i]->cull();
}

What should happen if child 0 removes itself from the graph in its
preCull callback? The act of removing child 0 shifts children 1 through n-1
to the left by one. Then i++ will increment i to 1 so that the
new child 0, which used to be child 1, will be skipped and will
not be culled.

        Why not attach the callbacks to attached_cell? Then you can
call pfCullResult(PFIS_FALSE) or pfCullResult(PFIS_MAYBE | PFIS_TRUE)
in the preCull callback if the cell is not visible or visible respectively.
pfCullResult is the intended mechanism for your kind of culling.

        Note that PFTRAV_PRUNE is indeed ignored in the postCull()
since you've already traversed the group's children. If you want
to aggressively terminate traversal, return PFTRAV_TERM but use
this with caution.


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:51:24 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.