30.5. Optimizing for Large Amounts of Data

Overview

FEI has added new methods to the multiple field classes, for example SoMFVec3f SoMFVec3f SoMFVec3f , to allow application data to be assigned to the field without making a copy of the data. This enhancement is of particular benefit to programs that handle large amounts of data.

There are two ways to pass arguments:

  1. Pass-by-copy : Use the setValues() method. Open Inventor allocates memory and makes a copy of the application data. This memory is freed by the field destructor.

  2. Pass-by-reference : Use the setValuesPointer()SetValuesBuffer()setValuesBuffer() method. The application data is not duplicated. The application “owns” this memory and is responsible for freeing it unless the enableDeleteValues() method is called.

The example below shows a typical use of the pass-by-reference feature. It is extracted from a sample program ($OIVHOME/src/Inventor/examples/Features/NonDuplicateMField). This example displays the pointer values of the original data (vertices) and of the internal multiple-field data to show that they are the same.

Example 30.2.  Red obelisk node

SoSeparator *obelisk = new SoSeparator();
obelisk->ref();

SoVertexProperty *myVertexProperty = new SoVertexProperty;
myVertexProperty->orderedRGBA.setValue(SbColor(1.0, 0.0, 0.0).getPackedValue());

// Define coordinates for vertices with USER data
myVertexProperty->vertex.setValuesPointer(28, (float *)vertices);
myVertexProperty->vertex.enableDeleteValues();

// Define the FaceSet
SoFaceSet *myFaceSet = new SoFaceSet;
myFaceSet->numVertices.setValuesPointer(8, numvertices);
myFaceSet->numVertices.enableDeleteValues();

myFaceSet->vertexProperty.setValue(myVertexProperty);
obelisk->addChild(myFaceSet);
       
            
          
SoSeparator obelisk = new SoSeparator();

SoVertexProperty myVertexProperty = new SoVertexProperty();
myVertexProperty.orderedRGBA.setValue(new SbColor(1.0f, 0.0f, 0.0f).getPackedValue());

// Define coordinates for vertices with USER data
myVertexProperty.vertex.setValuesBuffer(vertices);

// Define the FaceSet
SoFaceSet myFaceSet = new SoFaceSet();
myFaceSet.numVertices.setValuesBuffer(numvertices);

myFaceSet.vertexProperty.setValue(myVertexProperty);
obelisk.addChild(myFaceSet);
       


Multiple field classes that support the pass-by-reference enhancement are: SoMFBool SoMFBool SoMFBool , SoMFColor SoMFColor SoMFColor , SoMFFloat SoMFFloat SoMFFloat , SoMFInt32 SoMFInt32 SoMFInt32 , SoMFUInt32 SoMFUInt32 SoMFUInt32 , SoMFShort SoMFShort SoMFShort , SoMFUShort SoMFUShort SoMFUShort , SoMFVec2f SoMFVec2f SoMFVec2f , SoMFVec3f SoMFVec3f SoMFVec3f , and SoMFVec4f SoMFVec4f SoMFVec4f .

Adding the Pass-by-Reference Enhancement to a New Multiple Field Class

This section shows how to add pass-by-reference methods to a new multiple field class. You will only need to know this if you are writing a custom class.

First, add the following macro to the multiple field class definition to declare the pass-by-reference methods and variables:

SO_MFIELD_SETVALUESPOINTER_HEADER(<storage type>);

where <storage type> is the primitive type.

The following example shows the beginning of the SoMFVec4f SoMFVec4f SoMFVec4f class declaration. The primitive type is float.

Example 30.3. Header of SoMFVec4f with pass-by-reference methods

...
class SoMFVec4f : public SoMField {             
  // Use standard field stuff 
  SO_MFIELD_HEADER(SoMFVec4f, SbVec4f, const SbVec4f &); 
  // pass-by-reference enhancement 
  SO_MFIELD_SETVALUESPOINTER_HEADER(float); 
  ...
};
       
            
          


Second, add the following macro to the multiple field class source to define the methods that are declared in SO_MFIELD_SETVALUESPOINTER_HEADER:

SO_MFIELD_SETVALUESPOINTER_SOURCE (<field name>, <basic type>, <storage type>);

where <field name> is the field class name, <basic type> is field value type, and <storage type> is the primitive type. The following example shows the line added to SoMFVec4f SoMFVec4f SoMFVec4f to enable the pass-by-reference enhancement.

Example 30.4. Source of SoMFVec4f with pass-by-reference methods

...
SO_MFIELD_SETVALUESPOINTER_SOURCE(SoMFVec4f, SbVec4f, float);
...


Optimizing a Non-Cached Scene

If the geometry or the appearance of some shapes in your scene graph is frequently modified, for example, to do animation, these shapes will be not cached. This means that at each modification, all vertices, normals, colors, and texture coordinates to render these shapes will be sent from main memory to the graphics board. With large models, this data transfer can be be a performance bottleneck.

Vertex Buffer Objects ( VBOs), which are a standard feature of OpenGL 1.5 and an extension feature (ARB_vertex_buffer_object) in previous OpenGL versions, provide a mechanism to store certain kinds of data in high performance memory on the graphics board. Open Inventor provides access to this OpenGL feature through the field SoShapeHints::useVBO . Setting this field to TRUE allows subsequent indexed shapes (SoIndexedFaceSet SoIndexedFaceSet SoIndexedFaceSet and SoIndexedTriangleStripSet SoIndexedTriangleStripSet SoIndexedTriangleStripSet )) to use VBO to speed up rendering.

When VBO usage is allowed, a VBO is created for each data array (indices, vertices, normals, colors, texture coords...). When a change to one of the data arrays is detected after the first rendering (for instance, the color values changed), the corresponding VBO is updated on the hardware, but the other buffers (for instance, vertices, texture coords...) are not changed.

If this OpenGL feature is not available, setting the useVBO field to TRUE has no effect.

An example of use is available in $OIVHOME/src/Inventor/examples/Features/VBO. This example allows you to turn VBO usage on and off so that you can see its effect on performance.