Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9

DirectXGraphics: Dot Product 3 Bump Mapping
Author: Jack Hoxley
Written: 16th October 2001
Contact: [EMail]
Download: GR_Dot3Bump.Zip (139kb)

Contents of this lesson
1. Introduction
2. The theory behind it all

1. Introduction

Welcome back to another extended Direct3D8 tutorial; whilst I've been spending most of my time recently working through the DirectXAudio tutorials, I decided to spend the afternoon playing with D3D8 again.

So what have I done this time? Well, whilst looking through the SDK sample files I came across the bump-mapping folder (It wasn't the first time I'd looked at it though), and looked at the Dot-Product-3 bump mapping sample, and decided that it looked pretty cool; so went about seeing how it worked (expecting it to be pretty complex). Well, within a couple of minutes I'd pretty much worked it out - which surprised me, so I went about porting it over to VB to see if it would work there too, and now that I've gotten it working here's the final result...

As you may have already guessed, this is pretty much identical to the SDK C++ sample, all I've done is jazzed up a few bits and converted it to another language... so credit goes to the people who write the samples for the SDK. Thanks!

2. The Theory Behind it all

This may seem to be pretty easy, or incredibly complicated. If you've ever written a simple lighting engine, or read articles on them (I have one here) then you're laughing, otherwise, you're probably going to scratch your head a little...

The simplest form of lighting is to calculate the colour of the given pixel (based on range), and then multiply it by the dot product of the normal and the lights direction; thus pixels "facing" the light are very bright, and those facing "away" from the light are black/dark. The dot product is simply just a component wise multiplication of two vectors (and adding the results together):

AxBx + AyBy + AzBz

if both vectors are unit vectors (length of 1) then the result always lies in the range |V|<=1, and we can get a great little scalar value. If you need to understand more about the specifics of this then check out the article linked above, or any other good article on lighting algorithms.

So, what if we could get Direct3D to perform this on a per-pixel basis? well we can - we store all the pixel normals in a texture, and then the lighting direction in the texture-factor property. We then tell Direct3D to multiply the vector components together and output the result as a greyscale value (white=bright, black=no light). Fairly simple, and pretty fast as well.

Now step back a second, I've been talking about vectors - but you know that textures are actually colours (ARGB). Which is where we need to be clever. We need to pack a 4D vector WXYZ into a 4 byte/32bit ARGB colour. From square one we are already limited to using D3DFMT_A8R8G8B8 textures (ie, if there's no support for them, give up now). I haven't tried using 565/555 16 bit textures, I suppose theoretically you could try packing the 4 vector components into a 4444 ARGB textures - but I dont know if that would work (the 4 bit accuracy per vector component would probably make it look awful anyway).

For reference:
A = W
R = X
G = Y
B = Z

and if we are using a standard D3DVECTOR to store our normals, we must convert each 32 bit single into an unsigned 8 bit integer. This isn't too hard really, and can be done by multiplying the vector by 127 (puts it into the -127<X<+127 range) and adding 128 (puts it in the 1<x<255 range); which is painless enough.

As for actually generating the normals, well, that should be engrained in your head by now, as a quick reminder:

Normalised Cross product of the vectors v0 to v1 and v0 to v2 : Norm(Cross(Sub(v1,v0),Sub(v2,v0)))

If you're still stumped, then look at the lighting article, or look back through the previous Direct3D8 tutorials.

The last thing you need to know is the texture-factor parameter. Again we pack a vector into an ARGB long; but this time it represents the lights direction. Now we instantly have a slight short-fall in the technique, we can only (effectively) have directional lighting, and we wont get any difference in angle across the surface of the triangle. This can be awkward to sort out - but your best bet is to generate an average vector for the light-source to the triangle...

That's about all you need to know for Dot-3 bump-mapping; it's quite a cool little feature, not quite as impressive as full environment bump-mapping, but still, it can add that extra little touch to your graphics engine. Short of the extra texture space required, there's very little overhead in using this method either, so you dont need to be too tight as to how much of it you use.

You'll need to download the source code for this article to see what I'm going on about; if you get errors about your hardware not supporting the required functions, switch it to the reference rasterizer by replacing D3DDEV_HAL with D3DDEV_REF...

You can get the file from the top of the page, or from the downloads page

any feedback or improvements can be emailed to me - I'm always interested...

DirectX 4 VB 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster