Hello fellow coders.

This is Sqrt(-1) speaking. Many demos nowadays feature 2d bump mapping
(the effect in which highlight travels upon a bumpy surface (prolly with
embossed writing or something on it) seen from above), so I decided to write
something about it...

As you'll soon see, I convert my page into this kind of a text articles
w/ sample programs and source codes. I hope you will be happy now.
(To you whom got this article from else where, consider visiting
www.sci.fi/~zaphod)

Ok, to the point.

To really do REAL 2d bump mapping one has to calculate normals for every
pixel in bump map (an image representing "heights" of pixels) and for each
pixel take dot product of light source and this normal (the normal of the
surface (ie. bumpy screen) is <0,0,-1>, ie. directly to the viewer, so it
doesn't affect bump mapping).

This, of course, is awfully slow. And it does not look that good either.

The answer is simple. If we know X and Y of normal, we can calculate it's Z
(as normals are unit vectors. So Z is simply 1-sqrt(X^2 + Y^2) ). Therefore,
we can calculate the lighting value for each X and Y and store it into a
map (which, normally is 256x256). This kind of a map is called enviroment map
(enviroment maps are used to simulate reflecting objects with simple mapping).

Here's some pseudocode to calculate enviroment map:

for (int y=0;y<256;y++)
for (int x=0;x<256;x++)
{
   float nX=(x-128)/128;
   float nY=(y-128)/128;
   float nZ=1-sqrt(nX*nX + nY*nY);
   if (nZ<0) nZ=0;
   enviromentmap[x][y]=nZ*256; // 256 shades...
};

Of course you can use Phong illumination model as well...

So, by picking value at enviromentmap[normalx+128][normaly+128] (if normals are
in 9.7 fixed point format) we get the correct lighting info for lightsource at
<0,0,-infinity>. This, althought correct, is not what we want. We want light-
source to move and be infinitely close to the surface.

Normalx is simply difference of heights in neighbour pixel on X axis... ie.

normalx = bumpmap[x+1][y] - bumpmap[x-1][y]

and for normaly, we ofcourse do

normaly = bumpmap[x][y+1] - bumpmap[x][y-1]

And now, gals and guys, comes the damned easy part :)

We simply pick value from
enviromentmap[(normalx-(lightx-currentx))][(normalx-(lightx-currentx))].
Of course, you have to check that values are within range...

So, here's a simple pseudocode for 2d bump mapper:

for (int y=0;y<200;y++)
for (int x=0;x<320;x++)
{
   int nX=bumpmap[x+1][y]-bumpmap[x-1][y];
   int nY=bumpmap[x][y+1]-bumpmap[x][y-1];
   int lX=x-lightx;
   int lY=y-lighty;
   nX-=lX;
   nY-=lY;
   nX+=128;
   nY+=128;
   if (nX<0 || nX>255) nX=0;
   if (nY<0 || nY>255) nY=0;
   screen[x][y]=enviromentmap[nX][nY];
};

Hope this helps you...

And don't ask me why the sample proggy is called "dan"... I keep it in a
directory called "danfort"...

To compile the proddy with DJGPP, write:

cmp dan
gxx -o dan.exe *.o

That's it.

If you need to contact me, email. zaphod@sci.fi

Discuss this article in the forums


Date this article was posted to GameDev.net: 7/16/1999
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
Texture Mapping

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!