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
bumpmapping folder (It wasn't the first time
I'd looked at it though), and looked at the DotProduct3
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):
A_{x}B_{x}
+ A_{y}B_{y} + A_{z}B_{z}
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 perpixel basis? well we can  we store all
the pixel normals in a texture, and then the lighting
direction in the texturefactor 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 texturefactor
parameter. Again we pack a vector into an ARGB
long; but this time it represents the lights direction.
Now we instantly have a slight shortfall 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 lightsource
to the triangle...
That's
about all you need to know for Dot3 bumpmapping;
it's quite a cool little feature, not quite as
impressive as full environment bumpmapping, 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...
