NOTE: As of April 2002, we have rewritten the primary scene graph interface to Panda, which invalidates almost all of the contents of this document. We hope to be providing an updated document soon. In the meantime, this document remains, and may be useful for historical purposes. Panda has two primary modes of rendering: with or without a separate "Cull" traversal. In the simplest case, Panda renders directly, without a separate Cull traversal. In this case, the scene graph is traversed with a simple depth-first, left-to-right in-order traversal, and GeomNodes are sent to the graphics engine as they are encountered. When operating in this mode, the only way to control render order is to adjust the order of nodes within the hierarchy. It is possible to do this by either building the hierarchy in a specific order (each reparenting operation in the scene graph appends the new node to the end of its parent's children list), or more explicitly, by setting a sort order on each arc as it is created or moved (the NodePath reparenting methods support an optional sort parameter, and the NodeRelation class has a set_sort() method). Normally the sort order on each arc is zero, but it may be explicitly set to any integer. A node's list of children will always be kept in order from lowest to highest sort order, and where siblings have an equal sort order, they will be arranged in the order in which they were added. More commonly, Panda is operated using a Cull traversal. This traversal makes a complete pass through the scene graph before rendering anything, collecting together all the GeomNodes that are to be rendered and arranging them in a suitable order before passing them to the graphics engine. It is somewhat inappropriately named; although it does do view-frustum culling, so does the simpler direct traversal; it should more properly be called the State Sorting traversal. When the Cull traversal is in use, the hierarchy order is irrelevant. Instead, the Cull traversal uses a binning system to support user control of the order in which things are rendered. As the Cull traversal encounters GeomNodes, it assigns each one to a particular bin, identified by name. These bins are selected by setting a GeomBinTransition above the arc in question, or by calling NodePath::set_bin(). After all the GeomNodes have been identified, the various bins are sorted in order according to each bin's sort index, which is specified by GeomBin::set_sort(). This is an arbitary integer assigned to each bin, and the lower-number bins are drawn first. Each bin is then responsible for drawing its contents--the set of GeomNodes assigned to it--in whatever order it likes. The various kinds of bins render their GeomNodes in different ways: GeomBinStateSorted -- collects together all GeomNodes that share a common state and renders them at once, before switching to the next group of GeomNode with a common state. Attempts to minimize the state changes between groups of GeomNodes. The goal of this bin is to minimize the number of state changes sent to the graphics engine, and so reduce rendering overhead. GeomBinBackToFront -- renders everything in order from the furthest away to the closest. This is generally necessary for correct transparent and semitransparent rendering. The ordering is based on the center of each GeomNode's bounding volume, relative to the camera plane. GeomBinNormal -- assigns each GeomNode to one of two sub-bins: transparent geometry is assigned to a GeomBinBackToFront, while opaque geometry is assigned to a GeomBinStateSorted. This is the kind of bin that 'default' is defined to be; it is the bin that all GeomNodes are assigned to when no other bin is explicitly specified. GeomBinUnsorted -- renders everything in no particular order. GeomBinFixed -- renders everything according to a user-specified order, potentially per GeomNode. Each GeomBinTransition that specifies a GeomBinFixed bin may also include an optional sort order (this is an optional second parameter to the GeomBinTransition constructor, as well as to NodePath::set_bin()); the GeomBinFixed will render low-number nodes before high-number nodes. If no bin is explicitly specified, each GeomNode is assigned to a bin named 'default', which is of type GeomBinNormal; this bin is created at startup and contains two sub-bins, one for transparent geometry and one for nontransparent geometry. The nontransparent bin is rendered first, with its contents in state-sorted order, followed by the transparent bin, with its contents in order from back to front. This usually provides correct behavior for transparent and semitransparent objects, which must generally be rendered after everything behind them has already been rendered. However, this sometimes fails, particularly with large, flat polygons stacked closely in front of one another. In cases like these it may be necessary to explicitly specify an ordering. There is another predefined bin available called 'fixed'. Nothing will ever be rendered in 'fixed' (or any other bin, other than 'default') unless it is explicitly assigned to it. The 'fixed' bin is of type GeomBinFixed, and renders its objects according to a fixed ordering, specified as the second parameter to the GeomBinTransition constructor, or to NodePath::set_bin(). There is also another predefined bin called 'background', which is another bin of type GeomBinFixed. The order of all the predefined bins (and their predefined sort orders) is as follows: 10 - 'background' : GeomBinFixed 20 - 'default' : GeomBinNormal (opaque sub-bin) 30 - 'default' : GeomBinNormal (transparent sub-bin) 40 - 'fixed' : GeomBinFixed Thus, the 'fixed' bin can be used for things that must be rendered correctly relative to each other, but should render after all other things in the scene graph, while the 'background' bin can be used for things that must render before other transparent things in the scene graph (it's particularly useful for large, flat polygons on the horizon). Other bins may easily be defined, either at run time or via a line in a Configrc file. It is also possible to redefine any of the predefined bins by defining a new bin with the same name. To define a bin via the Configrc file, add a line beginning with "cull-bin" and consisting of three space-separated fields: the name of the bin, the bin sort order, and the type of bin. For example, to create an bin called 'shadow' to render shadows in no particular order, but before any other transparent objects are rendered, you may add the line: cull-bin shadow 25 unsorted The valid bin types are normal, unsorted, state-sorted, fixed, or back-to-front. To define a bin at run time, you simply create a bin of the appropriate type using its constructor, and then assign it to the current render traverser via GeomBin::set_traverser(). To do this, you must get a pointer to the current traverser via GraphicsStateGuardian::get_render_traverser(). This will either be a DirectRenderTraverser or a CullTraverser. A GeomBin may only be assigned to a CullTraverser. If the current render traverser is not a CullTraverser, then Panda is operating without a Cull traversal, and you cannot meaningfully assign things to GeomBins anyway. For example, the following Python code creates the same GeomBin defined above: shadowBin = GeomBinUnsorted('shadow') shadowBin.setSort(15) try: shadowBin.setTraverser(win.getGsg().getRenderTraverser()) except: pass The try .. except block is a good idea to protect against the case in which getRenderTraverser() does not return a CullTraverser.