SGI Techpubs Library

IRIX 6.5  »  Books  »  Developer  »  
OpenGL Optimizer Programmer's Guide: An Open API for Large-Model Visualization
(document number: 007-2852-002 / published: 1998-06-09)    table of contents  |  additional info  |  download
find in page

Chapter 10. Creating and Maintaining Surface Topology

Most objects in a large model are made of many parametric surfaces. The OpenGL Optimizer classes that describe the connectivity of parametric surfaces, that is, their topology, allow you to “stitch” surfaces together by defining shared boundary curves, and to propagate surface contact information.

The main purpose for shared-boundary information is to generate tessellations of adjacent surfaces that are consistent, that is, no cracks develop between any pair of rendered surfaces. Tessellations are discrete approximations of surfaces in terms of renderable geometric primitives, typically triangles (see Chapter 11, “Rendering Higher-Order Primitives: Tessellators”).

These topics are covered in this chapter:

Overview of Topology Tasks

The topology classes provide definitions of boundary curves shared by adjacent parametric surfaces. Discrete versions of these curves are used by tessellators to prevent cracks. A rendered image can have artificial cracks due to the following:

  • Difficulty sampling enough points on the boundary between two surfaces so that mismatches of the tessellations are imperceptible

  • Finite-precision mismatches between coordinates of ideally identical points, for example at triple junctions where the edges of three surfaces meet at a point

Propagating surface contact information is useful for other tasks, such as

  • Maintaining consistent normal vectors for adjacent surfaces

  • Deforming a surface and consistently deform an adjacent surface

  • Determining whether an edge of a surface is in fact a shared boundary

  • Creating a mirror image of a compound surface (you can use topological information to reorient the surface)

Summary of Scene Graph Topology: opTopo

The class opTopo holds data that indicates whether, and how, two opParaSurfaces are in contact. You can create several opTopos for a particular scene: for example, one each for subassemblies. A static member of opTopo lists all the opTopos that you create.

opTopo maintains lists of surfaces and boundaries (opBoundarys) that are shared by an arbitrary number of surfaces. Figure 10-1 illustrates how these data structures define relations between opParaSurfaces.

When an edge has been tessellated, the associated opBoundary holds a discrete version of the curve. This discrete version is needed for consistent tessellations because it specifies one set of boundary vertices for tessellating all the surfaces that share the boundary. The role of opBoundary in determining a consistent tessellation is illustrated in Figure 10-2.

The classes opTopo and opBoundary are examples of b-reps, which identify objects in terms of their bounding objects. opBoundary is also winged data structures, a particular form of b-rep. For more information on these structures, see the book Computer Graphics: Principles and Practice listed in “Recommended Background Reading”.

Figure 10-1. Topological Relations Maintained by Topology Classes

Figure 10-1 Topological Relations Maintained by Topology Classes

Figure 10-2. Consistently Tessellated Adjacent Surfaces and Related Objects

Figure 10-2 Consistently Tessellated Adjacent Surfaces and Related Objects

Building Topology: Computing and Using Connectivity Information

Given a set of opParaSurfaces in a scene graph, there are several ways to develop a set of shared vertices to be held in opBoundarys. The following sections describe the topology construction strategies (beyond the low-fidelity alternative of ignoring topology):

Building Topology Incrementally: A Single-Traversal Build

As each surface is tessellated during a traversal, the tessellator checks for previously tessellated adjacent surfaces, uses existing vertices when it can, and adds necessary data to topology data structures.

Although OpenGL Optimizer's incremental topology building tools attempt to avoid cracks, they can, in principle, appear: When a surface is added, a new junction on the boundary of an existing, tessellated surface may occur and the junction point may not be in the existing tessellation. The tessellation of the added surface introduces the junction point, necessarily at a finite distance from the existing tessellation, and a crack appears between the newly and previously tessellated surfaces.

Building Topology From All Scene Graph Surfaces: A Two-Traversal Build

Topology built with two passes is very clean; unlike a single-pass build, in principle no cracks due to unforeseen junctions can occur. The added cost of performing a two-traversal build is slight; it is the recommended way to build topology and perform tessellations if you want high-quality images. When building topology in two traversals, the following steps occur:

  1. Connectivity of all surfaces is calculated during a topology building traversal of the scene graph, before a tessellation traversal.

  2. The surfaces in the scene are tessellated during a second traversal.

Building Topology From a List of Surfaces

You can explicitly accumulate a list of surfaces for which to build topology and then tessellate the surfaces. The result is clean tessellations of the surfaces on the list. Cracks may appear if an adjacent surface was not included in the list.

Building Topology “by Hand”: Imported Surfaces

If you have a set of surfaces for which you know connectivity, you can explicitly develop the appropriate topological data structures and develop consistent tessellations.

The presence of cracks will depend on how good your input trim curves are. If three surfaces meet at a junction point that is not the shared endpoint of trim curves, a crack may appear.

Summary of Topology Building Strategies

Table 10-1 lists the methods required for each of the topology building strategies. See “Base Class opTessellateAction” for more information about the tessellation methods listed.

Table 10-1. Topology Building Methods

Topology Building Strategy

 

Methods

Ignore topology information and let cracks appear as they will.

 

1. Do not create an opTopo or build topology.
2. opTessellateAction::setBuildTopoWhileTess( FALSE ).
3. opTessellateAction::apply()

Build topology incrementally.

 

1. Create an opTopo.
2. opTessellateAction::setBuildTopoWhileTess( TRUE ).
3. opTessellateAction::setTopo(topo).
4. opTessellateAction::apply( root ).

Two-traversal build.

 

1. Create an opTopo.
2. opTopo::buildTopologyTraverse( root ).
3. opTessellateAction::setBuildTopoWhileTess( FALSE ).
4. opTessellateAction::apply( root ).

Assemble a list of surfaces, build the topology, and then tessellate.

 

1. Create an opTopo.
2. Assemble list of surfaces: opTopo::addSurface( surf ).
3. opTopo::buildTopology().
4. opTessellateAction::setBuildTopoWhileTess( FALSE ).
5. opTessellateAction::apply( shape ).

Build the topology “by hand.”

See the file src/apps/topoTest/topoTest.cxx (step 7 does not appear in the code because FALSE is the default).

 

1. Create an opTopo.
2. Assemble list of surfaces: opTopo::addSurface().
3. Create opBoundarys.
4. Add to list of boundaries: opTopo::addBoundary().
5. Add edges to boundaries: opBoundary::addEdge().
6. Set boundary orientation: opEdge::setBoundaryDir().
7. opTessellateAction::setBuildTopoWhileTess( FALSE ).
8. opTessellateAction::apply( shape ).


Reading and Writing Topology Information: Using opoptimize

You can add topological information to an existing set of connected, higher-order surfaces in a file—for example NURBS in an .iv file—and save the information for future, crack-free surface rendering. As a result, you don't have to repeat the topology build. The method opGenLoader::load() reads the topological information in a .csb file. See “Saving and Loading Scene-Graph Files”.

Before you save the scene graph data, you can also add tessellations that use the topology to give crack-free images (see Chapter 11, “Rendering Higher-Order Primitives: Tessellators”).

The demonstration program opoptimize illustrates how to perform these steps (see , “Scene Graph Tuning With the opoptimize Application” and /usr/share/Optimizer/apps/sample/opoptimize).

Table 10-2 shows three possible file conversions that you can apply to .iv or .csb files that contain reps but no topology or tessellation; they are listed with example opoptimize command lines.

Table 10-2. Adding Topology and Tessellations to .iv and .csb Files

Conversion

 

Example Command Line

Format change only.

 

opoptimize sur.iv -tess no -batch sur.csb

Add topology information to scene graph: save reps and topology information but not tessellations.

 

 

opoptimize sur.iv -tess no -ttol topoTol -batch surTopo.csbor

 

opoptimize sur.csb -tess no -ttol topoTol -batch surTopo.csb

Add topology information and tessellations to scene graph: save reps, topology, and tessellations.

 

 

opoptimize sur.iv -ttol topoTol -batch surTopoTess.csbor

 

opoptimize sur.csb -ttol topoTol -batch surTopoTess.csb

If you perform conversion, you may have files with or without tessellations. Depending on the type of file you read, use one of the command lines in Table 10-3.

Table 10-3. Reading .csb Files: With and Without Tessellations

To read a .csb file and perform tessellation (without having to build topology):

 

opoptimize surTopo.csb -ctol tessTol

To read a .csb file that already has tessellations

 

opoptimize surTopoTess.csb -tess no



Note: If you attempt to load a tessellated surface, no additional tessellation is performed.

To delete the tessellation date, use the method clearTessellation().

Class Declaration for opTopo

The following are the main methods in the class:

class opTopo : public csNode
{
public:
// Creating and destroying
opTopo( opReal tol = 1.0e-3, 
        opLengthUnits u = meter, 
        int sizeEstimate = 1024 );
~opTopo();

// Accessor functions
void setDistanceTol( opReal tol, opLengthUnits u ) 
opReal getDistanceTol( ) 

opParaSurface* getSurface(  int i );  
int getSurfaceCount( );  

opBoundary* getBoundary( int i );
int getBoundaryCount(  );

int getSolidCount() 
opSolid* getSolid( int i )

//Adding topological elements
int addSurface(  opParaSurface *sur );
int addBoundary( opBoundary    *bnd ); 

//Topology construction
void buildTopology();
void buildTopologyTraverse(csNode *n);
int  buildSolids();
};

Methods in opTopo

buildSolids() 

Collects connected surfaces in the opTopo into opSolids (see “Collecting Connected Surfaces: opSolid”.

buildTopology() 


Builds consistent set of boundaries from the list of surfaces accumulated by calls to addSurface(). Previously developed boundaries are deleted.

buildTopologyTraverse() 


Traverses a scene graph and builds a consistent set of boundaries for all surfaces in the graph.

opTopo(tol,u,sizeEstimate) 


Construct a topological data structure.

tol specifies a tolerance for calculating when points are close enough together to be considered the same. Default is 1 millimeter.

u specifies the system of units for tol. Default is meters.

sizeEstimate specifies an estimate of the number of surfaces whose topology needs to be maintained.

The static member topology is an array of all topologies that have been created.

Consistent Vertices at Boundaries: opBoundary

The opBoundary class is an element in the list of boundaries are shared by parametric surfaces that is maintained by opTopo. An opBoundary holds a curve that represents a common boundary, and points to adjoining surfaces. Notice that an opBoundary can include any number of surfaces that share a particular curve as a boundary, so it can represent the intersection of several surfaces and allow you to describe a non-manifold surface structure. An opBoundary can also hold just one surface, and thus represent a free edge.

The opBoundary class holds an opDisCurve3d xyzBoundary, which is derived from a tessellation, to store a discrete version of a shared boundary. The unique discrete version guarantees that tessellations of adjoining surfaces share the same vertices along the boundary and so prevents the development of cracks.

In addition to information identifying each surface, opBoundary stores the index used by each opParaSurface to identify the trim curve that defines the shared boundary. Because a boundary may consist of several trim curves, more than one trim curve, and therefore more than one opBoundary, can define a geometric boundary between two surfaces.

If you have an opParaSurface and want to identify adjacent surfaces, you have two options. The simplest is to find the opSolid that holds the surface, using the opParaSurface member _solid_id. At a lower level, you can identify each opBoundary associated with the surface by using the boundary index that is stored in each of the surface's opEdge trim curves. The boundary index identifies opBoundary members in the opTopo list. From each member of the list, you can identify surfaces that share that boundary. See the section “Parametric Surfaces” in Chapter 9 for more information about opEdge.

Class Declaration for opBoundary

The following are the main methods in the class:

class opBoundary
{
public:
opBoundary( );
~opBoundary( );

// Accessor functions
void addEdge( int i, opParaSurface &sur, int trimLoop, int trimCurve );
int getSurface( int i );
int getLoop( int i );
int getTrimCurve( int i );
int getWingCount();
int getBoundaryId();

// Copy
opBoundary* clone(csNode::CloneEnum what);
};

Methods in opBoundary

opBoundary() 

Constructs an empty boundary.

addEdge(i, sur, trimLoop, trimCurve) 


“Attaches” the surface with index i to the boundary and identifies the trim loop and trim curve that define the boundary in that surface. The index sur is from the opTopo list of all opParaSurfaces. The indices trimLoop and trimCurve are from the doubly indexed list in the opParaSurface.

getSurface(i)  

Returns the opTopo index of the opBoundary surface with index i. The other get*() functions return elements associated with the surface. See “Parametric Surfaces” for more details about the returned objects.

xyzBoundary  

Is a discrete representation of the boundary curve. Notice that the curve is not in the coordinate space of any of the surfaces but represents the boundary as a curve in three-dimensional space. This curve defines the set of vertices used in the tessellations of all surfaces that share this boundary.

The set*() methods, which you can find in opBoundary.h, are mainly for use when reading topological data from a file. For example, they are used by the .csb loader in opGenLoader to create topological objects when reading a file (see “Saving and Loading Scene-Graph Files”).

Collecting Connected Surfaces: opSolid

To maintain consistent normals or propagate deformation information, organize connected opParaSurfaces in an opSolid. With an opSolid, you can collect connected surface patches in one object for convenient access and manipulation.

Despite the name of the class, the set of surfaces need not form a closed surface, that is the boundary of a volume. They can be a set of patches joined to form a surface, for example, you might generate a hood of a car from two opParaSurafaces that are mirror images of each other.

To create solids, collect them in an opTopo and then call opTopo::buildSolid() (see “Summary of Scene Graph Topology: opTopo”).

Class Declaration for opSolid

The following are the main methods in the class:

class opSolid
{
public:

// Creating and destroying
opSolid()
~opSolid()

// Accessor functions
int addSurface(  opParaSurface *sur );
opParaSurface* getSurface( int i);
int getSurfaceCount( );
int getSolidId();
};

Methods in opSolid

Use the methods only after you have created an opSolid with opTopo::buildSolid().

Treat the method setSolidId() that appears in opSolid.h as private: it is used by opTopo::buildSolid() when building the solid.

OpenGL Optimizer Programmer's Guide: An Open API for Large-Model Visualization
(document number: 007-2852-002 / published: 1998-06-09)    table of contents  |  additional info  |  download

    Front Matter
    About This Guide
    Part I. Getting Started
    Part II. High-Level Strategic Tools for Fast Rendering
    Part III. Specific Tools for Fast Rendering
    Part IV. Managing and Rendering Higher-Order Geometric Primitives
    Part V. Traversers, Low-Level Geometry Processing, and Multiprocessing
    Part VI. Utilities and Troubleshooting
    Part VII. Appendices
    Glossary
    Index


home/search | what's new | help