7 /*! \defgroup GrpSystemNodeCoresDrawablesGeometry Geometry
8 \ingroup GrpSystemNodeCoresDrawables
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.
15 /*! \defgroup GrpSystemDrawablesGeometryIterators Geometry Iterators
16 \ingroup GrpSystemNodeCoresDrawablesGeometry
18 Helpers to access Geometry in a generic way. See \ref PageSystemGeometryIterators
22 /*! \defgroup GrpSystemDrawablesGeometryFunctions Geometry Functions
23 \ingroup GrpSystemNodeCoresDrawablesGeometry
25 The GeoFunctions group contains different different functions to
26 manipulate geometry. See \ref PageSystemGeoFunctions for a description.
29 /*! \defgroup GrpSystemDrawablesGeometryProperties Geometry Properties
30 \ingroup GrpSystemNodeCoresDrawablesGeometry
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
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.
44 /*! \defgroup GrpSystemDrawablesGeometrySimpleGeometry Simple Geometry
45 \ingroup GrpSystemNodeCoresDrawablesGeometry
47 SimpleGeometry combines a number of functions to create some specialized
48 geometry very easily. See \ref PageSystemSimpleGeometry for a description.
53 /*! \page PageSystemGeometry Geometry
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.
65 \section PageSystemGeoProperties Properties
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
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
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.
106 \subsection PageSystemGeoPropertyClasses Class Structure
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.
113 All properties are derived from osg::Attachment, so they can directly be used as
114 attachments and attached to an osg::AttachmentContainer.
116 There are two primary types of GeoProperties: osg::AbstractGeoProperty and
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.
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.
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.
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
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.
152 Do we need a subValue here? DR
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.
164 - To write functions that can handle arbitrary types of data, use abstract
165 property pointers and the generic interface to access the data.
167 GeoColorsPtr col = GeoColorsPtr::dcast(geo->getColors());
170 FWARNING(("Downcast failed!\n"));
173 beginEditCP(col, Geometry::ColorsFieldMask);
174 col->push_back(Color3f(1, 0, 1));
176 endEditCP(col, Geometry::ColorsFieldMask);
178 This may incur some overhead, as the data might have to be converted to the
179 actual data type of the property.
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.
186 GeoColors3ubPtr col = GeoColors3ubPtr::dcast(geo->getColors());
189 FWARNING(("Downcast failed!\n"));
192 MFColor3ub *c = col->getFieldPtr();
193 beginEditCP(col, Geometry::ColorsFieldMask);
194 c->push_back(Color3ub(255, 0, 255));
196 endEditCP(col, Geometry::ColorsFieldMask);
198 This is the most efficient way to access the data.
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.
210 \section PageSystemGeoIndexing Indexing
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.
217 \image html geo_nonindexed.png "Non-Indexed Geometry"
219 \image latex geo_nonindexed.eps "Non-Indexed Geometry" width=8cm
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.
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,
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.
237 \image html geo_indexed.png "Indexed Geometry"
239 \image latex geo_indexed.eps "Indexed Geometry" width=8cm
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.
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.
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.
255 \image html geo_multiindexed.png "Multi-Indexed Geometry"
257 \image latex geo_multiindexed.eps "Multi-Indexed Geometry" width=8cm
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).
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.
273 \section PageSystemGeometryIterators Geometry Iterators
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.
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
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
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.
298 \example The following loop prints all the vertices and normals of all the
299 triangles of a geometry:
302 for(it = geo->beginTriangles(); it != geo->endTriangles(); ++it)
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;
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.
320 \subsection PageSystemPrimitiveIterator Primitive Iterator
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.
327 \subsection PageSystemFaceIterator Face Iterator
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.
333 \subsection PageSystemTriangleIterator Triangle Iterator
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
340 \subsection PageSystemLineIterator Line Iterator
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.
346 \subsection PageSystemEdgeIterator Edge Iterator
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
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
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.
368 \subsection PageSystemSimpleGeometry Simple Geometry
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.
376 \dev We definitely need a Teapot here... :) \enddev
378 \subsubsection PageSystemSimpleGeometryPlane Plane
380 osg::makePlane creates a single subdivided quad.
382 \subsubsection PageSystemSimpleGeometryBox Box
384 osg::makeBox creates a box around the origin with subdivided sides.
386 \subsubsection SimpleGeometryCone Cone
388 osg::makeCone create a cone at the origin.
390 \subsubsection PageSystemSimpleGeometryCylinder Cylinder
392 osg::makeCylinder create a cylinder at the origin.
394 \subsubsection PageSystemSimpleGeometryTorus Torus
396 osg::makeTorus create a torus at the origin.
398 \subsubsection PageSystemSimpleGeometryConicalFrustum ConicalFrustum
400 osg::makeConicalFrustum creates a truncated cone at the origin.
402 \subsubsection PageSystemSimpleGeometrySphere Sphere
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.
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.
415 \subsubsection PageSystemSimpleGeometryExtrusion Extrusion Geometry
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
427 \subsection PageSystemGeoFunctions Helper Functions
429 A number of helper functions can be used in conjunction with manipulating and
432 \subsubsection PageSystemGeoFunctionsCalcNormals Normal Calculation
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.
438 Normals can be calculated either for every face or for every vertex.
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
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
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.
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.
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.
473 \subsubsection PageSystemGeoFunctionsMakeGeo Geometry Creation
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.
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.
486 \subsubsection PageSystemGeoFunctionsOptimizeGeo Geometry Optimization
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.
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,
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.
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.
519 UInt32 calcPrimitiveCount ( GeometryPtr geo,
520 UInt32 &triangle, UInt32 &line, UInt32 &point );
523 \subsubsection PageSystemGeoFunctionsShowNormals Normal Visualisation
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.
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.
535 osg::calcVertexNormalsGeo creates an object that shows the vertex normals of
536 the given geometry, while osg::calcFaceNormalsGeo creates an object that shows
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