ATI SDK

ATI Product Information

Support for Alternate OS's

Hardware partners

Software partners

RenderMonkey

Drivers


 
 

Highlights


GPU MeshMapper (V1.0)

GPU PerfStudio (V1.2)

Samples: CrossFire Detect (update)

Samples: PostTonemapResolve

The Compressonator (version 1.41)

GPU Shader Analyzer (V1.42)

RenderMonkey™
(version 1.81) (New)


ATI Compress (version 1.6)

AMD Tootle 2.0 (New)

AMD OpenGL ES 2.0 Emulator (V1.1) (New)

HLSL2GLSL (V0.9)

AMD at GDC 2007

ATI SDK


 
 
ATI Developer - Source Code
 
Bump Mapping on Consumer 3D Graphics Accelerators

Sections
Emboss Bump Mapping
DOTPRODUCT3
EnvBump Mapping
References and Links
 
Introduction
Bump mapping is a shading technique introduced in 1978 by Jim Blinn [Blinn78] to simulate wrinkled or bumped surfaces. In general, bump mapping techniques perturb the illumination of a surface on a per-pixel basis to create the illusion of bumps. The underlying geometry of the surface is not altered in any way (that's called displacement mapping and is a completely separate topic)-bump mapping is purely a rasterization-level illumination or texture-addressing tweak. Some bump mapping techniques supported by mainstream 3D graphics accelerators diverge fairly significantly from Blinn's original method and produce various levels of quality.

There are at least three flavors of bump mapping currently available on commercial 3D graphics accelerators:
  • Emboss Bump Mapping
  • DOTPRODUCT3 Bump Mapping
  • Environment Mapped Bump Mapping
We will cover the three techniques and their mathematical foundations in this tutorial. We also provide a number of Sample Applications for both Direct3D® and OpenGL®.
 
Emboss Bump Mapping
The bump mapping technique supported by the majority of 3D graphics accelerators, including the Radeon® and RAGE 128™, is a form of embossing. It can be tough to get this technique to look right and few, if any, games have used this method. That said, the concept of tangent space, which is fundamental to emboss bump mapping, is also common to many other visual effects such as DOTPRODUCT3 bump mapping and anisotropic lighting.

A good 2D discussion of embossing can be found in [Schlag84]. The basic idea of embossing comes from the observation that subracting a grayscale heightmap from a slightly shifted version of itself gives the appearance of a bumpy or embossed surface. The direction of the shift gives the appearance of illumination from a particular direction. Mathematically, this subtraction of the height map is an approximation of the derivative of the height map in the direction of the shift.

A 2D Example

Figure 1 below shows a grayscale heightmap of a brick wall and a magnified portion of the top-left corner, provided by the IBM® Human Computer Interaction Texture Library. In keeping with image processing conventions, white texels represent high areas in the height map while black texels are low.
 
Click to enlarge Click to enlarge
Figure 1
 
Figure 2 below shows what the brick height map in Figure 1 looks like when subracted from a version of the height map that has been shifted down and to the left. Note that the image gives the impression of a light source emanating from the upper-right.
 
Click to enlarge
Click to enlarge
Figure 2
 
Bump mapping is particularly effective under changing lighting conditions. In the following animation, the light source is moving in a circular pattern around the brick bump map. Downloading the AVI and setting it to loop during playback gives the best results.
 
Click to enlarge
Download the Zip'd AVI Movie
Embossing in 3D

In a 3D context, this technique can be used to provide diffuse bumped illumination of polygons. The application offsets the height map relative to itself by adjusting the texture coordinates of the shifted heightmap based on the incident angle of the light source at each polygon vertex independently. The computation of this texture coordinate shift is the key to properly implementing emboss bump mapping.

Ultimately, our goal is to map a 3-space vector (the light vector incident at a particular vertex) to a 2-space vector (the perturbation of the texture coordinate at the vertex). It is convenient to define a coordinate space local to each vertex which uses as its basis the vertex normal, a tangent to the surface which represents the direction of increase of the t texture coordinate and their cross product (aka the binormal). [Blythe] refers to this coordinate space as tangent space. Figure 3 below shows the tangent space vectors for a specific vertex on a sphere with overlayed wireframe.
 


Figure 3 - Tangent space with normal, tangent and binormal axes
 
Figure 4 shows the tangent space vectors for a specific vertex on a sphere without the overlayed wireframe
 

 
Figure 4 - Tangent space with normal, tangent and binormalaxes
 
These vectors, expressed in object coordinates, represent a transformation from object space to tangent space.

Once you have defined tangent space for a given vertex, you must transform the light source into this space. This typically involves transforming the light source into object space and then using the tangent space basis vectors to transform from object to tangent space.
 


 
Figure 5 - normal, tangent , binormal and light vectors
 
Once the light vector is expressed in tangent space, the tangent and binormalcomponents of this vector represent the direction of the texture coordinate shift for the emboss effect. The magnitude of the texture coordinate shift must be designed such that it doesn't cause the texture coordinates to offset too far. As an approximation to the derivative, this technique is actually taking a first difference in a particular direction. As such, too large an offset can cause strange aliasing artifacts. "Too far" is defined by the spatial frequency of the height map (i.e. the sharpness of the bump edges). In the pick-nearest-filtering case, this first differencing can be viewed as a classic Roberts filter, commonly used in image processing to detect diagonal edges in image data. Turning on bilinear filtering causes a prefiltering step to happen prior to the Roberts filter. We expect that developers will want to do a lot of experimenting in this area in order to tune the magnitude of the texture coordinate shift to their own style.

Another consideration when computing the texture coordinate shift is whether or not the vertex is facing the light source in the first place. If the vertex is not facing the light (the normalcomponent of the light vector is negative), the texture coordinates should not be shifted at all.

Figures 3 through 5 showed only the bump and Gouraud components of an emboss bump mapped sphere. Naturally, we would also like to include a base color map in this process as shown in Figure 6 below.


 


 
Figure 6 - Diffuse bump and Gouraud shaded sphere with a base color map. This is done in a single pass on the RAGE 128™ or Radeon®.
 
Embossing with Hardware

Examining the areas of interest in the Radeon® 3D Pixel Pipeline, we see that we can calculate the emboss bump mapping effect using the first two multitexture units and the alpha blending unit. Essentially, the math that we want to perform is as follows:

(height - shifted_height) * diffuse * base

(Some developers may also want to incoporate a 2X multiplier into this equation. This is also supported on the RAGE 128™ and later chips.)

In order to perform these operations as effectively as possible, we recognize that the height calculations are scalar while the other values are RGB vectors. With this we can exploit the parallel nature of the separate RGB and alpha pipes in the multitexture stages to perform some of the math in parallel. We associate a single texture map with both Texture Lighting Unit 0 and Texture Lighting Unit 1, but we use shifted texture coordinates for fetches in Unit 1. The texture map has its bump map stored as a height map in its alpha channel. Texture Lighting Unit 0 modulates base RGB with diffuse RGB and passes along this result as well as unmodified alpha texels. Texture Lighting Unit 1 leaves RGB untouched while doing a signed addition on the incoming alpha from Unit 0 and the inverted alpha texels from Unit 1. The multiplication of the alpha math with the RGB math is done in the alpha blender with src and dest factors of srcAlpha:Zero. This data flow is illustrated below:


 

    RGB: MODULATE{2X}
alpha: Passthrough


  RGB: Passthrough
alpha: invert tex1.alpha, ADDSIGNED{2X}


  src * srcAlpha + dst * zero
 
So far, we have outlined the math behind emboss bump mapping without referring to specific API syntax. In the following sections, we will express emboss bump mapping in the two most common APIs developers will be using-Direct3D® and OpenGL®.
 
Embossing with Direct3D®
In this Direct3D® section we will use the multitexture API introduced in DirectX® 6.0. For some background on the multitexturing abstraction, consult the DirectX® SDK as well as the article, "Multitexturing in DirectX® 6" in the September 1998 issue of Game Developer Magazine.

The following code is used in the RAGE 128™ SDK R128BumpMap2 Direct3D® sample application and performs the multitexture operations outlined above.

//
// Program stage 0 to modulate diffuse.rgb with tex0.rgb
//

pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0 );
// Can also MODULATE2X here
pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE );
pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );

//
// Program Stage 1 to pass through the RGB channels. The
// texture coordinates associated with Stage 1 are the
// shifted ones. Invert the alpha channel and
// do a signed add.
//

pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1 );
pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT );
// Can also ADDSIGNED2X here
pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_ADDSIGNED);
pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG1,
D3DTA_TEXTURE | D3DTA_COMPLEMENT);
pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );

// Use the same texture on both stages
if (pTexture != NULL)
{
pd3dDevice->SetTexture(0, pTexture );
pd3dDevice->SetTexture(1, pTexture );
}

//
// Set up the alpha blender to multiply the alpha channel (monochrome emboss)
// with the src color (lighted texture)
//

pd3dDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
pd3dDevice->SetRenderState( D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
pd3dDevice->SetRenderState( D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO );
pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2,
g_pMeshVertices, g_NumVertices,
g_pIndices, g_NumIndices, NULL );
//
// The result is (height - shifted_height) * tex.RGB * diffuse.RGB
//

 
Embossing with OpenGL®
This code, taken from the RAGE 128Bump, sample application, illustrates the use of the ARB_multitexture and .EXT_texture_env_combine, extensions to perform emboss bump mapping.

//
// Program a display list to multiply the interpolators
// with the base texture and pass the texel alpha...
//

glNewList(BUMP_STAGE_0,GL_COMPILE);
{
// RGB
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT);

glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB_EXT,GL_MODULATE);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB_EXT,GL_TEXTURE);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB_EXT,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB_EXT,GL_PREVIOUS_EXT);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB_EXT,GL_SRC_COLOR);

// alpha
glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_ALPHA_EXT,GL_REPLACE);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA_EXT,GL_TEXTURE);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_ALPHA_EXT,GL_SRC_ALPHA);

}
glEndList();

//
// Program a display list for texture environment 1
//

glNewList(BUMP_STAGE_1,GL_COMPILE);
{
// RGB
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT);
glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB_EXT,GL_REPLACE);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB_EXT,GL_PREVIOUS_EXT);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB_EXT,GL_SRC_COLOR);

// alpha
glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_ALPHA_EXT,GL_ADD_SIGNED_EXT);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA_EXT,GL_TEXTURE);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_ALPHA_EXT,GL_ONE_MINUS_SRC_ALPHA);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_ALPHA_EXT,GL_PREVIOUS_EXT);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_ALPHA_EXT,GL_SRC_ALPHA);
}
glEndList();



//
// In your draw loop, use the display lists as follows...
//

glActiveTexture(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureName);
glCallList(BUMP_STAGE_0);

glActiveTexture(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureName);
glCallList(BUMP_STAGE_1);

glEnable(GL_BLEND);

// src * srcAlpha + 0
glBlendFunc(GL_SRC_ALPHA, GL_ZERO);

DrawBumpedSphere();

glDisable(GL_BLEND);
 
DOTPRODUCT3 Bump Mapping
The bump mapping technique which most closely resembles Blinn's original method is DOTPRODUCT3 bump mapping. With DOTPRODUCT3 bump mapping, a normal map is used to represent per-pixel 3-space normals (N) to a surface. At each pixel, it is possible to compute a dotproduct with another 3-space vector which represents the vector to a given light source, L.
 
Click to enlarge
Click to enlarge
Normal Map (N)
Vector to light source (L)
 
Once these two quantities are being routed into the pixel pipeline, it is a simple matter of programming the pixel operations to perform a dot product operation at each pixel. The result of the scalar dotproduct is replicated to R, G, B and (optionally) A to represent a grayscale per-pixel lighting value as shown below:
 
Click to enlarge
·
Click to enlarge
=
Click to enlarge
N
·
L
=
N·L
 
Naturally, this scalar N·L term can be modulated with a constant to color the light source, a 3D texture or attenuation map for per-pixel distance attenuation (see the 3D Texture Tutorial). Per-pixel N·L terms can even be accumulated for different light sources before being modulated with a base texture map.
 
Environment Mapped Bump Mapping
More exposition in next release. For now, see the relevant samples
 
References
  • James F. Blinn "Simulation of wrinkled surfaces," Computer Graphics, 123, pp. 286-292, 1978.
  • David Blythe, "Bump Mapping with Textures," SGI OpenGL® tutorial, June 1998.
  • John Schlag, "Fast Embossing Effects on Raster Image Data," Graphics Gems IV, Academic Press, Inc. pp. 433-437, 1994
  • Jason L. Mitchell, Michael J. Tatro and Ian Bullard, "Multitexturing in DirectX® 6", Game Developer, pp. 33-37, September 1998.
 
Links
 
 
 


 



©2008 Advanced Micro Devices, Inc.  |  Contact AMD  |  Careers  |  RSS Feeds  |  Terms and Conditions  |  Privacy  |  Trademark information  |  Site Map