The opoptimize application illustrates the basic structure of a scene-graph tuning application. Scene graph tuning is typically done before rendering. As a result, opoptimize is usually used in batch processing mode. However, opoptimize does allow scene-graph rendering interactions using an opViewer (see “Viewing Class: opViewer”). The output of the application is typically a scene graph that can be easily manipulated in an application like opviewer, which was discussed in Chapter 2.
This chapter presents lines of code that are essentially the same as those of /usr/share/Optimizer/src/sample/opoptimize/main.cxx. Comments highlight OpenGL Optimizer features when they are used by the code, and direct you to detailed discussions that appear in this guide.
The main tools not included in opoptimize are tools for multiprocessing, which are discussed in Chapter 14, “Managing Multiple Processors.”
This appendix discusses opoptimize in the following sections:
When you use OpenGL Optimizer methods that construct scene graphs and csGeoSets, you must not use input pointers after the method call. Input objects may change as a result of applying the method or they may be included in the output. This may occur, for example, with the simplifiers, tessellators, and spatialization tools.
If an input object is included in the output, subsequent changes to the original input may affect the output object. For example, if you generate a level of detail node by simplifying a csGeoSet and you want to use color to distinguish the levels of detail, but the simplifier could not change the input because of the criteria you used, then a color change applied to input will also change the color of the output.
If you want to use an input scene graph or csGeoSet after a call to any modifying method, make a copy first.
To compile opoptimize, enter the command make while in the directory /usr/share/Optimizer/src/sample/opoptimize.
To run opoptimize, recall that command-line options are listed if you invoke the application without any command-line arguments. To print a list of interactive program controls into your command shell while you run opoptimize, place the mouse cursor in the rendering window and enter h.
Figure D-1 illustrates simplification of the original model of 19474 polygons to 10902 to 4938 polygons. The three panels in the figure correspond from left to right to the following three commands:
# opoptimize kittyHawk.iv -rotation 1 0 0 1
# opoptimize kittyHawk.iv -rotation 1 0 0 1 -simpPercent 50 0 1 0
# opoptimize kittyHawk.iv -rotation 1 0 0 1 -simpPercent 15 1 2 1
The simplifier used for these images is discussed in “Methods in opSimplify”.
The rest of this chapter is a running commentary on the code in main.cxx.
| Note: The sequence in which tools are applied to the scene graph in opoptimize is not fundamental to a scene-graph tuning application; if you use opoptimize as a template, other orderings may be more appropriate for your needs. |
Inclusions |
|
|
| #include <stdio.h> #include <Cosmo3D/csFields.h> | |
|
#include <Optimizer/opArgs.h> | |
You can simplify the rendering task by culling small features from the scene. See “Detail Culling”. |
|
#include <Optimizer/opDetailSimplify.h> |
|
#include <Optimizer/opGenLoader.h> | |
This header provides various functions that control specific features of the scene graph and accelerate rendering. For example, see “Display Lists”, “Vertex Arrays”, and “Methods in opCollapseAppearances”. |
|
#include <Optimizer/opGFXSpeed.h> |
See “Calling opInit()”. |
|
#include <Optimizer/opInit.h> |
|
#include <Optimizer/opNotify.h> | |
Inclusions (cont.) |
|
|
The basic control of interactive rendering, including keyboard commands and the ability to manipulate selected portions of the scene graph, are provided by the classes in these files. See “opDrawImpl Subclasses Used In Sample Applications” and “Interacting With a Rendered Object: opPickDrawImpl”.
|
| #include <Optimizer/opDefDrawImpl.h> |
To make scene graph traversals more efficient, you can organize nodes spatially. See Chapter 6, “Organizing the Scene Graph Spatially.” |
|
#include <Optimizer/opSpatialize.h>#include <Optimizer/opGeoSpatialize.h> |
A sophisticated simplification tool is provided by this file. See “Methods in opSimplify”. |
|
#include <Optimizer/opSRASimplify.h> |
You can collect statistics about the numbers of vertices, triangles and connected primitives in your scene graph. See “Gathering Triangle Statistics”. |
|
#include <Optimizer/opTriStats.h> |
Includes classes to develop connected primitives from a set of triangles in a csGeoSet. See “Merging Triangles Into Both Strips and Fans: opTriFanAndStrip” and “Merging Triangles Using Multiple Processors: opMPTriFanAndStrip”. |
| #include <Optimizer/opTriFanAndStrip.h> |
This file holds the basic rendering class opViewer, discussed in “Viewing Class: opViewer”. |
|
#include <Optimizer/opViewer.h> |
Inclusions (cont.) |
|
|
Tessellators convert abstract geometries into renderable collections of triangles. See “Tessellating Parametric Surfaces”. This application focuses mainly on simplifying the rendering task by using tessellations with differing levels of resolution, by removing triangles from tessellated objects, and by reorganizing the distribution of triangles in the scene graph. |
| #include <Optimizer/opTessParaSurfaceAction.h> #include <Optimizer/opTessNurbSurfaceAction.h> |
To guarantee consistent tessellations between adjacent surfaces, that is, surfaces rendered without cracks, OpenGL Optimizer provides topology maintenance tools. See Chapter 10, “Creating and Maintaining Surface Topology.” |
|
#include <Optimizer/opTopo.h> |
These files are in the opoptimize directory. |
|
#include “colorTag.h” |
Initialize |
|
|
You can use either of the algorithms to remove triangles from a mesh. See “Creating LODs: opSRASimplify” and “Rossignac Simplification Algorithm: opLatticeSimplify”. Here the application initializes the control parameter for one of the simplification tools and creates an instance of the other. |
| // Global simplifier paramaters for passing to |
You have three ways to develop surface connectivity information. The values enumerated list from best to worst. See Chapter 10, “Creating and Maintaining Surface Topology.” |
|
int LODoffset;enum opTopoOption |
Define a Key Handler |
|
|
The key handler extends the default keyboard controls available during rendering. See “opDrawImpl Subclasses Used In Sample Applications”. |
| // SimplifyViewer extends opViewer by adding new
// key bindings:
static bool keyHandler(opDrawImpl *di, int key) |
|
|
switch(key) |
See “Merging Triangles Into Strips: opTriStripper”; and “Gathering Triangle Statistics”. |
|
case `c': |
Define a Key Handler (cont.) |
|
|
See the file simplify.h and “Rossignac Simplification Algorithm: opLatticeSimplify”, and “Gathering Triangle Statistics”. |
| case `G': latticeSimplifySameTree( |
See the file simplify.h and “Creating LODs: opSRASimplify”, and “Gathering Triangle Statistics”. |
| case `g': simplifySameTree( |
The LOD offset adjusts the LOD calculation when objects in the scene are moving. See “Viewing Class: opViewer”. |
|
case `+': case `-':
|
Define a Key Handler (cont.) |
|
|
This calls a Cosmo3D function to save a scene graph to a file in .csb format. See “Saving and Loading Scene-Graph Files”. |
| case `z': default: |
main() |
|
|
See “Calling opInit()” and “Command-Line Parser: opArgParser”. |
|
int main(int argc, char *argv[]) opInit(); opArgParser args; int numFiles; char *filename,*outFile; |
Command-Line Control Parameters |
|
|
The location on the screen (x, y) of the rendering window, and the dimensions of the window (w,h). The default x-coordinate assumes a screen of width 1280, and a rendering window of width 600 with a 10-pixel boundary. You can control these parameters from the command line. |
| bool haveX=-1, haveY=-1, haveW=-1, haveH=-1, |
If TRUE, the processed scene graph is written to a .csb file and not rendered. See “Saving and Loading Scene-Graph Files”. |
| bool writeCSB; |
You can use several techniques to develop connected primitives that accelerate the rendering process. See “Creating OpenGL Connected Primitives”. |
|
bool doTriStrip, doTriFan, doTriFanStrip, doMPTriFanStrip; int minFanSize; bool doRandomTriStrip; |
Command-Line Control Parameters (cont.) |
|
|
You can use either of two simplification algorithms to remove triangles from a mesh. See “Creating LODs: opSRASimplify” and “Rossignac Simplification Algorithm: opLatticeSimplify”. |
| bool doSRASimplify; |
There are several techniques to rearrange triangles in a scene graph to reflect their positions in space and facilitate cull traversals. See Chapter 6, “Organizing the Scene Graph Spatially.” |
|
bool combineGSet; bool spatialize, geospatialize; |
|
|
bool writeOutput; |
You can place simplified and unsimplified scene graphs under a csLOD node. |
| bool LODfiles, makeLOD; |
See “Detail Culling”. |
|
bool doDetail; bool doRootRadius; |
|
|
bool doScale; |
|
|
bool showDelete; |
|
|
bool doDeleteSurf; |
You can interactively assign colors to objects. See “Interacting With a Rendered Object: opPickDrawImpl”. |
|
bool enableColoring; |
|
|
bool doRemoveEmptyGrp; |
Get Command-Line Parameters |
|
|
Specify the threshold distance between points below which they are considered identical when building topology. See “Summary of Scene Graph Topology: opTopo” on page 180. |
| bool haveTopoTol; |
Specify the background color for the rendering window and the model orientation. These settings are controlled by opViewer options. See “Viewing Class: opViewer”. |
| bool haveBackgroundColor;float backgroundRed, backgroundGreen, |
Specify control parameters for tessellation, and the type of tessellator (for example for general parametric surfaces or for NURBS surfaces). See “Tessellating Parametric Surfaces”. If tessType is equal to zero, no tessellation is performed. The main use for this option is in batch mode to convert file formats and possibly store topology information; you can read in a .iv file and write the scene graph without tessellations to a .csb file. Depending on the topology-build command-line option, the output could have topology information. See “Saving and Loading Scene-Graph Files”. |
| bool haveChordalTol = -1; |
By default, build the best topology. See Chapter 10, “Creating and Maintaining Surface Topology.” |
| bool isOnePass = false; |
You must supply a file with the scene graph. All other command-line control parameters are optional. |
| args.defRequired( “%s”, |
Get Command-Line Parameters (cont.) |
|
|
|
| args.defOption( “-width %d”, |
|
|
args.defOption( “-tristrip”, |
|
|
args.defOption( “-trifan”, |
|
|
args.defOption( “-trifanstrip %d”, |
|
|
args.defOption( “-mptrifanstrip %d”, |
|
|
args.defOption( “-detail %f”, |
|
|
args.defOption( “-rootRadius %f”, |
|
|
args.defOption( “-simplify”, |
Get Command-Line Parameters (cont.) |
|
|
|
| args.defOption( “-rossignac %f”, |
The target of the simplification can be specified as a percentage of the original number of triangles, or as a exact number. See “Creating LODs: opSRASimplify”. |
|
args.defOption( “-simpPercent %f %f “, args.defOption( “-simpCount %d %f “, |
You can render individual csTriStrips in differing colors, to see their sizes.See “Creating OpenGL Connected Primitives”; and “Specifying Coloring of New csGeoSets: opColorGenerator”. |
| args.defOption( “-tristripRandom”, |
|
|
args.defOption( “-scale %f”, |
|
|
args.defOption( “-batch %s”, |
|
|
args.defOption( “-combine”, |
|
|
args.defOption( “-spatialize %d %d “, |
Get Command-Line Parameters (cont.) |
|
|
|
| args.defOption( “-geospatialize %d %d “, |
|
|
args.defOption( “-LODfiles”, |
|
|
args.defOption( “-makeLOD”, |
|
|
args.defOption( “-writeSG”, |
|
|
args.defOption( “-noColors”, |
Get Command-Line Parameters (cont.) |
|
|
|
| #ifdef OP_REAL_IS_DOUBLE args.defOption( “-ttol %l”, #else args.defOption( “-ctol %f”, args.defOption( “-ttol %f”, #endif |
|
|
args.defOption( “-onePass”, // Sets the type of tessellator used either by the |
|
|
// Sets how many samples are used on trim curves
// during the tessellation. |
Get Command-Line Parameters (cont.) |
|
|
|
| // enable feature to delete highlighted nodes with
`X' key |
|
|
// enable feature to color highlighted subtrees
with number keys |
|
|
// Read in <filename>.delete to determine which
parts to delete from SG |
|
|
// User defined background color |
|
|
// Use colortag file to determine which color to
apply to all parts |
|
|
// Remove group nodes with no children |
Get Command-Line Parameters (cont.) |
|
|
|
| numFiles = args.scanArgs(argc,argv); //set topoOption |
Create the Appropriate Tessellator |
|
|
See Chapter 11, “Rendering Higher-Order Primitives: Tessellators.”
|
| // Create a tessellator |
Create the Topology Data Structures |
|
|
See Chapter 10, “Creating and Maintaining Surface Topology.” |
| //topology |
Load the Scene Graph Data |
|
|
The loader manages topology in one of the following ways: It anticipates the development of connectivity information for all surfaces in the scene graph followed by tessellating the surface. Code for these steps appears later in the application. It develops connectivity information as surfaces load, and tessellates them. It ignores connectivity: it simply tessellates surfaces as they load without regard for adjacencies. See“Saving and Loading Scene-Graph Files”; Chapter 10, “Creating and Maintaining Surface Topology”; and “Base Class opTessellateAction”. |
| // Create a loader loader = new opGenLoader( true, tess, false ); } // Load the file on the command line and get a //
scene graph backcsGroup *obj = loader->load( filename ); |
Load the Scene Graph Data (cont.) |
|
|
|
|
if (obj) |
You can use a color tag file to specify the appearance of different parts in the scene. The format of the color tag file is: Comments (preceded by the pound sign, #). A line containing the number of colors. Lines containing the colors: five digits that
specify red, green, blue, alpha, and shininess
values. Currently, alpha is not used, but a Part names and their associated colors. See colorTable::colorTable() in
/usr/share/Optimizer/src/sample/opoptimize/ |
| // Color the parts as specified in color file |
Load the Scene Graph Data (cont.) |
|
|
|
|
if (numFiles) if (LODfiles) if (obj) |
Load the Scene Graph Data (cont.) |
|
|
See addLOD.cxx. |
| if (LODfiles) |
|
| // Throw the loader away, we're done with it |
Build Topology and Tessellate |
|
|
The most accurate topology, which yields crack-free tessellations, is created by two traversals of the scene graph: one to establish adjacencies of surfaces, and the second to tessellate the surfaces. See “Building Topology: Computing and Using Connectivity Information”. |
|
//build topology if we haven't done it fprintf(stderr, “Building topology starts ...
\n”);
|
You can tessellate higher-order surface representations and view the scene, or in batch processing, not view the scene but write the scene graph (possibly with topology information) to a .csb file. See “Saving and Loading Scene-Graph Files”. |
| if(tess) |
Remove Childless Nodes and Color Bindings |
|
|
|
// Run through the SG and remove groups with no | |
Remove Childless Nodes and Color Bindings (cont.) |
|
|
|
| csType *type = csTriFanSet::getClassType(); |
|
if (removeColors) | |
Remove Small Objects from the Scene |
|
|
You can remove small objects from the rendering pipeline. See “Detail Culling”. |
| csSphereBound sph; |
Remove Childless Nodes After Detail Cull |
|
|
See the files removeEmpty.h and removeEmpty.cxx. |
|
// Run through the SG and remove groups with no
children |
Spatialize the Scene Graph |
|
|
If you have a scene graph with too many small csGeosets, you can combine them and develop a graph consisting of a root node with one child that contains all of the triangles of the original graph. See “Merging csGeoSets in a Scene Graph: opCombineGeoSets”. |
| if (combineGSet) |
Spatialize the Scene Graph (cont.) |
|
|
You can re-organize existing nodes to reflect their spatial relations (see “Spatializing a Scene Graph: opGeoSpatialize”) or spatially re-organize triangles in a csGeoSet (see “Spatialization Tool: opSpatialize”). The function geoSpatializeTree() is defined in geoSpatialize.cxx and spatializeTree() is defined in spatialize.cxx. These functions apply the spatialization methods to the whole scene graph. |
| if (geospatialize) |
Print Scene Graph |
|
|
| if (writeOutput)
| |
Remove Triangles and Create Levels of Detail |
|
|
You can use either of two simplification algorithms to remove triangles from a mesh. See “Creating LODs: opSRASimplify” and “Rossignac Simplification Algorithm: opLatticeSimplify”. |
| if ( doSRASimplify || makeLOD) |
Remove Triangles and Create Levels of Detail |
|
|
The functions simplifyTree(), simplifySameTree(), and latticeSimplifySameTree() traverse the scene graph and simplify all csGeoSets. See the files simplify.h, simplify.cxx, and simplifySameTree.cxx.
|
| if (makeLOD) |
Create OpenGL Connected Primitives |
|
|
To reduce the load on the graphics hardware, you can reduce redundant vertex information by combining triangles into fans of a minimum size, and combining the remainder into triangle strips (using either a single or multiple processors). See “Merging Triangles Into Both Strips and Fans: opTriFanAndStrip” and “Merging Triangles Using Multiple Processors: opMPTriFanAndStrip”. |
| if (doTriFanStrip) |
You can create just triangle strips to reduce redundant vertex information, rather than create both triangle fans and triangle strips. See “Merging Triangles Into Strips: opTriStripper”. The methods of opTriStripper work only on a csGeoSet. The function triStripTree() traverses the whole scene graph, applying the methods of opTriStripper to every csGeoSet (see triStrip.cxx). |
| } else if |
You can create just triangle fans to reduce redundant vertex information, rather than create both triangle fans and triangle strips. See “Merging Triangles Into Fans: opTriFanner”. The methods of opTriFanner work only on a csGeoSet. The function triFanTree() traverses the whole scene graph, applying the methods of opTriFanner to every csGeoSet. (see triFan.cxx). |
| }else if (doTriFan && !combineGSet) |
|
|
|
|
| if (doScale) |
Collect Vertex Statistics and Print Them |
|
|
See “Error Handling and Notification” and “Getting Statistics About a Scene Graph: opTriStats”. |
| // Get stats on the scene graph |
Write Scene Graph to File |
|
|
You can run opoptimize in batch mode without viewing the effects of the scene-graph manipulation tools. |
| if ( writeCSB) |
|
| } |
Set Parameters to Draw the Scene |
|
|
To see the effects of the scene-graph manipulations, you can use an opViewer and register the keyboard commands defined by the keyHandler() with the interaction control class, an opDrawImpl. See “Viewing Class: opViewer”, “Controlling Rendering: opKeyCallback and opDrawImpl”, and “opDrawImpl Subclasses Used In Sample Applications”. |
| if (haveSize) |
|
|
// Use default DrawImpl until pick invoked |
Draw the Scene |
|
|
You can set the model orientation. See “Viewing Class: opViewer”.
|
| viewer->addChild(root); |
You can further reduce the load on the graphics hardware by using OpenGL display lists. See “Display Lists”. |
| opDListScene((csGroup*)viewer->getRoot()); |