If these two vectors point in the same direction, the surface is in front of the light, and it is well lighted. On the other hand if these two vectors have two opposite direction, the light cannot reach the surface. So using the result of their dot product, we can compute the amount of light that is received on a given pixel.
Now where does this bump mapping interfere? Well the goal of the bump mapping is to alter the lighting to simulate details on the surface. So by altering a bit the normal on the surface, we simulate the fact that the simulate is not flat.
Black: a face. Red: its normals and how it will look like. Up: no bump. Bottom: bump mapping.
"L" is the light vector
"N" is the normal
"H" is the half-angle. In fact H = E+L or E+N, both work, where E is the unit vector pointing from the pixel to the camera.
"." is a dot product
Basic lighting: diffuse reflexion
Intensity = N . L
Phong lighting: diffuse lighting + specular lighting
Intensity = N.L + (H.N)^n
The new term adds some specular lighting, that is some shyness when the light is directly reflected in direction of the camera.
Most of the time we use the tangent space, for it can be used in every cases.
The tangent space is made of three vectors: the tangent, the binormal and the normal. The tangent is the vector along which the U coordinates of the vertices are increased. The binormal is the vector along which the V coordinates of the vertices are increased. The normal is... the normal!
Most of the time the three vectors are orthogonal. In some cases they are not, but lighting will still work.
Of course each vertex has a different tangent space.
To compute the tangent space in a given vertex, you may use:
//X being the cross product For each face { (x,y,z) = (p2->x-p1->x,p2->u-p1->u,p2->v-p1->v) X (p3->x-p1->x,p3->u-p1->u,p3->v-p1->v) if (x!=0) { NORMALIZE(x,y,z) p1->Tx += -y/x; p1->Bx += -z/x; p2->Tx += -y/x; p2->Bx += -z/x; p3->Tx += -y/x; p3->Bx += -z/x; } (x,y,z) = (p2->y-p1->y,p2->u-p1->u,p2->v-p1->v) X (p3->y-p1->y,p3->u-p1->u,p3->v-p1->v) if (x!=0) { NORMALIZE(x,y,z) p1->Ty += -y/x; p1->By += -z/x; p2->Ty += -y/x; p2->By += -z/x; p3->Ty += -y/x; p3->By += -z/x; } (x,y,z) = (p2->z-p1->z,p2->u-p1->u,p2->v-p1->v) X (p3->z-p1->z,p3->u-p1->u,p3->v-p1->v) if (x!=0) { NORMALIZE(x,y,z) p1->Tz += -y/x; p1->Bz += -z/x; p2->Tz += -y/x; p2->Bz += -z/x; p3->Tz += -y/x; p3->Bz += -z/x; } } For each vertex { NORMALIZE(T) NORMALIZE(B) newN = TxB //Check direction of N according to a classic normal computation method: //sometimes N needs to be reversed if newN . oldN > 0 N = newN else N = -newN }
Once you have your three vectors (T,B and N), all required vectors must be converted in this basis. For this you use three dot products:
"." being the dot product
L = (Lo . T , Lo . B , Lo . N) where Lo is the Light vector in the object space.
N = (No . T , No . B , No . N) where No is the Normal vector in the object space.
N = (0 , 0 , 1) in most cases as N==No (unless you alter it with Bump mapping).
Now you need to convert the vectors in colors. First normalize the vector. Then:
R = 127 + x*127 G = 127 + y*127 B = 127 + z*127
Let's get some more fun. We will implement Phong lighting, that is per pixel lighting. We can just use the basic lighting, or the whole lighting, as you want. It just require some more passes to add the different terms of the equation. Now how to compute this damn per pixel dot product?
Hopefully, we have an OpenGL extension to help us: the GL_DOT3 extension, that does compute a per pixel dot product. We store the normal vector(s) in a texture called a normal map. And we store the light vector in the color of the vertex. So the normal map (using texture coordinates) gives us the proper per pixel normal (including the bump effect if you want), and OpenGL will interpolate the light vector when interpolating the color across a triangle.
Now let's set up the DOT3. I hope you know how to use multitexturing. Now let's set up a Texture Unit to use DOT3 between a texture color and a texel color:
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_EXT,GL_DOT3_RGBA_EXT); glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_EXT,GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_EXT,GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_EXT,GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_EXT,GL_SRC_COLOR);That's all, folks!
Main page | email : Sly |