open_toontown_panda3d/panda/src/doc/howto.control_render_order

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.