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.
![]() | |
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. |
![]() | |
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. |
The main idea of bump mapping is that, instead of using a texture to modify the color of a surface, we apply a texture, called a normal map, height map, or simply bump map (generic term), to modify the surface normals. The surface patterns are encoded in the bump map texture.
The texture is called a normal map if it stores normals. The bump map texture is in this case an RGB texture, with x, y, and z corresponding to the red, green, and blue components respectively.
The texture is called a height map if it stores heights. The bump map texture is in this case a monochrome texture where each monochrome value represents a height, with white used for high areas and black for low areas. A height map is converted internally to a normal map.
As previously described, a bump map is a texture where heights (a height map) or normals (normal map) are encoded.
Like classical texture mapping, texture coordinates (s and t) are assigned to each vertex of a polygon, to control how the bump map is mapped onto the geometry.
The following figure illustrates this.
Additionally, each normal stored within the normal map can be expressed either in the space of the object called “modeling space” or in the space of the polygon called “tangent space.”
![]() | |
The “tangent space” coordinate system is convenient for applying repetitive wrinkle patterns. |
When bump mapping, there are really two surface normals that should be considered for lighting: the unperturbed normal N based on the shape geometry, and the perturbed N', which is based on the surface’s small-scale microstructure stored within the normal map.
Self-shadowing corrects lighting which would normally only be based on the perturbed normal N' by taking into account the unperturbed normal N.
![]() | |
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:
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: | |||||||
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:
| |||||||
Specifies a 2D texture map to be used, and associated parameters for bump mapping and also for classical texture mapping (image mapping).
| |||||||
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).
|
There are two general scenarios for using bump mapping. The first consists of applying a bump map to a shape in order to generate a wrinkled surface. The second one consists of combining bump mapping with image mapping in order to obtain a wrinkled surface, with an image texture mapped on top of the wrinkles.
The following two figures illustrate these two possibilities.
The demo program $OIVHOME/src/FXViz/demos/BumpMapping illustrates the use of bump mapping. Additionally, some simple Open Inventor files combining bump mapping and image mapping are supplied in the directory $OIVHOME/src/FXViz/data/BumpMapping.
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.
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();
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();
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);
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
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();
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.