22.3. Using the VRML Nodes

Introduction

This section gets right down to the gritty technical details of using VRML in an Open Inventor application. This is mostly for programmers with some Open Inventor experience, but will give you a flavor of how Open Inventor works if you are somewhat familiar with VRML.

Class Names

Many of the VRML nodes have the same (or very similar) name as an existing Open Inventor node, but have different fields and/or different behavior. For example, both VRML and Open Inventor have an IndexedFaceSet node, but their fields are quite different. In order to clearly differentiate the VRML nodes, their class names all begin with the string “ SoVRML ”, while the traditional Open Inventor class names begin with just “So”. For example, the VRML version of IndexedFaceSet is implemented in class SoVRMLIndexedFaceSet SoVRMLIndexedFaceSet SoVRMLIndexedFaceSet , while the original Open Inventor IndexedFaceSet is implemented in class SoIndexedFaceSet SoIndexedFaceSet SoIndexedFaceSet . This also allows applications to easily distinguish these nodes in cases where it is important, for example, to write out only valid VRML nodes. The important thing to remember is that, in the Open Inventor tool kit, VRML nodes are Open Inventor nodes. They are created and manipulated the same way and share the same properties such as reference counting and persistence.

Scene Graph

General Structure

VRML has essentially the same scene graph concept as Open Inventor, with some notable exceptions:

One of the most significant differences in a VRML scene graph is that geometry and attribute nodes cannot be direct children of a grouping node. A geometry node and its associated attributes can only appear as part of a VRML Shape node (class SoVRMLShape SoVRMLShape SoVRMLShape ). Again, VRML scene graphs end up somewhat more deeply nested than traditional Open Inventor. However it is much easier to find the attributes that immediately affect a primitive, because they are always contained in the Shape node. In other words, you never have to search the hierarchy or traverse the scene graph to accumulate attributes.

Example 22.1. A cone (.iv file)

Let’s look at a simple example: the classic “Red Cone.” First we will look at the file format to see how the various nodes and fields fit together.

Later we will look at the code that creates this hierarchy (although you can probably deduce most of that from your Open Inventor experience).

Here is the traditional Open Inventor scene graph to display a red cone:

#Inventor V2.1 ascii
  Separator
    {
    Material { diffuseColor 1 0 0 }
    Cone {}
    }


Example 22.2. A cone (VRML97 format file)

Now here is the equivalent VRML97 scene graph to display a red cone:

#VRML V2.0 utf8
    Transform { 
        children Shape { 
            appearance Appearance { 
                material Material { diffuseColor 1 0 0 } 
            } 
            geometry Cone {} 
        }
    }


Example 22.3. A cone (X3D Classic VRML format file)

Here is the equivalent X3D scene graph to display a red cone:

#X3D V3.0 utf8
    Transform { 
        children Shape { 
            appearance Appearance { 
                material Material { diffuseColor 1 0 0 } 
            } 
            geometry Cone {} 
        }
    }

For these nodes, the file is exactly the same as the VRML97 file except for the header. For a few nodes, there will be differences between the VRML97 and X3D file formats.



Note first that SoVRMLTransform SoVRMLTransform SoVRMLTransform is a grouping node similar to SoSeparator SoSeparator SoSeparator , but unlike SoSeparator SoSeparator SoSeparator it does not handle children at the same syntactic level as fields. Instead the children are specified as the value of its children field, which has the type SoMFNode SoMFNode SoMFNode . (In the code example you will see that the familiar addChild (etc.) methods have been implemented in this class for convenience.) Next notice the SoVRMLShape SoVRMLShape SoVRMLShape node, which has two fields – appearance and geometry – each of which has the type SoSFNode SoSFNode SoSFNode . The only thing that can be put into the appearance field is an SoVRMLAppearance SoVRMLAppearance SoVRMLAppearance node. This may seem redundant but it is important to have Appearance as a node so that multiple Shape nodes can instance, or point to, the same Appearance node. Otherwise VRML hierarchies would use too much memory (if appearance information had to be duplicated for every Shape node). Next note that the Appearance node has a material field (type SoSFNode SoSFNode SoSFNode ) that can only contain an SoVRMLMaterial SoVRMLMaterial SoVRMLMaterial node. The Material node contains fields diffuseColor, etc., similar to the traditional Open Inventor material node. (More about this later.) Finally, note that the geometry field of SoVRMLShape SoVRMLShape SoVRMLShape can be assigned any VRML geometry node. These include Cone , Sphere , Box (similar to SoCube SoCube SoCube ), and so on.

Example 22.4.  C++ code for “Red Cone”

Here is the C++ code that creates the traditional Open Inventor “red cone” scene graph, roughly corresponding to the first Inventor Mentor example (see Example 2.1, “ Basic “Hello, Cone” Program):

// Classic Open Inventor nodes
SoSeparator *pRoot = new SoSeparator;
SoMaterial *pMat = new SoMaterial;

pMat->diffuseColor.setValue(1, 0, 0);
pRoot->addChild(pMat);

pRoot->addChild(new SoCone);
  
// Classic Open Inventor nodes
SoSeparator root = new SoSeparator();
SoMaterial mat = new SoMaterial();

mat.diffuseColor.SetValue(1, 0, 0);
root.AddChild(mat);

root.AddChild(new SoCone());
// Classic Open Inventor nodes
SoSeparator root = new SoSeparator();
SoMaterial mat = new SoMaterial();

mat.diffuseColor.setValue(1, 0, 0);
root.addChild(mat);

root.addChild(new SoCone());


Example 22.5. C++ code to create a VRML “Red Cone”

// VRML nodes
SoVRMLTransform *pRoot = new SoVRMLTransform;
SoVRMLShape *pShape = new SoVRMLShape;
SoVRMLAppearance *pApp = new SoVRMLAppearance;
SoVRMLMaterial *pMat = new SoVRMLMaterial;

pMat->diffuseColor.setValue(1, 0, 0);
pApp->material.setValue(pMat);
pShape->appearance.setValue(pApp);
pShape->geometry.setValue(new SoVRMLCone);

pRoot->addChild(pShape);
  
// VRML nodes
SoVRMLTransform root = new SoVRMLTransform();
SoVRMLShape shape = new SoVRMLShape();
SoVRMLAppearance app = new SoVRMLAppearance();
SoVRMLMaterial mat = new SoVRMLMaterial();

mat.diffuseColor.SetValue(1, 0, 0);
app.material.SetValue(mat);
shape.appearance.SetValue(app);
shape.geometry.SetValue(new SoVRMLCone());

root.AddChild(shape);
// VRML nodes
SoVRMLTransform root = new SoVRMLTransform();
SoVRMLShape shape = new SoVRMLShape();
SoVRMLAppearance app = new SoVRMLAppearance();
SoVRMLMaterial mat = new SoVRMLMaterial();

mat.diffuseColor.setValue(1, 0, 0);
app.material.setValue(mat);
shape.appearance.setValue(app);
shape.geometry.setValue(new SoVRMLCone());

root.addChild(shape);


We call pRoot->addChild to insert the geometry into the scene graph in both examples, because both SoSeparator SoSeparator SoSeparator and SoVRMLTransform SoVRMLTransform SoVRMLTransform are grouping nodes. However also note that we use “ addChild ” to insert “ pMat ” (the Material node) into the scene graph in the first example, but we use “ setValue” in the second example because the VRML Material node goes into the material field of the VRML Appearance node.

Inheritance

In general, VRML nodes do not inherit any attributes except transformation. However, for consistency, the VRML nodes do inherit (and respond correctly) to some very useful Open Inventor attributes that are not part of the VRML specification. These attributes include DrawStyle (note that line width and point size cannot be specified in a VRML97 file) and Complexity (no equivalent in VRML). Note that line properties were introduced in the X3D specification and are set using the SoVRMLLineProperties SoVRMLLineProperties SoVRMLLineProperties node. This node is in the lineProperties field of the SoVRMLAppearance SoVRMLAppearance SoVRMLAppearance node. Note also that the attributes of SoShapeHints SoShapeHints SoShapeHints are not inherited by VRML nodes because these values are specified directly in VRML geometry nodes.

Example 22.6.  Two red cones

Here is a simple Open Inventor scene graph showing two cones, translated to slightly different positions, and both inheriting the color “red”:

  Separator
    {
    Material { diffuseColor 1 0 0 }
    # Red

      Separator
      {
      Transform { translation -1 0 0 }
      # Translate left Cone
        {
        }
      }

    Separator
      {
      Transform
        {
        translation 1 0 0
        }
      # Translate right Cone
        {
        }
      }
    }
        


Example 22.7. Inheritance of color in an Open Inventor scene graph

Example 22.6, “ Two red cones ”, is not necessarily a realistic example since this type of attribute inheritance makes it relatively difficult to interactively change the attributes of a specific object. It also makes it difficult to modify the scene graph itself since the attribute inheritance shown here depends on a specific ordering of the nodes under the top Separator. The following scene graph is more realistic and makes it easier to see the parallels with the analogous VRML scene graph:

  Separator
    {
    Separator
      {
      DEF Red Material { diffuseColor 1 0 0 }
      # Red
        Transform { translation -1 0 0 }
      # Translate left Cone
        {
        }
      }
    Separator
      {
      USE Red Transform { translation 1 0 0 }
      # Translate right Cone
        {
        }
      }
    }



Example 22.8. Inheritance of color in a VRML scene graph

Now each of the second level Separators is more representative of an object bundled with its appearance and position. In order to minimize the memory used by the scene graph and allow the two objects to share a common appearance, we name the Material node in the first object and reference it in the second object. Here is the equivalent VRML scene graph:

  Transform
    {
    children [
      Transform
      {
      translation -1 0 0 # Translate left
        children Shape
        {
        appearance DEF Red Appearance
          {
          material Material
            {
            diffuseColor 1 0 0
            }
          # Red
          }
        geometry Cone
          {
          }
        }
      }
    Transform
      {
      translation 1 0 0 # Translate right
        children Shape
        {
        appearance USE Red geometry Cone
          {
          }
        }
      }
    ]
    }


First, note that the children field of the first VRML Transform node has multiple values (children) so we must use the “[ ]” syntax (which is not required when there is only a single child). Next, notice how the VRML Transform node combines the function of the Separator and (Open Inventor) Transform nodes in the previous example, providing both a new level of hierarchy and a translation. Finally, notice that we named the Appearance node containing the color Red in the first object and referenced it in the second object’s Shape node, similar to the previous example. Alternatively we could have named the Material node in the first object and referenced it in the second object’s Appearance node. It all depends on what effect we are trying to achieve.

Grouping nodes

In general, the VRML node classes are derived from SoVRMLNode SoVRMLNode SoVRMLNode , which is derived from class SoNode SoNode SoNode . The abstract class SoVRMLNode SoVRMLNode SoVRMLNode was introduced to add the metadata field to all new and existing VRML nodes (metadata is part of the X3D specification). However the VRML grouping node classes are derived from class SoGroup SoGroup SoGroup (as are all the traditional Open Inventor grouping node classes). This is because many Open Inventor features depend on being able to identify a grouping node using isOfType(SoGroup::getClassTypeId()). Therefore the VRML grouping nodes also return TRUE for this query.

The traditional Open Inventor grouping nodes maintain their children in a hidden list which can only be accessed by methods like addChild, removeChild, insertChild, and so on. The VRML grouping nodes maintain their children in an SoMFNode SoMFNode SoMFNode field, which can be accessed by the usual SoMF field methods like setValues and set1Value. However, for convenience, the VRML grouping nodes also support the familiar addChild (etc.) methods.

SoVRMLTransform *pTrans = new SoVRMLTransform;
SoVRMLShape *pShape = new SoVRMLShape;

pTrans->addChild(pShape);    // Is equivalent to...
pTrans->children.setValue(pShape);
         
SoVRMLTransform trans = new SoVRMLTransform();
SoVRMLShape shape = new SoVRMLShape();

trans.AddChild(shape);    // Is equivalent to...
trans.children.SetValue(shape);
         
SoVRMLTransform trans = new SoVRMLTransform();
SoVRMLShape shape = new SoVRMLShape();

trans.addChild(shape);    // Is equivalent to...
trans.children.setValue(shape);
         

In general, the VRML grouping nodes have a field named children and the corresponding method names addChild() (etc.) make sense. However SoVRMLSwitch SoVRMLSwitch SoVRMLSwitch maintains its children in a field named choice, therefore the access methods are named addChoice(), removeChoice(), and so on. Similarly SoVRMLLOD SoVRMLLOD SoVRMLLOD maintains its children in a field named levels, therefore the access methods are named addLevel(), removeLevel(), and so on.

In the X3D specification, the choice field in SoVRMLSwitch SoVRMLSwitch SoVRMLSwitch was changed to children as was the level field in SoVRMLLOD SoVRMLLOD SoVRMLLOD . Both fields were kept so that either VRML97 or X3D files can be read by Open Inventor.

SoVRMLSwitch *pSwtch = new SoVRMLSwitch;
SoVRMLShape *pShape = new SoVRMLShape;

pSwtch->addChoice(pShape);           // Is equivalent to... for VRML97
pSwtch->choice.setValue(pShape);

pSwtch->addChild(pShape);            // Is equivalent to... for X3D
pSwtch->children.setValue(pShape);
         
SoVRMLSwitch swtch = new SoVRMLSwitch();
SoVRMLShape shape = new SoVRMLShape();

swtch.AddChoice(shape);           // Is equivalent to... for VRML97
swtch.choice.SetValue(shape);

swtch.AddChild(shape);            // Is equivalent to... for X3D
swtch.children.SetValue(shape);
         
SoVRMLSwitch swtch = new SoVRMLSwitch();
SoVRMLShape shape = new SoVRMLShape();

swtch.addChoice(shape);           // Is equivalent to... for VRML97
swtch.choice.setValue(shape);

swtch.addChild(shape);            // Is equivalent to... for X3D
swtch.children.setValue(shape);
         

In Open Inventor the VRML Transform node (class SoVRMLTransform SoVRMLTransform SoVRMLTransform ) has the same special capabilities as a Separator node (class SoSeparator SoSeparator SoSeparator ), including:

  • Render caching,

  • Bounding box caching,

  • Render culling, and

  • Pick culling.

The fields associated with these capabilities are defined for SoVRMLTransform SoVRMLTransform SoVRMLTransform , but are not written when saving the scene graph to a VRML format file. See SoSeparator SoSeparator SoSeparator for more information.

Routes

VRML ROUTE statements are just a different way of specifying field-to-field connections in a file. As discussed in the the section called “ Files”, Open Inventor will automatically create any connections specified by ROUTE statements when it reads a VRML file. Conversely, Open Inventor will automatically generate ROUTE statements for any connections that exist when it writes a VRML file. In an application you can still use a field’s connectFrom() method to create a new connection (ROUTE) to it from another field. However you can also use the new static method SoDB::createRoute() to create a connection. This method takes pointers to each of the nodes and the names of the two fields to be connected. If you are working in a “pure” VRML mode, this is the recommended method. For example, creating a ROUTE from an SoVRMLTouchSensor SoVRMLTouchSensor SoVRMLTouchSensor to an SoVRMLPointLight SoVRMLPointLight SoVRMLPointLight , so that clicking on the geometry associated with the TouchSensor will turn on the light:

SoVRMLTouchSensor *pTouch = new SoVRMLTouchSensor;
SoVRMLPointLight *pLight = new SoVRMLPointLight;

SoDB::createRoute(pTouch, "isActive", pLight, "set_on");
        
SoVRMLTouchSensor touch = new SoVRMLTouchSensor();
SoVRMLPointLight light = new SoVRMLPointLight();

SoDB.CreateRoute(touch, "isActive", light, "set_on");
        
SoVRMLTouchSensor touch = new SoVRMLTouchSensor();
SoVRMLPointLight light = new SoVRMLPointLight();

SoDB.createRoute(touch, "isActive", light, "set_on");
        

The traditional Open Inventor nodes allow connections between fields of different types, as long as a reasonable conversion exists (Open Inventor does the conversion automatically). VRML only allows connections (ROUTEs) between fields with exactly the same type. For example, you cannot connect an SoSFFloat SoSFFloat SoSFFloat field to an SoSFInt32 SoSFInt32 SoSFInt32 field. Open Inventor enforces this restriction for VRML nodes when you use SoDB::createRoute() to create the ROUTE. Note that the fields in the example above both have type SoSFBool SoSFBool SoSFBool .

The VRML97 specification uses the term “field” in a much more specific sense than traditional Open Inventor does. In the VRML97 specification you will see several other terms used, including eventIn, eventOut, field, and exposedField. Open Inventor implements all these objects as fields (in the Open Inventor sense) which have certain properties associated with them. The properties are:

  • EventIn: A ROUTE can be connected to this field.

  • EventOut: A ROUTE can be connected from this field.

  • Field: No connections are allowed.

  • ExposedField: Combines the EventIn and EventOut properties.

The X3D specification uses a slightly different notation for indicating the meanings of eventIn, eventOut, field, and exposedField.

  • [in] is an eventIn,

  • [in,out] is an exposedField,

  • [out] is an eventOut,

  • [ ] is a field.

For the following discussions, only the VRML97 notation is used since both methods have the same meaning.

VRML only allows connections (ROUTEs) from an eventOut to an eventIn. In Open Inventor this means a ROUTE is only allowed from a field with the EventOut property to a field with the eventIn property. Fields declared as an exposedField in the VRML specification have both properties. Open Inventor enforces this restriction for VRML nodes when you use SoDB::createRoute() to create the ROUTE.

The VRML specification says that an exposedField is a “shorthand” for declaring that an eventIn, a field, and an eventOut with the same base name exist in the node, implying that there are three separate objects. For example, an exposedField named “children” implies these objects:

  • An eventIn named: set_children

  • A field named: children

  • An eventOut named: children_changed

In the Open Inventor implementation, an exposedField is represented by a single field, which has both the eventIn and the eventOut properties, representing all three objects. In the example above (which is common to most of the VRML grouping nodes), the Open Inventor class has a single field named “children”. However, in this case either the base name or the eventIn / eventOut name is accepted by the SoDB::createRoute() method (just as it is by the ROUTE statement in a file). So the previous example with the SoVRMLTouchSensor SoVRMLTouchSensor SoVRMLTouchSensor and the SoVRMLPointLight SoVRMLPointLight SoVRMLPointLight could also look like this:

SoVRMLTouchSensor *pTouch = new SoVRMLTouchSensor;
SoVRMLPointLight *pLight = new SoVRMLPointLight;

SoDB::createRoute(pTouch, "isActive", pLight, "on");
        
SoVRMLTouchSensor touch = new SoVRMLTouchSensor();
SoVRMLPointLight light = new SoVRMLPointLight();

SoDB.CreateRoute(touch, "isActive", light, "on");
        
SoVRMLTouchSensor touch = new SoVRMLTouchSensor();
SoVRMLPointLight light = new SoVRMLPointLight();

SoDB.createRoute(touch, "isActive", light, "on");
        

The VRML specification also talks about “events” being sent from one node to another through the ROUTEs. These events are “conceptual” and only exist for the purpose of explaining the model. Open Inventor does not literally implement these events.

Actions

Rendering

Rendering works essentially the same for VRML nodes as for traditional Open Inventor nodes. However, in addition to the difference in attribute inheritance discussed above, there are some specific differences required by the VRML specification, including:

  • Lines (SoVRMLIndexedLineSet SoVRMLIndexedLineSet SoVRMLIndexedLineSet ) and Points (SoVRMLPointSet SoVRMLPointSet SoVRMLPointSet ) are not lit or textured (in other words lighting and texturing are always disabled when rendering these primitives).

  • There is no explicit equivalent of Open Inventor’s SoMaterialBinding SoMaterialBinding SoMaterialBinding in VRML. However the same effects can be achieved for IndexedFaceSet as follows: For OVERALL binding, provide a VRML Material node and leave the color field empty (NULL). For PER_FACE binding, provide a VRML Color node in the color field and set the colorPerVertex field to FALSE. For PER_VERTEX binding, provide a VRML Color node in the color field and leave the colorPerVertex field set to TRUE.

  • There is no explicit equivalent of Open Inventor’s SoLightModel SoLightModel SoLightModel in VRML. However, you can turn off lighting for a particular Shape. If either the appearance field in the VRML Shape node or the material field in the VRML Appearance node is NULL, then lighting is disabled for that Shape. If lighting is disabled and there is no VRML Color node in the geometry’s color field, then the geometry is White (unlit).

  • There is no equivalent of Open Inventor’s texture mapping “model” (Modulate, Decal, or Blend) in VRML. Instead the texture mapping behavior is hardwired and depends on the number of components in the texture image. For 1- and 2-component textures (Intensity and Intensity plus Alpha) the object color is multiplied by the texture intensity value, similar to Modulate mode. This is useful because, in effect, the texture takes on the color of the object. For 3- and 4-component textures (RGB and RGB plus Alpha) the object color is replaced by the texture color, similar to Decal mode.

    However, that is not quite the end of the story for 3- and 4-component textures. VRML also specifies that lighting is applied after texturing. In other words, if the object is lit, then the object color is replaced by the texture color and lighting modifies that color (the texture color). OpenGL actually applies textures after lighting (the opposite order), but Open Inventor adjusts the parameters sent to OpenGL and achieves the correct effect.

Picking

Picking works for VRML geometry as well as traditional Open Inventor geometry. Both explicit SoRayPickAction SoRayPickAction SoRayPickAction and implicit SoSelection SoSelection SoSelection picking return a “pick path” (class SoPath SoPath SoPath ). For traditional Open Inventor geometry, the “tail” (last node) of the path will be the actual geometry node that was picked. However, for VRML geometry, the tail of the path will be the Shape node (class SoVRMLShape SoVRMLShape SoVRMLShape ) that contains the picked geometry. The actual geometry node is contained in the Shape node’s geometry field. Conveniently, the rendering attributes for this geometry are defined by the Appearance node (class SoVRMLAppearance SoVRMLAppearance SoVRMLAppearance ) that is contained in the Shape node’s appearance field. For example, in a pure VRML scene graph:

SoPath *pSelPath = <selection path from SoSelection node>

SoVRMLShape *pShape = pSelPath->getTail();

SoVRMLAppearance *pApp = pShape->appearance.getValue();
SoVRMLMaterial *pMat = NULL;
if (pApp != NULL)
  pMat = pApp->material.getValue();

          
SoPath selPath = <selection path from SoSelection node>;

SoVRMLShape shape = (SoVRMLShape)selPath.GetTail();

SoVRMLAppearance app = (SoVRMLAppearance)shape.appearance.GetValue();
SoVRMLMaterial mat = null;
if (app != null)
  mat = (SoVRMLMaterial)app.material.GetValue();
        
SoPath selPath = <selection path from SoSelection node>;

SoVRMLShape shape = (SoVRMLShape)selPath.regular.getTail();

SoVRMLAppearance app = (SoVRMLAppearance)shape.appearance.getValue();
SoVRMLMaterial mat = null;
if (app != null)
  mat = (SoVRMLMaterial)app.material.getValue();
        

Others

All the other Open Inventor actions have been modified (if necessary) to do the “usual thing” with respect to VRML nodes. So there should not be any surprises. In particular, SoCallbackAction SoCallbackAction SoCallbackAction will visit all nodes in the scene graph, including nodes underneath a VRML Shape node (like VRML Material). Likewise, SoSearchAction SoSearchAction SoSearchAction will find VRML nodes, including nodes underneath a VRML Shape node.

Files

Reading VRML files

Open Inventor automatically recognizes the file headers “ #VRML V2.0 utf8”, indicating a VRML97 format file, and “ #X3D V3.0 utf8”, indicating an X3D format file with Classic VRML encoding. Open Inventor does not support the X3D XML encoding at this time. When reading a VRML file, Open Inventor recognizes nodes by their VRML name. For example, “IndexedFaceSet” will create an SoVRMLIndexedFaceSet SoVRMLIndexedFaceSet SoVRMLIndexedFaceSet node. If other Open Inventor nodes appear in the file (which would make the file non-compliant), their names must begin with “ So ”. For example, “ SoIndexedFaceSet SoIndexedFaceSet SoIndexedFaceSet ” will create an SoIndexedFaceSet SoIndexedFaceSet SoIndexedFaceSet node.

Any other (valid) file header is assumed to be an Open Inventor or VRML 1.0 file. When reading these files, Open Inventor recognizes nodes by their “classic” Open Inventor name. For example “Material” will create an SoMaterial SoMaterial SoMaterial node. If VRML nodes appear in the file (which is perfectly legal), their names must begin with “VRML”. For example, “VRMLMaterial” will create an SoVRMLMaterial SoVRMLMaterial SoVRMLMaterial node.

VRML does not have a binary format (although one has been proposed and Open Inventor will support it when it is fully defined and accepted). You may wish to use the Open Inventor binary file format in some cases because the files are much smaller and load much faster.

About GZIP: Because VRML does not have a binary format, VRML files are often compressed with the gzip utility program to reduce their download time. The core Open Inventor library does not support gzip’d files. However on Win32 platforms (Windows), FEI offers “IVF”, a set of extension classes that integrates Open Inventor with MFC (the Microsoft Foundation Classes application framework). Applications built with MFC and IVF have built-in support for gzip’d files. IVF automatically detects gzip compression regardless of the file extension.

As discussed above under ROUTES, Open Inventor will automatically create field-to-field connections specified by ROUTE statements in the input file.

The SoDB::read method returns an SoNode*, which may be any type of node, so this method is suitable for reading both traditional Open Inventor and VRML files. However the SoDB::readAll method always returns an SoSeparator*. This method can be used to read VRML files, but it will always create and return an SoSeparator SoSeparator SoSeparator as the root node in that case. That is not a problem, but it may be more convenient when reading VRML files to use the new method SoDB::readAllVRML, which always returns an SoVRMLGroup* . This allows the application, if desired, to keep the scene graph limited to “pure” VRML nodes.

Writing files

By default Open Inventor writes the scene graph to a file using the standard Open Inventor file header and standard Open Inventor naming conventions. For example, “ SoMaterial SoMaterial SoMaterial ” will be written out as “ Material ” and “ SoVRMLMaterial SoVRMLMaterial SoVRMLMaterial ” will be written out as “ VRMLMaterial ”. This is the standard Open Inventor convention of dropping the leading “ So ” from the class name. All VRML nodes in the file will have class names beginning with “ VRML ”. This convention both identifies the VRML nodes in the file and distinguishes the VRML nodes, like “ Material ”, that are ambiguous with a traditional Open Inventor node.

In order to write a VRML compliant file and use VRML naming conventions, your application must call the SoOutput SoOutput SoOutput method:

setHeaderString("#VRML V2.0 utf8")
         
SetHeaderString("#VRML V2.0 utf8")
         
setHeaderString("#VRML V2.0 utf8")
         

or

setHeaderString("#X3D V3.0 utf8")
         
SetHeaderString("#X3D V3.0 utf8")
         
setHeaderString("#X3D V3.0 utf8")
         

using a pointer to your SoOutput SoOutput SoOutput object. If you only have an SoWriteAction SoWriteAction SoWriteAction object, use the getOutput() method to obtain a pointer to its SoOutput SoOutput SoOutput object. For example:

SoWriteAction wa;
wa.getOutput()->setHeaderString("#VRML V2.0 utf8");
         
SoWriteAction wa = new SoWriteAction();
wa.GetOutput().SetHeaderString("#VRML V2.0 utf8");
         
SoWriteAction wa = new SoWriteAction();
wa.getOutput().setHeaderString("#VRML V2.0 utf8");
         

When writing a VRML file, Open Inventor writes the scene graph to a file using VRML naming conventions. For example, “ SoVRMLMaterial SoVRMLMaterial SoVRMLMaterial ” will be written out as “ Material ” and “ SoMaterial SoMaterial SoMaterial ” will be written out as “SoMaterial SoMaterial SoMaterial ”. In other words, VRML nodes have their normal VRML class name and traditional Open Inventor nodes have a “ So ” prefix to their class name. Please note however that although Open Inventor can read VRML files containing non-VRML nodes, these are not conforming VRML files and will cause errors in most VRML viewers. On the other hand, as noted previously, it can be useful to use a “mixed” file when saving a project between sessions and “publish” a pure VRML file when the project is completed.

As discussed above under ROUTEs, Open Inventor will automatically generate ROUTE statements for any field-to-field connections that exist in the scene graph. Please note that unlike the traditional Open Inventor file syntax for field-to-field connections, ROUTE statements require both the “from” and “to” nodes to have names. We recommend explicitly naming all nodes that will have field connections in them. This makes your VRML file much easier to interpret if it becomes necessary to examine it by hand. However, Open Inventor will automatically create “synthetic” names for nodes, if necessary, when generating the ROUTE statements. These names have the form “_n” where “n” is an integer value. For example, “_1” and “_2” will normally be the first two names created. These names are automatically removed when the file is read back in by Open Inventor.

Open Inventor guarantees that synthetic names are unique within the current scene graph. However it does not guarantee that application specified names are unique (we assume you know what you are doing in this case). Both Open Inventor and the VRML specification allow names to be multiply defined in an input file. They simply use the most recently encountered definition of the name.

Components

Viewers

The base Viewer class (SoXtViewer on Unix, SoWinViewer SoWinViewer on Win32) setSceneGraph method has been modified to handle VRML Viewpoint nodes. Previously, on setSceneGraph an Open Inventor viewer would search for a camera node and use that camera definition if found, otherwise it would create a perspective camera with default values and do a “ viewAll ”. A VRML scene graph will not contain any camera nodes and the VRML specification states that the first Viewpoint node encountered while reading the file defines the initial view. So the viewer still searches for a camera node (because there is no way to know if a scene graph came from a VRML file or not), but if there is no camera, then it searches for a Viewpoint node. If a Viewpoint is found, then the viewer creates a perspective camera and initializes it to the values in the Viewpoint node.

Color Editor

It was not necessary to modify the Color Editor (SoXtColorEditor on Unix, SoWinColorEditor SoWinColorEditor on Win32) for VRML because the Color Editor attaches to a color field and VRML uses the standard Open Inventor field types SoSFColor SoSFColor SoSFColor and SoMFColor SoMFColor SoMFColor . As discussed elsewhere in this chapter, it is generally easier to attach a Color Editor when working with VRML geometry because there is no need to search for the appropriate Material node. The pick (selection) path will have an SoVRMLShape SoVRMLShape SoVRMLShape node as its tail node. This node has five fields, two of which are the appearance and geometry fields. So typically the attach algorithm will look something like the following:

  1. If the geometry node (e.g. SoVRMLIndexedFaceSet SoVRMLIndexedFaceSet SoVRMLIndexedFaceSet ) contains a Color node (it has a color field and the value is not NULL), then attach to the color field of the Color node.

  2. If there is no Appearance node (appearance field is NULL), then create a default Appearance node and put it in the appearance field.

  3. If there is no Material node (Appearance node’s material field is NULL), then create a default Material node and put it in the Appearance node’s material field.

  4. Attach to the diffuseColor field of the Material node.

the section called “ Attach Color Editor” shows the source code (or the demo program SceneViewer).

Material Editor

The Material Editor (SoXtMaterialEditor on Unix, SoWinMaterialEditor SoWinMaterialEditor on Win32) has been enhanced to allow attaching to SoVRMLMaterial SoVRMLMaterial SoVRMLMaterial nodes (in addition to SoMaterial SoMaterial SoMaterial nodes). An SoVRMLMaterial SoVRMLMaterial SoVRMLMaterial node contains essentially the same information as an SoMaterial SoMaterial SoMaterial node, except:

When a Material Editor is attached to a VRML Material node, you will notice that the ambient intensity slider does not have buttons beside it (like the other color sliders do). This is because it is not possible to edit the VRML ambient color directly. You can only change the ambient intensity (using the slider) or change the diffuse color.

As discussed elsewhere in this discussion, it is generally easier to attach a Material Editor when working with VRML geometry (no need to search for the appropriate Material node). The pick (selection) path will have an SoVRMLShape SoVRMLShape SoVRMLShape node as its tail node. This node has five fields, two of which are the appearance and geometry fields. So typically the attach algorithm will look something like the following:

  1. If there is no Appearance node (appearance field is NULL), then create a default Appearance node and put it in the appearance field.

  2. If there is no Material node (Appearance node’s material field is NULL), then create a default Material node and put it in the Appearance node’s material field.

  3. Attach to the Material node.

the section called “ Attach Material Editor” shows the source code (or see the demo program SceneViewer).

Manipulators

The manipulators (SoTransformerManip SoTransformerManip SoTransformerManip and so on) have not been specifically modified for VRML. However they are just as useful for VRML geometry as they are for traditional Open Inventor geometry. Because manipulators are usually added to the scene graph by replacing an SoTransform SoTransform SoTransform node, all the manipulator classes are derived from SoTransform SoTransform SoTransform (by way of SoTransformManip SoTransformManip SoTransformManip ). To be able to replace an SoVRMLTransform SoVRMLTransform SoVRMLTransform node, it would have been necessary to (essentially) duplicate the manipulator classes and derive them from SoVRMLTransform SoVRMLTransform SoVRMLTransform . This would have significantly increased the size of the Open Inventor toolkit. There is an easier way: temporarily add an SoTransform SoTransform SoTransform node to the VRML scene graph. So the algorithm for a VRML scene graph, given a path to some selected geometry, is roughly:

To insert a manipulator:

  1. Ensure that the Shape node’s parent is an SoVRMLTransform SoVRMLTransform SoVRMLTransform node (add one if necessary, creating an additional level of hierarchy).

  2. Insert an SoTransform SoTransform SoTransform node at an appropriate place in the scene graph (usually as the first child of the Shape node’s parent).

  3. Replace the SoTransform SoTransform SoTransform node with a manipulator (using the manipulator’s replaceNode() method as usual).

the section called “ Attach Manipulator” shows the source code (or see the demo program SceneViewer).

To remove a manipulator:

  1. Remove the manipulator from the scene graph (that is, literally remove the manipulator from the scene graph, not using the replaceManip() method, because we don’t want an SoTransform SoTransform SoTransform node left in a VRML scene graph).

  2. Concatenate the transformation in the manipulator into the Shape node’s parent node (which we previously made sure was an SoVRMLTransform SoVRMLTransform SoVRMLTransform node).

the section called “ Detach Manipulator” shows the source code (or see the demo program SceneViewer).