| 1 |
#include <OSGConfig.h> |
|---|
| 2 |
|
|---|
| 3 |
using namespace OSG; |
|---|
| 4 |
|
|---|
| 5 |
// the used groups |
|---|
| 6 |
|
|---|
| 7 |
/*! \defgroup GrpSystemNodeCoresDrawablesGeometry Geometry |
|---|
| 8 |
\ingroup GrpSystemNodeCoresDrawables |
|---|
| 9 |
|
|---|
| 10 |
Geometry is the primary leaf node of the tree. It wraps polygonal |
|---|
| 11 |
primitives as defined by OpenGLs glBegin()/glEnd() loops. See \ref |
|---|
| 12 |
PageSystemGeometry for a description. |
|---|
| 13 |
*/ |
|---|
| 14 |
|
|---|
| 15 |
/*! \defgroup GrpSystemDrawablesGeometryIterators Geometry Iterators |
|---|
| 16 |
\ingroup GrpSystemNodeCoresDrawablesGeometry |
|---|
| 17 |
|
|---|
| 18 |
Helpers to access Geometry in a generic way. See \ref PageSystemGeometryIterators |
|---|
| 19 |
for a description. |
|---|
| 20 |
*/ |
|---|
| 21 |
|
|---|
| 22 |
/*! \defgroup GrpSystemDrawablesGeometryFunctions Geometry Functions |
|---|
| 23 |
\ingroup GrpSystemNodeCoresDrawablesGeometry |
|---|
| 24 |
|
|---|
| 25 |
The GeoFunctions group contains different different functions to |
|---|
| 26 |
manipulate geometry. See \ref PageSystemGeoFunctions for a description. |
|---|
| 27 |
*/ |
|---|
| 28 |
|
|---|
| 29 |
/*! \defgroup GrpSystemDrawablesGeometryProperties Geometry Properties |
|---|
| 30 |
\ingroup GrpSystemNodeCoresDrawablesGeometry |
|---|
| 31 |
|
|---|
| 32 |
osg::GeoProperty is the wrapper class for the geometry's attributes. They |
|---|
| 33 |
encapsulate and abstract the specific types of the attributes and offer an |
|---|
| 34 |
interface that is targeted at glVertexArrays. To simplify usage they also |
|---|
| 35 |
have a generic interface, which is easy to use, but not as efficient as |
|---|
| 36 |
the specific one. |
|---|
| 37 |
|
|---|
| 38 |
The class hierarchy for the Properties looks very complicated, but |
|---|
| 39 |
isn't really, templates and traits are just not easy to handle in doxygen. |
|---|
| 40 |
See \ref PageSystemGeoPropertyClasses for a description. |
|---|
| 41 |
|
|---|
| 42 |
*/ |
|---|
| 43 |
|
|---|
| 44 |
/*! \defgroup GrpSystemDrawablesGeometrySimpleGeometry Simple Geometry |
|---|
| 45 |
\ingroup GrpSystemNodeCoresDrawablesGeometry |
|---|
| 46 |
|
|---|
| 47 |
SimpleGeometry combines a number of functions to create some specialized |
|---|
| 48 |
geometry very easily. See \ref PageSystemSimpleGeometry for a description. |
|---|
| 49 |
*/ |
|---|
| 50 |
|
|---|
| 51 |
// the page(s) |
|---|
| 52 |
|
|---|
| 53 |
/*! \page PageSystemGeometry Geometry |
|---|
| 54 |
|
|---|
| 55 |
Geometries in most cases define what's being rendered. Note that Geometries |
|---|
| 56 |
don't necessarily have to be leaves of the tree, as due the Node/Core divison |
|---|
| 57 |
every Node keeping a osg::Geometry Corehas children anyway, which are used |
|---|
| 58 |
just as all other osg::Node's children. Geometry has to be flexible, to |
|---|
| 59 |
accommodate the needs of the application. Different data types for the data |
|---|
| 60 |
that defines the geometry are useful, as well as different indexing |
|---|
| 61 |
capabilities to reuse data as much as possible. On the other hand, it also has |
|---|
| 62 |
to be efficient to render. Flexibility and performance don't always go well |
|---|
| 63 |
together, thus, there are some simplifications to make. |
|---|
| 64 |
|
|---|
| 65 |
\section PageSystemGeoProperties Properties |
|---|
| 66 |
|
|---|
| 67 |
OpenSG geometry is modeled closely following OpenGL. The data that make up the |
|---|
| 68 |
geometry are stored in separate arrays. Positions, Colors, Normals and Texture |
|---|
| 69 |
Coordinates all have their own arrays, (or osg::MField, to stay in OpenSG |
|---|
| 70 |
terminology). As OpenGL can handle a lot of different formats for the data, |
|---|
| 71 |
some of which might be more appropriate due to speed and memory consumption |
|---|
| 72 |
than others, depending on the application, OpenSG features different versions |
|---|
| 73 |
of this data, allowing pretty much all the variants that OpenGL can handle. To |
|---|
| 74 |
allow that with type safety and without having a separate geometry class for |
|---|
| 75 |
every possible combination the data fields are stored in separate field |
|---|
| 76 |
containers, a so called osg::GeoProperty. There are separate osg::GeoProperty for |
|---|
| 77 |
different attributes, and variants for different data types for each kind of |
|---|
| 78 |
osg::GeoProperty. The most prominent types are probably osg::GeoPositions3f for osg::Pnt3f |
|---|
| 79 |
positions, osg::GeoNormals3f for osg::Vec3f normals, osg::GeoColors3f for osg::Color3f colors and |
|---|
| 80 |
osg::GeoTexCoords2f for osg::Vec2f texture coordinates, but other variants are |
|---|
| 81 |
possible. |
|---|
| 82 |
|
|---|
| 83 |
As properties only have a single field they can mimic that field by exposing |
|---|
| 84 |
parts of the standard osg::MField interface for their contents, so you can use |
|---|
| 85 |
a GeoProperty pretty much just like an osg::MField. One problem with the type |
|---|
| 86 |
variety is that writing functions that work on every type of property can |
|---|
| 87 |
become tedious, as you have to have a big switch for every kind of data that |
|---|
| 88 |
could arrive. To make that easier for every property there is defined generic |
|---|
| 89 |
format, e.g. for Positions the format is osg::Pnt3f. A property has a |
|---|
| 90 |
getValue()/setValue() interface for these generic types, i.e. every property, |
|---|
| 91 |
no matter in what format it stores the data, can be used as if it used the |
|---|
| 92 |
generic format. Of course, this is not as efficient as directly accessing the |
|---|
| 93 |
data, but if speed is not the highest priority or as a fall-back it's quite |
|---|
| 94 |
useful. And, finally, osg::GeoProperty features an interface for OpenGL vertex |
|---|
| 95 |
arrays, giving access to the data and the types involved, which is used for |
|---|
| 96 |
rendering. |
|---|
| 97 |
|
|---|
| 98 |
In addition to the above-mentioned data there are some other osg::GeoProperty. |
|---|
| 99 |
OpenSG allows multiple primitive types per geometry, i.e. you can freely mix |
|---|
| 100 |
triangles, triangle strips and polygons in a single geometry node. The |
|---|
| 101 |
osg::GeoPTypes property defines the type of the primitives used. Right now, it only |
|---|
| 102 |
exists as a osg::GeoPTypesUI8 variant, but others may follow. The number of |
|---|
| 103 |
vertices per primitive is defined by another property, the osg::GeoPLengths |
|---|
| 104 |
property. This, too, only exists in a osg::GeoPLengthsUI32 variant right now. |
|---|
| 105 |
|
|---|
| 106 |
\subsection PageSystemGeoPropertyClasses Class Structure |
|---|
| 107 |
|
|---|
| 108 |
The basic idea of the GeoProperty class structure is very simple. The actual |
|---|
| 109 |
implementation looks complicated, but is primarily so to simplify reuse of |
|---|
| 110 |
code and simplify extensions. If the ideas behind the structure are |
|---|
| 111 |
understood, the actual code doesn't look so bad any more. |
|---|
| 112 |
|
|---|
| 113 |
All properties are derived from osg::Attachment, so they can directly be used as |
|---|
| 114 |
attachments and attached to an osg::AttachmentContainer. |
|---|
| 115 |
|
|---|
| 116 |
There are two primary types of GeoProperties: osg::AbstractGeoProperty and |
|---|
| 117 |
osg::GeoProperty. |
|---|
| 118 |
|
|---|
| 119 |
osg::AbstractGeoProperty describes the different kinds of attributes a Geometry |
|---|
| 120 |
can have: Positions, Colors, Normals, TexCoords, Indices, Types and |
|---|
| 121 |
Lengths. These are abstract, they have no specified data type and thus |
|---|
| 122 |
cannot be instantiated. They are the kinds of properties, not the actual |
|---|
| 123 |
properties. Use them in cases where you want to be able to use any actual type |
|---|
| 124 |
of data for a specific kind of property. |
|---|
| 125 |
|
|---|
| 126 |
osg::GeoProperty describes the concrete versions of the properties. These are |
|---|
| 127 |
typed, can be instantiated, and these are the versions normally used by an |
|---|
| 128 |
application to set up their osg::Geometry node cores. All the concrete classes |
|---|
| 129 |
like osg::GeoPositions3f and osg::GeoTexCoords2f are typedefs of this class. |
|---|
| 130 |
|
|---|
| 131 |
The actual interface to access the Properties has been factored out into |
|---|
| 132 |
separate classes, osg::GeoPropertyArrayInterface and |
|---|
| 133 |
osg::GeoPropertyInterface. Both of these are supported by all kinds and types |
|---|
| 134 |
of properties, the distinction is made for future extensions. |
|---|
| 135 |
|
|---|
| 136 |
osg::GeoPropertyArrayInterface defines a general, type-independent interface to |
|---|
| 137 |
all kinds of properties. It is very similar to the interface used by |
|---|
| 138 |
OpenGL's Vertex Arrays, i.e. it is possible to access the type, |
|---|
| 139 |
dimensionality and stride of the data, as well as getting access to the |
|---|
| 140 |
base pointer. This interface is primarily used for rendering. \dev The main |
|---|
| 141 |
reason for this interface is future extensibility to allow non-Property |
|---|
| 142 |
data to be used in osg::Geometry nodes, e.g. to use data that is stored in |
|---|
| 143 |
external libraries inside OpenSG. \enddev |
|---|
| 144 |
|
|---|
| 145 |
osg::GeoPropertyInterface is the typed interface. Thus there are specific |
|---|
| 146 |
classes for every kind of property, which use the GenericType of the specific |
|---|
| 147 |
kind in their interface. This interface is the one that models the osg::MField |
|---|
| 148 |
interface, it has functions to add values to and change values of the property. |
|---|
| 149 |
|
|---|
| 150 |
\dev |
|---|
| 151 |
|
|---|
| 152 |
Do we need a subValue here? DR |
|---|
| 153 |
|
|---|
| 154 |
\enddev |
|---|
| 155 |
|
|---|
| 156 |
\hint |
|---|
| 157 |
|
|---|
| 158 |
Some rules of thumb: |
|---|
| 159 |
|
|---|
| 160 |
- Everywhere you actually want to create a new property you have to use the |
|---|
| 161 |
typed versions like osg::GeoPositions3f, as they are the only ones that |
|---|
| 162 |
actually contain data. |
|---|
| 163 |
|
|---|
| 164 |
- To write functions that can handle arbitrary types of data, use abstract |
|---|
| 165 |
property pointers and the generic interface to access the data. |
|---|
| 166 |
\code |
|---|
| 167 |
GeoColorsPtr col = GeoColorsPtr::dcast(geo->getColors()); |
|---|
| 168 |
if(col == NullFC) |
|---|
| 169 |
{ |
|---|
| 170 |
FWARNING(("Downcast failed!\n")); |
|---|
| 171 |
return; |
|---|
| 172 |
} |
|---|
| 173 |
beginEditCP(col, Geometry::ColorsFieldMask); |
|---|
| 174 |
col->push_back(Color3f(1, 0, 1)); |
|---|
| 175 |
... |
|---|
| 176 |
endEditCP(col, Geometry::ColorsFieldMask); |
|---|
| 177 |
\endcode |
|---|
| 178 |
This may incur some overhead, as the data might have to be converted to the |
|---|
| 179 |
actual data type of the property. |
|---|
| 180 |
|
|---|
| 181 |
- If you know that all the geometry your function has to work on has been |
|---|
| 182 |
created yourself using a single type of property you can just downcast to |
|---|
| 183 |
that type and use the interface of the osg::MField that holds the data |
|---|
| 184 |
directly. For safety reasons you should make sure the downcast suceeded. |
|---|
| 185 |
\code |
|---|
| 186 |
GeoColors3ubPtr col = GeoColors3ubPtr::dcast(geo->getColors()); |
|---|
| 187 |
if(col == NullFC) |
|---|
| 188 |
{ |
|---|
| 189 |
FWARNING(("Downcast failed!\n")); |
|---|
| 190 |
return; |
|---|
| 191 |
} |
|---|
| 192 |
MFColor3ub *c = col->getFieldPtr(); |
|---|
| 193 |
beginEditCP(col, Geometry::ColorsFieldMask); |
|---|
| 194 |
c->push_back(Color3ub(255, 0, 255)); |
|---|
| 195 |
... |
|---|
| 196 |
endEditCP(col, Geometry::ColorsFieldMask); |
|---|
| 197 |
\endcode |
|---|
| 198 |
This is the most efficient way to access the data. |
|---|
| 199 |
|
|---|
| 200 |
- The most general is the osg::GeoPropertyArrayInterface. If you want to be |
|---|
| 201 |
able to support all kinds of osg::Geometry properties this is the way to go. |
|---|
| 202 |
It doesn't differentiate between property types, so this is as general as it |
|---|
| 203 |
gets. There are probably not many situations that need this kind of |
|---|
| 204 |
generality, the renderer and some very generic osg::Geometry optimizations |
|---|
| 205 |
like the osg::createSharedIndex and osg::createSingleIndex are the only |
|---|
| 206 |
places where it's used right now. |
|---|
| 207 |
|
|---|
| 208 |
\endhint |
|---|
| 209 |
|
|---|
| 210 |
\section PageSystemGeoIndexing Indexing |
|---|
| 211 |
|
|---|
| 212 |
Using these properties it is possible to define geometry. Note that OpenSG |
|---|
| 213 |
inherits the constraints and specifications that concern geometry from OpenGL. |
|---|
| 214 |
Vertex orientation is counterclockwise when seen from the outside, and concave |
|---|
| 215 |
polygons are not supported. |
|---|
| 216 |
|
|---|
| 217 |
\image html geo_nonindexed.png "Non-Indexed Geometry" |
|---|
| 218 |
|
|---|
| 219 |
\image latex geo_nonindexed.eps "Non-Indexed Geometry" width=8cm |
|---|
| 220 |
|
|---|
| 221 |
One additional advantage of separating properties from Geometry is the ability |
|---|
| 222 |
to share properties between geometry osg::NodeCore s. As geometries can only |
|---|
| 223 |
have one material right now that's useful for simplifying the handling of |
|---|
| 224 |
objects with multiple materials. |
|---|
| 225 |
|
|---|
| 226 |
This simple geometry has one problem: there is no way to reuse vertex data. |
|---|
| 227 |
When a vertex is to be used multiple times, it has to be replicated, which can |
|---|
| 228 |
increase the amount of memory needed significantly. Thus, some sort of |
|---|
| 229 |
indexing to reuse vertices is needed. You can guess what's coming? Right, |
|---|
| 230 |
another property. |
|---|
| 231 |
|
|---|
| 232 |
Indices are stored in the osg::GeoIndices property, which only exists in the |
|---|
| 233 |
osg::GeoIndicesUI32 variant right now. When indices are present the given lengths |
|---|
| 234 |
define how many indices are used to define the primitive, while that actual |
|---|
| 235 |
data is indexed by the indices. |
|---|
| 236 |
|
|---|
| 237 |
\image html geo_indexed.png "Indexed Geometry" |
|---|
| 238 |
|
|---|
| 239 |
\image latex geo_indexed.eps "Indexed Geometry" width=8cm |
|---|
| 240 |
|
|---|
| 241 |
Indexed geometry is very close to OpenGL, and probably the most often used |
|---|
| 242 |
type of geometry. It doesn't handle all the cases, though. |
|---|
| 243 |
|
|---|
| 244 |
Sometimes vertices need different additional attributes, even though they have |
|---|
| 245 |
the same position. One example are discontinuities in texture coordinates, |
|---|
| 246 |
e.g. when texturing a simple cube. The edges of the cube don't necessarily use |
|---|
| 247 |
the same texture coordinate. To support that a single indexed geometry has to |
|---|
| 248 |
replicate the vertices. |
|---|
| 249 |
|
|---|
| 250 |
To get around that you need multiple indices per vertex to index the different |
|---|
| 251 |
attributes. Adding an index for every attribute would blow up the geometry |
|---|
| 252 |
significantly and not necessarily make it easier to use. We decided to use |
|---|
| 253 |
another way: interleaved indices. |
|---|
| 254 |
|
|---|
| 255 |
\image html geo_multiindexed.png "Multi-Indexed Geometry" |
|---|
| 256 |
|
|---|
| 257 |
\image latex geo_multiindexed.eps "Multi-Indexed Geometry" width=8cm |
|---|
| 258 |
|
|---|
| 259 |
Interleaved indices require every vertex to hold multiple indices. Which index |
|---|
| 260 |
is used for what attribute is defined by a separate indexMapping field. The |
|---|
| 261 |
indexMapping field is a osg::UInt32 osg::MField. The possible values are bitwise |
|---|
| 262 |
combinations of the available attribute masks: osg::Geometry::MapPosition, |
|---|
| 263 |
osg::Geometry::MapNormal etc. The length of the indexMapping defines how many |
|---|
| 264 |
indices are used per vertex. If it's not set a single index for all available |
|---|
| 265 |
properties is used (or none at all). |
|---|
| 266 |
|
|---|
| 267 |
In addition to the properties geometry keeps a osg::MaterialPtr to define the |
|---|
| 268 |
material that's used for rendering the geometry (see \ref PageSystemMaterial) and |
|---|
| 269 |
a flag that activates caching the geometry in OpenGL display lists. As |
|---|
| 270 |
geometry rendering is not optimized very much right now that's the best way to |
|---|
| 271 |
get decent performance. Display lists are turned on by default. |
|---|
| 272 |
|
|---|
| 273 |
\section PageSystemGeometryIterators Geometry Iterators |
|---|
| 274 |
|
|---|
| 275 |
The osg::Geometry setup is very nice and flexible to define: you can mix different |
|---|
| 276 |
kinds of primitives in an object, you can have properties and different kinds |
|---|
| 277 |
and the indexing allows the reuse of some or all of the data. |
|---|
| 278 |
|
|---|
| 279 |
From the other side of the fence things look different: if you want to walk |
|---|
| 280 |
over all triangles of a geometry to calculate the average triangle size or the |
|---|
| 281 |
surface area, or for calculating face normals or for whatever reason you have |
|---|
| 282 |
to take care of all the flexibility and be prepared for lots of different ways |
|---|
| 283 |
to define geometry. |
|---|
| 284 |
|
|---|
| 285 |
To simplify that the concept of a geometry iterator has been introduced. A |
|---|
| 286 |
geometry iterator allows to iterate over a given geometry primitive by |
|---|
| 287 |
primitive, face by face (a face being a triangle or quad), or triangle by |
|---|
| 288 |
triangle. |
|---|
| 289 |
|
|---|
| 290 |
All of them are used like STL iterators: the osg::Geometry has methods to return |
|---|
| 291 |
the first or last+1th iterator, and to step from one |
|---|
| 292 |
element to the next. They can also unify the different indexing |
|---|
| 293 |
variants: when using an iterator you can access the index value for each |
|---|
| 294 |
attribute of each vertex of the iterator separately. Or you can directly |
|---|
| 295 |
access the data that's behind the index in its generic form, which is probably |
|---|
| 296 |
the easiest way of accessing the data of the osg::Geometry. |
|---|
| 297 |
|
|---|
| 298 |
\example The following loop prints all the vertices and normals of all the |
|---|
| 299 |
triangles of a geometry: |
|---|
| 300 |
|
|---|
| 301 |
\code |
|---|
| 302 |
for(it = geo->beginTriangles(); it != geo->endTriangles(); ++it) |
|---|
| 303 |
{ |
|---|
| 304 |
std::cout << "Triangle " << it.getIndex() << ":" << std::endl; |
|---|
| 305 |
std::cout << it.getPosition(0) << " " << it.getNormal(0) << std::endl; |
|---|
| 306 |
std::cout << it.getPosition(1) << " " << it.getNormal(1) << std::endl; |
|---|
| 307 |
std::cout << it.getPosition(2) << " " << it.getNormal(2) << std::endl; |
|---|
| 308 |
} |
|---|
| 309 |
\endcode |
|---|
| 310 |
|
|---|
| 311 |
\endexample |
|---|
| 312 |
|
|---|
| 313 |
If you're used to having a separate Face object that keeps all the data for a |
|---|
| 314 |
face, the Iterators pretty much mimic that behavior. The one thing you can't |
|---|
| 315 |
do using iterators is changing the data. To do that you have to use the Indices |
|---|
| 316 |
the Iterators give you and access the Properties directly. Be aware that the |
|---|
| 317 |
Iterators hide all data sharing, so manipulating data for a face the iterator |
|---|
| 318 |
gives you can influence an arbitrary set of other faces. |
|---|
| 319 |
|
|---|
| 320 |
\subsection PageSystemPrimitiveIterator Primitive Iterator |
|---|
| 321 |
|
|---|
| 322 |
The osg::PrimitiveIterator is the basic iterator that just iterates through the |
|---|
| 323 |
osg::GeoPTypes property and gives access to the primitive's data. It is useful |
|---|
| 324 |
to solve the index mapping complications and to get access to the generic |
|---|
| 325 |
data, but it's primarily a base class for the following two iterator types. |
|---|
| 326 |
|
|---|
| 327 |
\subsection PageSystemFaceIterator Face Iterator |
|---|
| 328 |
|
|---|
| 329 |
The osg::FaceIterator only iterates over polygonal geometry and ignores |
|---|
| 330 |
points, lines and polygonal primitives with less than three vertices. It also |
|---|
| 331 |
splits the geometry into triangles or quads. |
|---|
| 332 |
|
|---|
| 333 |
\subsection PageSystemTriangleIterator Triangle Iterator |
|---|
| 334 |
|
|---|
| 335 |
The osg::TriangleIterator behaves like the osg::FaceIterator, but it also splits |
|---|
| 336 |
Quads into two triangles, thus it does an implicit triangulation. As OpenSG |
|---|
| 337 |
just like OpenGL doesn't support concave geometry that's not as hard as it |
|---|
| 338 |
sounds. |
|---|
| 339 |
|
|---|
| 340 |
\subsection PageSystemLineIterator Line Iterator |
|---|
| 341 |
|
|---|
| 342 |
The osg::LineIterator only iterates over line geometry and ignores points, |
|---|
| 343 |
polygonal primitives and line primitives with less than two vertices. It |
|---|
| 344 |
splits line strips and loops into single lines. |
|---|
| 345 |
|
|---|
| 346 |
\subsection PageSystemEdgeIterator Edge Iterator |
|---|
| 347 |
|
|---|
| 348 |
The osg::EdgeIterator (currently) only iterates over line geometry and ignores |
|---|
| 349 |
points, polygonal primitives and line primitives with less than two |
|---|
| 350 |
vertices like the osg::LineIterator does, but it leaves line strips and loops |
|---|
| 351 |
as they are. This iterator will make more sense in a future version, where it |
|---|
| 352 |
returns the edges of the other primitives as single lines or line loops as |
|---|
| 353 |
well. |
|---|
| 354 |
|
|---|
| 355 |
\dev For all polygonal primitives probably except GL_POLYGON itself the edges |
|---|
| 356 |
could be returned as single lines conceptually similar to the implicit |
|---|
| 357 |
triangulation of the osg::TriangleIterator. For a polygon it seems reasonable |
|---|
| 358 |
to me to reinterpret it as line loop. Shouldn't we overload getType() to return |
|---|
| 359 |
the interpretation? \enddef |
|---|
| 360 |
|
|---|
| 361 |
The iterators can also be used to indicate a specific primitive/face/triangle/line. |
|---|
| 362 |
Each of these has an associated index that the iterator keeps and that can be |
|---|
| 363 |
accessed using getIndex(). A new iterator can be used to seek() a given |
|---|
| 364 |
primitive/face/triangle again and work on it. This is used for example in the |
|---|
| 365 |
osg::IntersectAction. |
|---|
| 366 |
|
|---|
| 367 |
|
|---|
| 368 |
\subsection PageSystemSimpleGeometry Simple Geometry |
|---|
| 369 |
|
|---|
| 370 |
OpenSG does not have NodeCores for geometric primitives like spheres, cones, |
|---|
| 371 |
cylinders etc. Instead there are a number of utility functions that can create |
|---|
| 372 |
these objects. They can be created as a ready-to-use node and as a naked node |
|---|
| 373 |
core. In most cases we tried to mimic the VRML primitive semantics, so if |
|---|
| 374 |
you're familiar with VRML you will feel right at home. |
|---|
| 375 |
|
|---|
| 376 |
\dev We definitely need a Teapot here... :) \enddev |
|---|
| 377 |
|
|---|
| 378 |
\subsubsection PageSystemSimpleGeometryPlane Plane |
|---|
| 379 |
|
|---|
| 380 |
osg::makePlane creates a single subdivided quad. |
|---|
| 381 |
|
|---|
| 382 |
\subsubsection PageSystemSimpleGeometryBox Box |
|---|
| 383 |
|
|---|
| 384 |
osg::makeBox creates a box around the origin with subdivided sides. |
|---|
| 385 |
|
|---|
| 386 |
\subsubsection SimpleGeometryCone Cone |
|---|
| 387 |
|
|---|
| 388 |
osg::makeCone create a cone at the origin. |
|---|
| 389 |
|
|---|
| 390 |
\subsubsection PageSystemSimpleGeometryCylinder Cylinder |
|---|
| 391 |
|
|---|
| 392 |
osg::makeCylinder create a cylinder at the origin. |
|---|
| 393 |
|
|---|
| 394 |
\subsubsection PageSystemSimpleGeometryTorus Torus |
|---|
| 395 |
|
|---|
| 396 |
osg::makeTorus create a torus at the origin. |
|---|
| 397 |
|
|---|
| 398 |
\subsubsection PageSystemSimpleGeometryConicalFrustum ConicalFrustum |
|---|
| 399 |
|
|---|
| 400 |
osg::makeConicalFrustum creates a truncated cone at the origin. |
|---|
| 401 |
|
|---|
| 402 |
\subsubsection PageSystemSimpleGeometrySphere Sphere |
|---|
| 403 |
|
|---|
| 404 |
There are two ways to create a sphere. osg::makeSphere uses a icosahedron as a |
|---|
| 405 |
base and subdivides it. This gives a sphere with equilateral triangles, but |
|---|
| 406 |
they do not correspond to latitude or longitude, which makes it hard to get |
|---|
| 407 |
good texture mapping on it. As every subdivision step quadruples the number of |
|---|
| 408 |
triangles, it is also hard to control the complexity of these kinds of spheres. |
|---|
| 409 |
|
|---|
| 410 |
osg::makeLatLongSphere on the other hand creates a |
|---|
| 411 |
sphere by simply usign a regular subdivision of latitude and longitude. This |
|---|
| 412 |
creates very small polygons near the poles, but is more amendable to texture |
|---|
| 413 |
mapping and gives finer control of the resoltuion of the sphere. |
|---|
| 414 |
|
|---|
| 415 |
\subsubsection PageSystemSimpleGeometryExtrusion Extrusion Geometry |
|---|
| 416 |
|
|---|
| 417 |
osg::makeExtrusion creates a pretty general extruded geometry. It works by sweeping a given cross |
|---|
| 418 |
section, which can be given clockwise or counterclockwise, across a spine. For |
|---|
| 419 |
every spine point an orientation and a scale factor are specified. The |
|---|
| 420 |
beginning and the end of the object can be closed by caps, but for the capping |
|---|
| 421 |
to work the cross section has to be convex. The resulting geometry can |
|---|
| 422 |
be refined as a subdivision surface (no idea which subdivision scheme is |
|---|
| 423 |
applied, anyone care who knows care to take a look?). Optionally normals and |
|---|
| 424 |
texture coordinates can be generated |
|---|
| 425 |
|
|---|
| 426 |
|
|---|
| 427 |
\subsection PageSystemGeoFunctions Helper Functions |
|---|
| 428 |
|
|---|
| 429 |
A number of helper functions can be used in conjunction with manipulating and |
|---|
| 430 |
optimizing geometry. |
|---|
| 431 |
|
|---|
| 432 |
\subsubsection PageSystemGeoFunctionsCalcNormals Normal Calculation |
|---|
| 433 |
|
|---|
| 434 |
A common problem for self-created geometry or for geometry loaded from simple |
|---|
| 435 |
file formats are missing normals. Normals are needed for proper lighting, |
|---|
| 436 |
without them objects will either be black or uniformly colored. |
|---|
| 437 |
|
|---|
| 438 |
Normals can be calculated either for every face or for every vertex. |
|---|
| 439 |
|
|---|
| 440 |
Face normals, as calculated by osg::calcFaceNormals, are only unique for a given |
|---|
| 441 |
triangle or quad. The resulting object will look faceted, whcih may or may not |
|---|
| 442 |
be the desired effect. This will also work for striped or fanned models, as |
|---|
| 443 |
OpenSG doesn't have a per-face binding and uses multi-indexed per-vertex |
|---|
| 444 |
normals for this. |
|---|
| 445 |
|
|---|
| 446 |
Vertex normals are calculated for every vertex and allow a shape to look |
|---|
| 447 |
smooth, as the lighting calculation is done using the vertex normals and |
|---|
| 448 |
interpolated across the surface. They can be calculated using two different |
|---|
| 449 |
methods. |
|---|
| 450 |
|
|---|
| 451 |
osg::calcVertexNormals(GeometryPtr geo) will just average all the normals of |
|---|
| 452 |
the faces touching a vertex. It does not unify the vertices, i.e. it does not |
|---|
| 453 |
check if a vertex with given coordinates appears in the position property |
|---|
| 454 |
multiple times, the geometry has to be created correctly or be run thrugh |
|---|
| 455 |
osg::createSharedIndex. |
|---|
| 456 |
|
|---|
| 457 |
The disadvantage of osg::calcVertexNormals(GeometryPtr geo) is its |
|---|
| 458 |
indiscriminative nature, it will average out all the edges in the object. The |
|---|
| 459 |
alternative is osg::calcVertexNormals(GeometryPtr geo, Real32 creaseAngle), |
|---|
| 460 |
which uses a crease angle criterion to define which edges to keep. Edges that |
|---|
| 461 |
have an angle larger than \a creaseAngle will not be averaged out. It won't |
|---|
| 462 |
always work for striped geometry. It will process it, but if a stripe point |
|---|
| 463 |
needs to be split because it has two normals, that won't be done. The same |
|---|
| 464 |
sharing caveat as given above applies. |
|---|
| 465 |
|
|---|
| 466 |
Calculating vertex normals with a crease angle sounds simpler than it is, |
|---|
| 467 |
especially if the calculation should be independent of the triangulation of the |
|---|
| 468 |
object. Thus the algorithm is relatively expensive and should be avoided in a |
|---|
| 469 |
per-frame loop. There are some ideas to do the expesive calculations once and |
|---|
| 470 |
quickly reaverage the normals when needed. These have not been realized, if you |
|---|
| 471 |
need this or even better want to implement it, notify us at info@opensg.org. |
|---|
| 472 |
|
|---|
| 473 |
\subsubsection PageSystemGeoFunctionsMakeGeo Geometry Creation |
|---|
| 474 |
|
|---|
| 475 |
Setting up all the objects needed to fully specify an OpenSG Geometry can be a |
|---|
| 476 |
bit tedious. So to simplify the process there are some functions that take data |
|---|
| 477 |
in other formats and create the corresponding OpenSG Geometry data. |
|---|
| 478 |
|
|---|
| 479 |
Right now there is only one function to help with this, |
|---|
| 480 |
osg::setIndexFromVRMLData. It takes separate indices for the different |
|---|
| 481 |
attributes, as given in the VRML97 specification, together with the flags that |
|---|
| 482 |
influence the interpretation of these indices, and sets up the indices, lengths |
|---|
| 483 |
and types properties of the given geometry. |
|---|
| 484 |
|
|---|
| 485 |
|
|---|
| 486 |
\subsubsection PageSystemGeoFunctionsOptimizeGeo Geometry Optimization |
|---|
| 487 |
|
|---|
| 488 |
OpenSG's Geometry structure is very flexible and pretty closed modeled on |
|---|
| 489 |
OpenGL. But not all of the Geometry data specification variants are similarly |
|---|
| 490 |
efficient to render. The functions in this group help optimizie different |
|---|
| 491 |
aspects of the Geometry. |
|---|
| 492 |
|
|---|
| 493 |
osg::createOptimizedPrimitives takes a Geometry and tries to change it so that |
|---|
| 494 |
it can be rendered using the minimum number of vertex transformations. To do |
|---|
| 495 |
that it connects triangles to strips and fans (optionally). It does not change |
|---|
| 496 |
the actual property values, it just creates new indices, types and lengths. The |
|---|
| 497 |
algorithm realized here does not try a high-level optimization, instead it is |
|---|
| 498 |
optimized for speed. Due to its pseudo-random nature it can be run multiple |
|---|
| 499 |
times in the same time a more complex algorithm needs, allowing it to try |
|---|
| 500 |
different variants and keeping the best one found. Or, if execution time is a |
|---|
| 501 |
problem, it can be run only once and create a very quick result that is good, |
|---|
| 502 |
but not optimal. |
|---|
| 503 |
|
|---|
| 504 |
osg::createSharedIndex tries to find identical elements in the Geometries |
|---|
| 505 |
Properties and remove the copies. It will not actually change the Property |
|---|
| 506 |
data, it will just change the indexing to only use one version of the data. |
|---|
| 507 |
This is a necessary preparation step to allow osg::createOptimizedPrimitives to |
|---|
| 508 |
identify the triangles it can connect to form stripes and fans. |
|---|
| 509 |
|
|---|
| 510 |
osg::createSingleIndex resorts the Geometry's Property values to allow using |
|---|
| 511 |
a single index (in contrast to interleaved multi-indices) to represent the |
|---|
| 512 |
Geometry. To do that it might have to remap and copy Property values, as well |
|---|
| 513 |
as index values. While multi-indexing can be very efficient datawise, as as |
|---|
| 514 |
much of possible is shared, for rendering it is problematic. OpenGL doesn't |
|---|
| 515 |
know multi-indexing, thus for multi-indexed Geometry the more efficient OpenGL |
|---|
| 516 |
geometry specifiers like VertexArrays can't be used, which can have a |
|---|
| 517 |
significant impact on performance, especially for dynamic objects. |
|---|
| 518 |
|
|---|
| 519 |
UInt32 calcPrimitiveCount ( GeometryPtr geo, |
|---|
| 520 |
UInt32 &triangle, UInt32 &line, UInt32 &point ); |
|---|
| 521 |
|
|---|
| 522 |
|
|---|
| 523 |
\subsubsection PageSystemGeoFunctionsShowNormals Normal Visualisation |
|---|
| 524 |
|
|---|
| 525 |
For debugging it can be useful to actually see the normals of an object, as |
|---|
| 526 |
that allows making sure that the normals point in the expected direction and |
|---|
| 527 |
that normals are really identical and not just pretty close. Every normal is |
|---|
| 528 |
represented by a line of a user-defined length. |
|---|
| 529 |
|
|---|
| 530 |
As OpenSG doesn't have an explicit face/vertex binding mode there are two |
|---|
| 531 |
different functions to create an object representing the vertex or face |
|---|
| 532 |
normals. The application should know whether face or vertex normals are used in |
|---|
| 533 |
the given geometry. In general it is safe to assume vertex normals are used. |
|---|
| 534 |
|
|---|
| 535 |
osg::calcVertexNormalsGeo creates an object that shows the vertex normals of |
|---|
| 536 |
the given geometry, while osg::calcFaceNormalsGeo creates an object that shows |
|---|
| 537 |
the face normals. |
|---|
| 538 |
|
|---|
| 539 |
\dev We should add something more general here. Forcing the app to know is not |
|---|
| 540 |
nice. calcVertexNormalsGeo can already calc normals at the vertices and at the |
|---|
| 541 |
centers of the tris, but the decision when to use which and which normal to use |
|---|
| 542 |
is not clear. \enddev |
|---|
| 543 |
|
|---|
| 544 |
*/ |
|---|