delete Image;
Image=NULL;
}
// Load The "Extension Enabled"-Logo
if (Image=auxDIBImageLoad("Data/multi_on_alpha.bmp")) {
alpha=new char[4*Image->sizeX*Image->sizeY]; // Create Memory For RGBA8-Texture
>…<
glGenTextures(1, &multiLogo); // Create One Textures
// Create Linear Filtered RGBA8-Texture
>…<
delete alpha;
} else status=false;
if (Image) { // If Texture Exists
if (Image->data) delete Image->data; // If Texture Image Exists
delete Image;
Image=NULL;
}
return status; // Return The Status
}
Next comes nearly the only unmodified function ReSizeGLScene(). I've omitted it here. It is followed by a function doCube() that draws a cube, complete with normalized normals. Note that this version only feeds texture-unit #0, since glTexCoord2f(s,t) is the same thing as glMultiTexCoord2f(GL_TEXTURE0_ARB,s,t). Note also that the cube could be done using interleaved arrays, but this is definitely another issue. Note also that this cube CAN NOT be done using a display list, since display-lists seem to use an internal floating point accuracy different from GLfloat. Since this leads to several nasty effects, generally referred to as "decaling"-problems, I kicked display lists. I assume that a general rule for multipass algorithms is to do the entire geometry with or without display lists. So never dare mixing even if it seems to run on your hardware, since it won't run on any hardware!
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
>…<
void doCube (void) {
int i;
glBegin(GL_QUADS);
// Front Face
glNormal3f( 0.0f, 0.0f, +1.0f);
for (i=0; i<4; i++) {
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Back Face
glNormal3f( 0.0f, 0.0f,-1.0f);
for (i=4; i<8; i++) {
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Top Face
glNormal3f( 0.0f, 1.0f, 0.0f);
for (i=8; i<12; i++) {
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Bottom Face
glNormal3f( 0.0f,-1.0f, 0.0f);
for (i=12; i<16; i++) {
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Right Face
glNormal3f( 1.0f, 0.0f, 0.0f);
for (i=16; i<20; i++) {
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Left Face
glNormal3f(-1.0f, 0.0f, 0.0f);
for (i=20; i<24; i++) {
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
glEnd();
}
Time to initialize OpenGL. All as in Lesson 06, except that I call initLights() instead of setting them here. Oh, and of course I'm calling Multitexture-setup, here!
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
multitextureSupported=initMultitexture();
if (!LoadGLTextures()) return false; // Jump To Texture Loading Routine
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
initLights(); // Initialize OpenGL Light
return true // Initialization Went OK
}
Here comes about 95% of the work. All references like "for reasons discussed later" will be solved in the following block of theory.
If you have a Powerpoint-viewer installed, it is highly recommended that you download the following presentation:
"Emboss Bump Mapping" by Michael I. Gold, nVidia Corp. [.ppt, 309K]
For those without Powerpoint-viewer, I've tried to convert the information contained in the document to .html-format. Here it comes:
Michael I. Gold
NVidia Corporation
Real Bump Mapping Uses Per-Pixel Lighting.
• Lighting calculation at each pixel based on perturbed normal vectors.
• Computationally expensive.
• For more information see: Blinn, J. : Simulation of Wrinkled Surfaces, Computer Graphics. 12,3 (August 1978) 286-292.
• For information on the web go to: http://www.objectecture.com/ to see Cass Everitt's Orthogonal Illumination Thesis. (rem.: Jens)
Emboss Bump Mapping Is A Hack
• Diffuse lighting only, no specular component
• Under-sampling artefacts (may result in blurry motion, rem.: Jens)
• Possible on today's consumer hardware (as shown, rem.: Jens)
• If it looks good, do it!
C=(L*N) × Dl × Dm
• L is light vector
• N is normal vector
• Dl is light diffuse color
• Dm is material diffuse color
• Bump Mapping changes N per pixel
• Emboss Bump Mapping approximates (L*N)
Texture Map Represents Heightfield
• [0,1] represents range of bump function
• First derivate represents slope m (Note that m is only 1D. Imagine m to be the inf.-norm of grad(s,t) to a given set of coordinates (s,t)!, rem.: Jens)
• m increases / decreases base diffuse factor Fd
• (Fd+m) approximates (L*N) per pixel
Embossing Approximates Derivative
• Lookup height H0 at point (s,t)
• Lookup height H1 at point slightly perturbed toward light source (s+ds,t+dt)
• Subtract original height H0 from perturbed height H1
• Difference represents instantaneous slope m=H1-H0
1) Original bump (H0).
2) Original bump (H0) overlaid with second bump (H1) slightly perturbed toward light source.