Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
47 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:


Software and Hardware Requirements

Software Environment
The code that accompanies the article has been compiled and tested only on Microsoft Windows 2000 Professional SP3 and Microsoft Visual Studio .NET (version 7.0). The code includes the necessary Visual Studio project files and configuration.

You will need the following 3rd party libraries:

  1. OpenGL Utility Toolkit (GLUT) 3.7.6 or better [5]
  2. Corona image library 1.0.0 or better [6]
  3. nVIDIA Cg toolkit 1.0 or better

Hardware Environment
The code has been tested on a GeForce4 Ti 4200 video card. The code should run on a GeForce3 (or better) or a Radeon 9500 (or better) card.

In general, Cg OpenGL requires a GPU with support for either ARB_vertex_program/ARB_fragment_program (GeForceFX (or better) or Radeon 9500 (or better) families) or NV_vertex_program/NV_texture_shader/NV_register_combiners (GeForce3 (or better) family).


To execute the pre-compiled binaries, you need to use the following command line:

C:\>Bumpmap.exe Cube.ms3d Fragment.cg

The first parameter specifies the 3D Model to render on the screen, and the second parameter specifies the Cg fragment program to use in order to render the faces of the model.

Once the application window appears on the screen, you can right-click anywhere in it and display a pop-up menu with four options in it:

  1. Draw flat: render the scene without any bump mapping: only use the flat textures.
  2. Draw multipass: render the scene and emulate bump mapping using a multiple pass algorithm [7].
  3. Draw multitexture: render the scene and emulate bump mapping using a multi-texture algorithm [7].
  4. Draw pixel shader: render the scene using the Cg approach described in this article.


The code that accompanies this article (and implements the concepts described within) has a few additional features that go beyond the scope of the article.

In particular, the Cg code computes both the diffuse and the specular component for the lighting model, for which reason it is longer and slightly more complicated.

The triangle mesh rendered on the screen is a cube created using Milkshape 3D [8].

The code is documented and automated documentation is produced using Doxygen [9].

Cg Setup Code

#include <Cg/cg.h>
#include <Cg/cgGL.h>

void cgErrorCallback()
    CGerror err = cgGetError();

    if (err != CG_NO_ERROR) {
        cerr << "cgErrorCallback(): " << cgGetErrorString(err) << endl;

void main(int argc, char* argv[]) {

    CGcontext context = cgCreateContext();

    CGprofile profile = cgGLGetLatestProfile(CG_GL_FRAGMENT);

    CGprogram program = cgCreateProgramFromFile(
        [file name],
        NULL,    // entry point
        NULL);   // arguments



Cg Rendering Code

#include <Cg/cg.h>
#include <Cg/cgGL.h>

void draw() {
    // OpenGL lighting must be disabled since the pixel shader
    // program will compute the lighting value

    // The first texture unit contains the detail texture
    glBindTexture(GL_TEXTURE_2D, [detail texture handle]);

    // The second texture unit contains the normalmap texture
    glBindTexture(GL_TEXTURE_2D, [normalmap texture handle]);

    // Set the (fixed) ambient color value
    CGparameter ambientColorParameter = cgGetNamedParameter(program, "ambientColor");
    cgGLSetParameter3f(ambientColorParameter, [ambientr], [ambientg], [ambientb]);

    for every vertex in the triangle {
        // Bind the light vector to COLOR0 and interpolate
        // it across the edge
        glColor3f([lightx], [lighty], [lightz]);
        // Bind the texture coordinates to TEXTURE0 and
        // interpolate them across the edge
            [texturex], [texturey]);

        // Bind the normalmap coordinates to TEXTURE1 and
        // interpolate them across the edge
            [texturex], [texturey]);

        // Specify the vertex coordinates
        glVertex3fv([vertexx], [vertexy], [vertexz]);

Cg Fragment Program

float4 main(float2 detailCoords : TEXCOORD0,
            float2 bumpCoords: TEXCOORD1,
            float3 lightVector : COLOR0,
            uniform float3 ambientColor,
            uniform sampler2D detailTexture : TEXUNIT0,
            uniform sampler2D bumpTexture : TEXUNIT1): COLOR
    float3 detailColor = tex2D(detailTexture, detailCoords).rgb;

    // Uncompress vectors ([0, 1] -> [-1, 1])
    float3 lightVectorFinal = 2.0 * (lightVector.rgb - 0.5);
    float3 bumpNormalVectorFinal = 2.0 * (tex2D(bumpTexture, bumpCoords).rgb - 0.5);

    // Compute diffuse factor
    float diffuse = dot(bumpNormalVectorFinal, lightVectorFinal);

    return float4(diffuse * detailColor + ambientColor, 1.0);


[1] nVIDIA "OpenGL SDK"
[2] Eric Lengyel "Mathematics for 3D Game Programming & Computer Graphics"
[3] nVIDIA "Cg"
[4] Mark Kilgard "Cg in Two Pages"
[5] Nate Robbins Windows port of Mark Kilgard’s "OpenGL Utility Toolkit" (GLUT)
[6] Chad Austin "Corona"
[7] NeHe "OpenGL Tutorials", Lesson 22
[8] chUmbaLum sOft "Milkshape 3D"
[9] Dimitri van Heesch "Doxygen"

  Bump Mapping Background
  Cg Background
  Bump Mapping with Cg

  Source code
  Printable version
  Discuss this article