2D Bump-mapping

2D Bump-mapping


Introduction

2D bump mapping seems to be all the rage nowadays. And granted, it is a very impressive effect. And its also pretty simple to code. I'll walk you through how to code a simple bump-mapper.

Algorithm

With 2D bumping, we basically have a 'phongmap', a precalculated lookup table for a light source. We want to use the image to distort the lighting, to make the surface appear corrugated. So we need to effectively calculate some kind of normal, and use that to index the texture map - like in fake env-map phong shading.

First thing we need to do is interpolate 2 variables across the image - Lx and Ly. These are 'lightx' and 'lighty'. Ly is initialized to -lightposy before the Y loop, and Lx is initialized to -lightposx before the X loop. At each cycle of the X loop, we increment Lx, and at each cycle of the Y loop, we increment Ly. Kind of like interpolating the texture co-ordinates for the light map if you like.

Now we need to calculate some kind of offset value. The way this is done is again quite simple. We take the difference between 2 entries in the bump-map. The values will be:

XDelta = ((texture[y][x-1] - texture[y][x+1]) >> 1) + 127
YDelta = ((texture[y-1][x] - texture[y+1][x]) >> 1) + 127
X and Y are our standard loop variables. The texture must be the same size as the screen. Now simply add these values to you Lx and Ly, and you've effectively disturbed the lighting normal. Now do a simple check; if the upper byte of either of those values if non-zero, ie (xtemp & 0xFF00) != 0, then paint the pixel black. Else, use those values to index the texture map:
XTemp = Lx + XDelta
YTemp = Ly + YDelta

if((XTemp & 0xFF00) || (YTemp & 0xFF00)) {
        PutPixel(x, y, 0)
} else {
        u = ytemp;      // these are byte variables - we are only
        v = xtemp;      // interested in 0..255
        PutPixel(x, y, phongmap[v*256+u])
}
And you've got yourself a simple bump-mapping routine. Putting it all together, you should get a routine like:
void Bumpmap(char *src, char *dst)
{
        int             xdist, ydist;
        int             xdelta, ydelta;
        int             xtemp, ytemp, temp;
        int             i, j, offset = 320;
        int             lx, ly;
        unsigned char   u, v;

        ly = -lighty;
        for(i=1; i<198; i++) {
                lx = -lightx;
                for(j=0; j<320; j++, offset++) {
                        xdelta = ((src[offset -   1] - src[offset +   1]) >> 1) + 127;
                        ydelta = ((src[offset - 320] - src[offset + 320]) >> 1) + 127;
                        lx++;

                        xtemp = xdelta + lx;
                        ytemp = ydelta + ly;
                        if((xtemp & 0xFF00) || (ytemp & 0xFF00)) {
                                *dst++ = 0;
                        } else {
                                u = ytemp;
                                v = xtemp;
                                *dst++ = phonglightmap[v*256+u];
                        }
                }
                ly++;
        }
}
Here src is the address of the source texture, and dst is the destination, ie the screen.


Colouring it

You can easily extend this to include colour. If you change the above code so that instead of painting a monochrome image, you paint a colour image, using a lookup table to get the right colour, you get a loop something like:

        xdelta = ((bumpmap[offset -   1] - bumpmap[offset +   1]) >> 1) + 127;
        ydelta = ((bumpmap[offset - 320] - bumpmap[offset + 320]) >> 1) + 127;
        lx++;
        
        xtemp = xdelta + lx;
        ytemp = ydelta + ly;
        if((xtemp & 0xFF00) || (ytemp & 0xFF00)) {
                *dst++ = 0;
        } else {
                u = ytemp;
                v = xtemp;
                colour = phongmap[v*256+u];
                *dst++ = colour_lookup[colour*256+texture[y][x]]
        }
Something like that. Where bumpmap is a pointer to your monochrome bump map, colour_lookup is a 256x256 lookup table for shade x of colour y, and texture is your 256-colour texture map. Obviously this will be a little slower, but it should still work well.

Anyway thats enough now of this simple effect, its time for you to go and code it up yourself. You'll be pleased with the results, its a great little effect.

Tom Hammersley, tomh@globalnet.co.uk