|  
                               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... 
                               |