IRIX 6.5 » Books » Developer »
OpenGL Optimizer Programmer's Guide: An Open API for Large-Model Visualization
(document number: 007-2852-002 / published: 1998-06-09)
table of contents | additional info | download find in page
Chapter 12. Traversing a Large Scene Graph
This chapter and Chapter 13, “Manipulating Triangles and Rebuilding Renderable Objects,” discuss methods to efficiently manipulate (parts of) a scene graph with extensible traversers. The OpenGL Optimizer tools fall in two general categories:
Tools that essentially focus on the scene graph manipulation, which are discussed in this chapter
Tools that coordinate scene-graph tasks as well as other tasks in a multiprocessor environment, which are discussed in the next chapter
You define OpenGL Optimizer traversals with callbacks held in a traversal object. The control provided by the callbacks allows you to do the following:
Specify the effect when a traverser visits a node.
Control the progress of the traversal, that is, which node to visit next.
Delete the traversal object when you are through with it.
This chapter consists of the following sections:
Traversals and Callbacks: General Features
Traversing a scene graph means “visiting” nodes in some sequence and invoking a callback as each node is visited. Callbacks allow you to perform operations whenever a node is visited during a traversal; for example, you can count nodes, render objects, or compute the volume of objects in a scene.
OpenGL Optimizer provides tools for two scene-graph traversal sequences: depth first or breadth first.
Depth-First Traversal Sequence
To picture depth-first traversals, imagine the path you would take if the links between nodes in a scene graph were hallways and you walk through the scene graph holding your right hand on a wall. Nodes would be rooms, and you would continue to hold your hand on the wall as you walked through the room. Callbacks are made each time you enter a room, except when the hand-on-the-wall rule returns you to a parent node before visiting all its children: a callback is made when you first “descend” into the parent node and after you “ascend” from the last child.
Figure 12-1 shows a depth-first traversal of a simple scene graph. The solid circles in the figure indicate pre-node callbacks, which are implemented when a traversal first visits a node. The solid squares indicate post-node callbacks, which are implemented as a traversal leaves a node.
Notice that a depth-first traversal visits each parent node twice, once before and once after visiting its children. A depth-first traversal is inherently sequential and so cannot be reasonably executed by more than one process; the ordering of actions, particularly when parents are visited after their children, is best maintained by one process.
Breadth-First Traversal Sequence
The central concept of a breadth-first traversal is that the traverser visits the nodes at a given level and proceeds to a lower level in the scene graph after all the nodes at a higher level have been visited. Figure 12-2 shows a breadth-first traversal of a simple scene graph. The solid circles in the figure indicate per-node callbacks, which are implemented when a traverser first visits a node.
Some features such as a multiprocess traversal or nodes with multiple parents, can complicate the sequence of nodes visited in a bread-first traversal. In those cases, the simple left-right, top-to-bottom sequence may not hold exactly.
When a breadth-first traversal is executed by several processes, or when nodes in the graph have several parents, a simple rule guarantees a reasonable sequence of events: the traversal does not visit children until it visits at least one of the parents. Whenever a parent node is encountered by a traverser, it places the node's children at the end of the processing queue.
Callbacks During a Traversal
During a traversal an instance of an action object performs and specifies the following basic operation:
Call a begin() method to establish any context you might want for the traversal.
Visit the scene-graph nodes in sequence.
Perform the appropriate callback at each node and determine how the traversal is to proceed.
Delete or retain the action object as specified by the return value of the action object's member function end().
You have two controls over how a traversal proceeds:
The return values of the node-visiting callbacks, which allow you to continue, stop, or remove the children of a node from the traversal.
The node argument of the callback, which is passed by reference, and provides great freedom in determining the specific node that is next in the traversal.
Controlling a Traversal With the Callback Return Value opTravDisp
The possible return values of callbacks, and the method apply() which initiates a traversal callback sequence, are set by the enumerated type opTravDisp whose values determine whether the traversal should continue, skip over the children of the current node, or stop.
This is the type definition for opTravDisp:
typedef enum {opTravCont=0, opTravPrune=1, opTravStop=2} opTravDisp;
|
Specifying Deletion of Traversal Object Storage: opActionDisp
After you complete a traversal, you can keep the object for subsequent use, or free storage assigned to the traversal object. For example, you may repeatedly use a cull traverser, invoking it each frame, but you may perform a tessellation traversal only once.
To specify whether a traversal object remains in memory after the traversal stops, specify the return value of the last callback, end(). The possible values are set by the enumerated type opActionDisp. This is the declaration for opActionDisp:
typedef enum {opDeleteThis, opKeepThis} opActionDisp;
|
Depth-First Traversals: opDFTravAction
The class opDFTravAction is used for a depth-first traversal of the scene graph. Parent nodes are visited at least twice, before and after their children are visited with a different callback for each visit (see “Depth-First Traversal Sequence”).
Class Declaration for opDFTravAction
The class has the following main methods:
class opDFTravAction : public opAction
{
public:
opDFTravAction();
virtual ~opDFTravAction();
opTravDisp apply(csNode *root);
virtual void begin (csNode *& , const opActionInfo&);
virtual opTravDisp preNode (csNode *&, const opActionInfo&);
virtual opTravDisp postNode(csNode *&, const opActionInfo&);
virtual opActionDisp end (csNode *&, const opActionInfo&);
};
|
Methods in opDFTravAction
| apply() | | Initiates a traversal below root.
|
The following table lists callbacks, where they are applied, and what they do (see also “Depth-First Traversal Sequence”):
Table 12-1. opDFTravAction Callbacks
Callback
| When Applied
| Notes
|
|---|
begin()
| Before the traverser visits any node.
| The csNode argument is the root of the
traversal. If the argument equals NULL,
the tree is empty and no traversal will
begin. The default for begin() does
nothing.
| preNode()
| Before visiting a node for the first
time or for each visit to a node before
visiting its children. The latter case
occurs, for example, when a parent is
itself the child of two parents; thus a
traverser could visit the node twice
during a traversal and apply
preNode() each time before visiting
the children.
| The default for preNode() returns
opTravCont, and thus simply continues
the traversal.
| postNode()
| After visiting a node's children.
| The default for postNode() returns
opTravCont and thus simply continues
the traversal.
| end(
node, info
)
| Once the traversal is completed or
halted by a callback.
| The node argument is the root of the scene
graph. The default for end() cleans up by
returning opDeleteThis, thus deleting the
opDFTravAction. To avoid deletion,
define end() to return the value
opKeepThis.
|
Note the following two features of the arguments you pass to preNode(), postNode(), and end():
The csNode pointer, which also appears as an argument for all of the callbacks, is passed by reference; thus you can change its value. This is useful when the scene graph changes during a traversal, typically when nodes have been added. The traverser “decides” where to go next by assuming the traversal is complete up to the current csNode.
The class opActionInfo, which appears as an argument for all the callback functions, is valid only if the traversal is initiated by the thread manager. opActionInfo is discussed in the section “Difference Between Interprocess Control Methods”.
Breadth-First Traversals: opBFTravAction
The class opBFTravAction is for a breadth-first traversal, which can be performed on one or several processors. All nodes are visited only once, typically, in contrast with an opDFTravAction, for which parent nodes are typically visited at least twice.
Class Declaration for opBFTravAction
The class has the following main methods:
class opBFTravAction : public opAction
{
public:
opBFTravAction();
virtual ~opBFTravAction();
opTravDisp apply(csNode *root);
void applyMP(csNode *root,
opThreadMgr *tm,
const opTIDSet& tids = opTIDSet::opAllTIDs,
opPriority p = Optimizer::opDefaultPriority);
virtual void begin (csNode *&, const opActionInfo& );
virtual opTravDisp perNode(csNode *&, const opActionInfo& ):
virtual opActionDisp end (csNode *&, const opActionInfo& );
};
|
Methods in opBFTravAction
The following table lists callbacks, where they are applied, and what they do (see also “Breadth-First Traversal Sequence”):
Table 12-2. opBFTravAction Callbacks
Callback
| When Applied
| Notes
|
|---|
begin()
| Before the traverser visits any node.
| The csNode argument is the root of the
traversal. If the argument equals NULL,
the tree is empty and no traversal will
begin. The default for begin() does
nothing.
| perNode()
| Is applied as the traverser visits each
node
| A return value of opTravStop stops the
traversal at the current node. A return
value of opTravStop is equivalent to
opTravPrune, thus eliminating from the
traversal whatever children the current
node may have. The default for
perNode() returns opTravPrune and thus
skips any of the node's children.
| end(
node, info
)
| Once the traversal is completed or
halted by a callback.
| The node argument is the root of the scene
graph. The default for end() cleans up by
returning opDeleteThis, thus deleting the
opDFTravAction. To avoid deletion,
define end() to return the value
opKeepThis.
|
The callbacks are applied at these points of the traversal (see ):
As for an opDFTravAction, the scene-graph-node callback arguments can be modified to change the course of the traversal and opActionInfo arguments are only valid if the traversal is initiated in a multi-threaded context by a thread manager.
Sample Traversal Function From the opoptimize Sample Application
The following code fragment illustrates the use of a traverser, and also shows how simplification traversal works.
OpenGL Optimizer does not provide a simplification traversal class, instead, an application can design its own traversal class to meet particular needs. The example below provides one approach: It defines a simplification traversal function that returns the root of a new, simplified scene graph.
The example performs two checks that are not usually needed for a traverser, but are necessary for a simplifier:
Some node-checking to determine whether a node is a csShape, and so could contain a csGeoSet to simplify
Some code to further check whether the csShape actually contains a csGeoSet.
These lines of code are taken from simplify.cxx and main.cxx in /usr/share/Optimizer/src/apps/opoptimize.
Traversing a Scene Graph and Applying a csDispatch: opDispatchAction
The class opDispatchAction is a csAction that, as it traverses a scene graph, applies a csDispatch to each node in a scene graph.
Recall that a csAction is a Cosmo3D object for traversing a scene-graph. The class csDispatch is an object designed to follow the “Visitor Behavioral Pattern,” which provides a convenient way to organize and define operations on scene graph elements. The Visitor Behavioral Pattern is described in Design Patterns, listed in “Recommended Background Reading”. A csDispatch is a “Visitor,” and subclasses are “Concrete Visitors.” This pattern is also used in Open Inventor; see The Inventor Toolmaker. For more information about csAction and csDispatch, see Cosmo 3D Programmer's Guide.
An example of an opDispatchAction is the tool for gathering scene graph statistics; see “Getting Statistics About a Scene Graph: opTriStats”.
Methods in opDispatchAction
| apply(csNode *node) | |
Is inherited from csAction. A call to apply() traverses the scene graph below node.
| | opDispatchAction(csDispatch *d) | |
Constructs the class and specifies the csDispatch to be applied during the traversal begun by a call to apply().
|
OpenGL Optimizer Programmer's Guide: An Open API for Large-Model Visualization
(document number: 007-2852-002 / published: 1998-06-09)
table of contents | additional info | download
Front Matter
About This Guide
Part I. Getting Started
Part II. High-Level Strategic Tools for Fast Rendering
Part III. Specific Tools for Fast Rendering
Part IV. Managing and Rendering Higher-Order Geometric Primitives
Part V. Traversers, Low-Level Geometry Processing, and Multiprocessing
Part VI. Utilities and Troubleshooting
Part VII. Appendices
Glossary
Index
home/search |
what's new |
help
|