| 1 |
#include <OSGConfig.h> |
|---|
| 2 |
|
|---|
| 3 |
using namespace OSG; |
|---|
| 4 |
|
|---|
| 5 |
/*! \defgroup GrpSystemNodeCores NodeCores |
|---|
| 6 |
\ingroup GrpSystem |
|---|
| 7 |
|
|---|
| 8 |
See \ref PageSystemNodesNCores for details. |
|---|
| 9 |
|
|---|
| 10 |
*/ |
|---|
| 11 |
|
|---|
| 12 |
/*! \page PageSystemNodesNCores Nodes & NodeCores |
|---|
| 13 |
|
|---|
| 14 |
\latexonly Starter:NewChapter \endlatexonly |
|---|
| 15 |
|
|---|
| 16 |
Of course the most important structures in a scene-graph are the actual nodes |
|---|
| 17 |
that make up the graph. |
|---|
| 18 |
|
|---|
| 19 |
OpenSG uses a somewhat different approach than many other systems. A |
|---|
| 20 |
node is split into two parts: the Node and a NodeCore, both of which |
|---|
| 21 |
are FieldContainers, so all that has been said before applies to them. |
|---|
| 22 |
|
|---|
| 23 |
A Node keeps the general information: a children list, a parent pointer, a |
|---|
| 24 |
bounding volume and a core pointer. Note that the node itself contains no |
|---|
| 25 |
information about its type (e.g. transform, group, etc.). A Node cannot be |
|---|
| 26 |
shared, every node can only be at one place in the graph, thus a single parent |
|---|
| 27 |
pointer is enough. All nodes together define the topology of the graph, |
|---|
| 28 |
without defining any content. Actions that depend on a position in the graph, |
|---|
| 29 |
like accessing the accumulated matrix to the world coordinate system or the |
|---|
| 30 |
world bounding volume, have to be done on the node, as it uniquely defines and |
|---|
| 31 |
identifies the position in the graph. |
|---|
| 32 |
|
|---|
| 33 |
Additionally, Nodes contain a traversal mask. When traversing a graph (see |
|---|
| 34 |
\ref PageActions) some parts of the graph can be left out. To do that the |
|---|
| 35 |
logical and of the Node's traversal mask and the Action's traversal mask is |
|---|
| 36 |
checked if it's 0. If it is, the Node and all its descendents are not |
|---|
| 37 |
traversed, otherwise they are. This allows splitting the graph into logical |
|---|
| 38 |
partitions, that are only use for some actions (e.g. have a separate set of |
|---|
| 39 |
moedls for ray intersection). To use this for rendering the osg::Viewport also |
|---|
| 40 |
has a traversal mask that is used for rendering it. |
|---|
| 41 |
|
|---|
| 42 |
A NodeCore carries the differentiating information for a node. There are |
|---|
| 43 |
NodeCores for all the different functions needed in the tree: groups, |
|---|
| 44 |
transformations, geometry and many more. NodeCores can be shared between |
|---|
| 45 |
different nodes, thus they keep an array or actually a MultiField of Node |
|---|
| 46 |
pointers. |
|---|
| 47 |
|
|---|
| 48 |
\image html node_core_share.png "Node & Node Core Sharing" |
|---|
| 49 |
\image latex node_core_share.eps "Node & Node Core Sharing" width=8cm |
|---|
| 50 |
|
|---|
| 51 |
The types of NodeCores using in OpenSG are divided into two large groups: |
|---|
| 52 |
Groups (\ref PageSystemNCGroups) and Drawables (\ref PageSystemNCDrawables). |
|---|
| 53 |
|
|---|
| 54 |
Thus to create a node to be put into a scene graph you need both a osg::Node |
|---|
| 55 |
as well as a osg::NodeCore. To simplify creating these there are two |
|---|
| 56 |
convenience functions. |
|---|
| 57 |
|
|---|
| 58 |
osg::makeCoredNode is a templated function to creates a NodeCore of the |
|---|
| 59 |
given type as well as a Node that goes with it and returns the NodePtr. |
|---|
| 60 |
|
|---|
| 61 |
\example To create a Group node you need to do this: |
|---|
| 62 |
|
|---|
| 63 |
\code |
|---|
| 64 |
NodePtr gr = makeCoredNode<Group>(); |
|---|
| 65 |
\endcode |
|---|
| 66 |
|
|---|
| 67 |
\endexample |
|---|
| 68 |
|
|---|
| 69 |
\example It is |
|---|
| 70 |
also possible to get access to the created NodeCore: |
|---|
| 71 |
|
|---|
| 72 |
\code |
|---|
| 73 |
TransformPtr tr; |
|---|
| 74 |
NodePtr gr = makeCoredNode<Transform>(&tr); |
|---|
| 75 |
\endcode |
|---|
| 76 |
|
|---|
| 77 |
\endexample |
|---|
| 78 |
|
|---|
| 79 |
makeCoredNode allows the creation from scratch, in addition to that |
|---|
| 80 |
there is makeNodeFor(), which allows creating a new Node for an existing |
|---|
| 81 |
NodeCore, that might come from somewhere else: |
|---|
| 82 |
|
|---|
| 83 |
\code |
|---|
| 84 |
TransformPtr tr = Transform::create(); |
|---|
| 85 |
NodePtr gr = makeNodeFor(tr); |
|---|
| 86 |
\endcode |
|---|
| 87 |
|
|---|
| 88 |
Even with these convenience functions it is still necessary to carry |
|---|
| 89 |
around two objects and two variable to manipulate the Node and the |
|---|
| 90 |
NodeCore. As this can becomne rather tedious in larger applications, |
|---|
| 91 |
there is a wrapper class that combines the two, the CoredNodePtr. |
|---|
| 92 |
|
|---|
| 93 |
As the name implies, the CoredNodePtr is an extended NodeCorePtr that |
|---|
| 94 |
internally handles the NodePtr. Due to cast operators it can be used |
|---|
| 95 |
everywhere a normal NodeCorePtr can. |
|---|
| 96 |
|
|---|
| 97 |
In addition to that, the CoredNodePtr features automatic refernce |
|---|
| 98 |
counting in the way of s smart pointer. Thus the user doesn't have to |
|---|
| 99 |
and shouldn't explicitly change the reference counts of the objects |
|---|
| 100 |
assigned to a CoredNodePtr, a simple NullFC assignment will be enough to |
|---|
| 101 |
clear them out. |
|---|
| 102 |
|
|---|
| 103 |
It can not totally hide the distinction between Nodes and Cores, thus in |
|---|
| 104 |
places where the NodePtr is needed (e.g. to add children to it), it has |
|---|
| 105 |
to be accessed explicitly using the node() member function. Also the |
|---|
| 106 |
begin/endEdit calls on the CoredNodePtr are not as efficient as the |
|---|
| 107 |
calls on the NodePtr or NodeCorePtr, as they have to begin/end both the |
|---|
| 108 |
Node and the Core using the given mask, which might result in |
|---|
| 109 |
unnecessary changes being recorded. |
|---|
| 110 |
|
|---|
| 111 |
\example The following code creates a torus geometry with a |
|---|
| 112 |
transformation on top and deletes it afterwards: |
|---|
| 113 |
|
|---|
| 114 |
\code |
|---|
| 115 |
typedef CoredNodePtr<Transform> TransformNodePtr; |
|---|
| 116 |
typedef CoredNodePtr<Geometry> GeometryNodePtr; |
|---|
| 117 |
|
|---|
| 118 |
GeometryNodePtr torus = makeTorusGeo( .5, 2, 8, 12 ); |
|---|
| 119 |
TransformNodePtr t = TransformNodePtr::create(); |
|---|
| 120 |
|
|---|
| 121 |
beginEditCP(t, Transform::MatrixFieldMask | Node::ChildrenFieldMask); |
|---|
| 122 |
{ |
|---|
| 123 |
t->setMatrix(Matrix::identity()); |
|---|
| 124 |
t.node()->addChild(torus.node()); |
|---|
| 125 |
} |
|---|
| 126 |
endEditCP(t, Transform::MatrixFieldMask | Node::ChildrenFieldMask); |
|---|
| 127 |
|
|---|
| 128 |
// This keeps the torus in the graph still alive, due to refcounts |
|---|
| 129 |
torus = NullFC; |
|---|
| 130 |
|
|---|
| 131 |
// This kills the whole graph, includiong the torus |
|---|
| 132 |
t = NullFC; |
|---|
| 133 |
|
|---|
| 134 |
\endcode |
|---|
| 135 |
|
|---|
| 136 |
\endexample |
|---|
| 137 |
|
|---|
| 138 |
*/ |
|---|