9.5. Bump Mapping

Bump mapping is a way of simulating fine details such as bumps or wrinkles in a surface by modifying the surface normals. Bump mapping can be used to simulate features that would otherwise take a large number of polygons to model.

This technique is a normal-perturbation rendering technique for simulating lighting effects caused by patterned irregularities on an otherwise locally smooth surface.

[Note]

This technique is a multi-pass per-pixel lighting computation using pixel shaders and vertex shader hardware features, thus classical OpenGL Gouraud lighting is deactivated when a shape is rendered using the bump mapping technique.

[Warning]

Depending on your hardware capabilities, bump mapping may not be available. This technique uses standard OpenGL 1.3 features but can also work with previous OpenGL versions if specific OpenGL extensions are available. The method SoBumpMapping::isSupported() will indicate if bump mapping is supported by your graphics board.


[Warning]

The bump mapping feature is not yet compatible with the shadow casting feature. Trying to combine these two features will give you an incorrect visual result.

The following nodes are involved in bump mapping:

SoBumpMappingProperty

Specifies the current bump mapping properties for all subsequent shapes.

The properties described in the section called “Key Concepts” can be set by this node, namely:

SoTextureUnit SoTextureUnit SoTextureUnit

Specifies the current texture unit and the associated mapping method for all subsequent 2D texture nodes.

If the graphics board supports multitexturing, then multiple textures, each defined by a texture unit, can be applied to the same shape. The maximum number of texture units depends on the board and can be queried using getMaxTextureUnit.

In FXViz 1.1, a maximum of two texture units is supported, with two different mapping methods (e.g., the first texture unit could be an image map and the second one a bump map).

A texture unit identified by the field unit (SoSFUInt32 SoSFUInt32 SoSFUInt32 ) is defined by the following texture properties:

SoTexture2 SoTexture2 SoTexture2

Specifies a 2D texture map to be used, and associated parameters for bump mapping and also for classical texture mapping (image mapping).

[Note]

This node is described in detail in the “Textures” chapter in The Inventor Mentor (see Section 7.3, “Texture Nodes”).

SoTextureCoordinate2

Explicitly defines the set of 2D texture coordinates to be used by subsequent vertex shapes for bump mapping, but also for classical texture mapping (image mapping).

[Warning]

Automatic texture coordinate generation (SoTextureCoordinateFunction SoTextureCoordinateFunction SoTextureCoordinateFunction and its derived classes) and 2D transformation (SoTexture2Transform SoTexture2Transform SoTexture2Transform ) are not supported by bump mapping.

[Note]

This node is described in detail in the “Textures” chapter in The Inventor Mentor (see the section called “Nodes Used for Texture Mapping”).

Using the appearance preserving simplification feature, you can create more realistic looking shapes with fewer triangles.

Starting with a complex model, the first step is to create a simplified (i.e., lower polygon count) version of the model using the existing simplification tools (SoSimplifyAction SoSimplifyAction SoSimplifyAction , etc.). The next step is to pass the two models to the new SoAppearancePreserver SoAppearancePreserver SoAppearancePreserver class which computes a normal map that attempts to reproduce the appearance of the complex model on the simplified model. The final step is to apply the resulting bump maps to the simple model.


  1. Compute a simplified version of your complex model using the simplification tools.

    For more information about simplication tools see the section called “Large Model Visualization (LMV)”.

    SoDecimator *decimator = new SoDecimator;
    // Bump mapping could be applied only on non-indexed shapes
    decimator->setSimplifiedShapeType(SoFaceSet::getClassTypeId());
    
    float level = 2000;              // We want to get a simplified model with 2000 triangles
    globalSimplifyAction = new SoGlobalSimplifyAction(decimator);
    globalSimplifyAction->setSimplificationLevels(1, &level);
    globalSimplifyAction->apply(myHighLevelModel);
    // Retrieves the simplified model
    myLowLevelModel = globalSimplifyAction-getSimplifiedSceneGraph();
    
    delete decimator;               // No longer needed
    delete globalSimplifyAction;    // No longer needed
          
    SoDecimator decimator = new SoDecimator();
    // Bump mapping could be applied only on non-indexed shapes
    decimator.SetSimplifiedShapeType(typeof(SoFaceSet));
    
    float[] level = new float[1]{2000}; // We want to get a simplified model with 2000 triangles
    SoGlobalSimplifyAction globalSimplifyAction = new SoGlobalSimplifyAction(decimator);
    globalSimplifyAction.SetSimplificationLevels(level);
    globalSimplifyAction.Apply(myHighLevelModel);
    // Retrieves the simplified model
    myLowLevelModel = globalSimplifyAction.GetSimplifiedSceneGraph();
        
    SoDecimator decimator = new SoDecimator();
    // Bump mapping could be applied only on non-indexed shapes
    decimator.setSimplifiedShapeClass(SoFaceSet.class);
    
    float[] level = new float[]{2000}; // We want to get a simplified model with 2000 triangles
    SoGlobalSimplifyAction globalSimplifyAction = new SoGlobalSimplifyAction(decimator);
    globalSimplifyAction.setSimplificationLevels(level);
    globalSimplifyAction.apply(myHighLevelModel);
    // Retrieves the simplified model
    myLowLevelModel = globalSimplifyAction.getSimplifiedSceneGraph();
        
  2. Initialize FXViz module and create an instance.

    This initialization must be called after initializing Open Inventor

    SoFXViz::init();
    SoAppearancePreserver *myAPS = new SoAppearancePreserver;
          
    SoAppearancePreserver app = new SoAppearancePreserver();
        
    SoAppearancePreserver app = new SoAppearancePreserver();
       
  3. Specify the high resolution and low resolution scene graphs with the method SoAppearancePreserver::setSceneGraphs().

    myAPS->setSceneGraphs(myHighLevelModel, myLowLevelModel);
          
    myAPS.SetSceneGraphs(myHighLevelModel, myLowLevelModel);
          
    myAPS.setSceneGraphs(myHighLevelModel, myLowLevelModel);
          
  4. Specify the requested normal map texture size with the method SoAppearancePreserver::setTextureSize().

    The quality of the final rendering using the bump mapping technique is closely linked to the size of the normal map texture.

    myAPS->setTextureSize(512, 512);      // 512 x 512
          
    myAPS.SetTextureSize(512, 512);      // 512 x 512
        
    myAPS.setTextureSize(512, 512);      // 512 x 512
        
  5. Retrieve the normal map texture and the bump mapping texture coordinates with the methods SoAppearancePreserver::getNormalMapTexture() and SoAppearancePreserver::getBumpCoords()

    SoTexture2 *bumpMapTex = myAPS->getNormalMapTexture("myBumpMapTex.png");
    SoTextureCoordinate2 *bumpCoord = myAPS->getBumpCoords();
    delete myAPS;           // No longer needed
          
    SoTexture2 bumpMapTex = myAPS.GetNormalMapTexture("myBumpMapTex.png");
    SoTextureCoordinate2 bumpCoord = myAPS.GetBumpCoords();
        
    SoTexture2 bumpMapTex = myAPS.getNormalMapTexture("myBumpMapTex.png");
    SoTextureCoordinate2 bumpCoord = myAPS.getBumpCoords();
        
  6. Build a scene graph using bump mapping

    SoTextureUnit *texUnit0 = new SoTextureUnit;
    texUnit0->unit.setValue(0);
    texUnit0->mappingMethod = SoTextureUnit::BUMP_MAPPING;
    
    SoSeparator *bumpMappingSep = new SoSeparator;
    bumpMappingSep->addChild(texUnit0);
    bumpMappingSep->addChild(bumpCoord);
    bumpMappingSep->addChild(bumpMapTex);
    bumpMappingSep->addChild(myLowLevelModel);
          
    SoTextureUnit texUnit0 = new SoTextureUnit();
    texUnit0.unit.Value = 0;
    texUnit0.mappingMethod.Value = SoTextureUnit.MappingMethods.BUMP_MAPPING;
    
    SoSeparator bumpMappingSep = new SoSeparator();
    bumpMappingSep.AddChild(texUnit0);
    bumpMappingSep.AddChild(bumpCoord);
    bumpMappingSep.AddChild(bumpMapTex);
    bumpMappingSep.AddChild(myLowLevelModel);
        
    SoTextureUnit texUnit0 = new SoTextureUnit();
    texUnit0.unit.setValue(0);
    texUnit0.mappingMethod.setValue(SoTextureUnit.MappingMethods.BUMP_MAPPING);
    
    SoSeparator bumpMappingSep = new SoSeparator();
    bumpMappingSep.addChild(texUnit0);
    bumpMappingSep.addChild(bumpCoord);
    bumpMappingSep.addChild(bumpMapTex);
    bumpMappingSep.addChild(myLowLevelModel);
        

The demo program $OIVHOME/src/FXViz/demos/BumpMapping illustrates the use of the appearance preserving simplification technique.