168 lines
7.6 KiB
Plaintext
168 lines
7.6 KiB
Plaintext
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.
|
|
|
|
|