Direct3D Tutorials | |
My primary goal in doing these tutorials is to learn. By developing these tutorials I hope to learn my way around Direct3D much quicker than I would otherwise. Also I hope to be able to provide a valuable resource for others who want to learn. While I'm not new to programming, Direct3D & 3D programming in general is new to me. These examples may not illustrate the best way to do things. I'm open to (constructive) criticism, if you have a better way of doing something, let me know. I've tried to use a clear and easy to read style with a fair number of comments. If you have any problems understanding my code or comments, please let me know and I'll see what I can do to make them clearer. These tutorials cover Direct3D8. The DirectX SDK is required to compile them. The tutorials are written in C++ but some have been converted to Visual Basic as well. |
NeHe-Style Tutorials | |
This set of tutorials is modelled after the OpenGL tutorials developed & hosted by Jeff Molofee (NeHe). Check out his site here, there is some amazing material there. Even if you have no interest in OpenGL or game/graphics programming, it's worth the visit to check out some of the sample programs. |
|
Tutorial | Last Updated |
Lesson 1:Your First Window | March 20, 2003 |
Lesson 2a:Your First Polygons (Screen Space) | March 20, 2003 |
Lesson 2b:Your First Polygons (Model Space) | March 20, 2003 |
Lesson 3:Coloured Polygons | March 20, 2003 |
Lesson 4:Rotation | March 20, 2003 |
Lesson 5:Solid Objects | March 20, 2003 |
Lesson 6:Texture Mapping | March 5, 2001 |
Lesson 7:Texture Filters, Lighting & Keyboard Control | March 5, 2001 |
Lesson 8:Alpha Blending (Vertex Alpha) | September 30, 2002 |
Lesson 9:Moving Bitmaps in 3D Space | April 9, 2002 |
Lesson 10:Moving in a 3D World | October 13, 2002 |
There are no Lessons 11 & 12 | n/a |
Lesson 13:D3DXFont | April 9, 2002 |
Drunken Hyena-Style Tutorials | |
This set of tutorials was created to either try out something I was interested in, or created in response to a request I receieved. I frequent the forums on GameDev.net and a lot of the tutorials are made to answer questions asked there. |
|
Tutorial | Last Updated |
X Rotations without D3DX | March 5, 2001 |
Y Rotations without D3DX | March 5, 2001 |
Z Rotations without D3DX | March 5, 2001 |
Translations without D3DX | March 5, 2001 |
Scaling without D3DX | March 8, 2001 |
Dancing Square | March 8, 2001 |
Colour Key Transparency | March 23, 2001 |
Alpha Channel Transparency | April 3, 2001 |
Computed Alpha Channel | April 15, 2001 |
Loading a Texture From a Resource | May 21, 2001 |
Additive Blending | May 21, 2001 |
3D Fonts | April 9, 2002 |
Using CD3DFont | April 9, 2002 |
Lesson 1: Your First Window | ||
![]() In this tutorial we will create a window and initialize Direct3D. This is the bare minimum you can do and still claim to have written a Direct3D program. It can be run in full-screen or windowed mode.. This code base will be used for the more advanced tutorials, so it's definitely worth a look. | ||
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe | Download VB Source & Exe |
Lesson 2a: Your First Polygons (Screen Space) | ||
![]() Now that you know how to open a window, let's draw something. Being able to draw a triangle may not seem like much, but it's the foundation of all the more complex drawing. A Quake model is nothing more than a bunch of textured triangles. In this tutorial we're going to draw a triangle and a square (which is just 2 triangles together). Each vertex in the triangle (and square of course) has a set of coordinates (x,y,z). These coordinates can be given in Screen Space (called Transformed Vertices), or Model Space (Untransformed Vertices). Coordinates can also be given in World Space (also Untransformed Vertices) In Screen Space, the top, left corner is at 0,0 (x,y) and the units of measurements are actual pixels used by the screen resolution you're using. Adding 10 to the x-coordinates of a triangle will move that triangle 10 pixels to the right. Since Screen Space is flat, the z-coordinate does very little. Changing the z-coordinate will not visibly make the object move deeper into the screen. If you're using a Z Buffer, changing the z-coordinate will determine which objects are in front of each other. Transformed Vertices are often used to draw 2D-style objects, such as a console, or interface. In World Space your units of measurement are arbitrary. Adding 1 to a coordinate could move something 1 centimeter, 1 meter, or whatever distance you choose. If the coordinates of your model are given in World Space, they still have to be Transformed, but since they don't change, it's a trivial Transformation. Operating on the object (rotation for example) can be tricky though. In Model Space the coordinates are relative to the model itself. Often the center of the model is at (0,0,0) which makes rotation easy to calculate. Matrices are used to transform the objects coordinates into World Space and then Screen Space. The Transformation into World Space allows object 'interaction' (lighting, object blocking each other from view) and the Transformation into Screen Space then allows the 3D objects to be presented on a 2D screen. In this tutorial we will use Transformed Vertices, because they're really easy. The Online Tutorial below shows the changes necessary to the code given in Lesson 1. Revisiting all of the code each time seems a bit excessive. Of course the complete source is given in the Source & Exe zip file. | ||
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe | Download VB Source & Exe |
Lesson 2b: Your First Polygons (Model Space) | ||
![]() In this version we specify our coordinates in Model Space and then Transform them into World Space. We also use a single Vertex Buffer to store the vertices for both the triangle and the square and just use an offset into the Vertex Buffer when drawing them. | ||
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe | Download VB Source & Exe |
Lesson 3: Coloured Polygons | ||
![]() Plain white polygons are boring. This time we'll show how you can blend colours together by setting vertices to different colours on our triangle. We'll colour our square a flat blue to show how the 2 methods contrast. | ||
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe | Download VB Source & Exe |
Lesson 4: Rotation | ||
![]() Now it's time to make them dance. Well, rotate anyway. We'll make the triangle rotate on the x-axis, and the square rotate on the y-axis. The Online Tutorial shows the changes from code in Lesson 3. | ||
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe | Download VB Source & Exe |
Lesson 5: Solid Objects | ||
![]() Now it's time to really enter the world of 3D. We've drawn, coloured, and rotated flat, 2D objects, now we're going to do the same to real (simple) 3D objects. A pyramid and a cube are our next victims. The pyramid will rotate on the Y-axis (which means we don't have to draw a bottom on it, you'd never see it). Since we're not drawing a bottom, all of the triangles that make up the pyramid share a common point, the top. This means we can draw them as a Triangle Fan. In a Triangle Fan, each triangle after the first is made up of the first vertex drawn, the previously drawn vertex and then the new vertex provided. Obviously fans can't be used in many places. Fan shapes (obviously), circles, spikes, pyramids, etc can be done with Triangle Fans. The cube will rotate on the X-axis. For simplicity, we'll use standard Triangle Lists to draw our cube. This means every single vertex has to be given for each triangle drawn, no sharing. It can't be done with a single Triangle Fan (correct me if I'm wrong), and Triangle Strips wouldn't be pretty (degenerate triangles would be required). Since our goal is simplicity, Triangle Lists win. In this tutorial we create a Z-Buffer. Normally if we drew the cube, we would have to make sure that we drew the triangles starting with the ones in the back, otherwise the triangles would clobber each other randomly. The Z-Buffer (also known as a depth buffer) tracks the depth at each point and only draws an object if it would be in front of what's already drawn. The Online Tutorial shows the changes from code in Lesson 4. | ||
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe | Download VB Source & Exe |
Lesson 6: Texture Mapping | ||
![]() Coloured solids are nice, but they can't compare to the results you can get with textures. In this tutorial we'll take the cube from Lesson 5 and slap a texture on all 6 faces. It's not the prettiest texture in the world, but that's why I'm a programmer and not an artist. The Online Tutorial shows the changes from code in Lesson 5. | ||
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe | Download VB Source & Exe |
Lesson 7:Texture Filters, Lighting & Keyboard Control | ||
![]() We're going to cover a lot of ground in this one. The keyboard control is a simple modification of the message handler for our window, no DirectInput(yet). The arrow keys control the speed that the cube spins on the X-axis and Y-axis. Page Up and Page Down move the cube along the Z-axis. 'L' turns lighting on and off while 'F' changes the type of texture filtering being used. The texture filters show the difference between No Filtering, Point Filtering, and Linear Filtering. Last, but definitely not least, we bring in lighting. Lighting can get complex, so we'll keep it as simple as we can while we introduce it. The Online Tutorial shows the changes from code in Lesson 6. | ||
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe | Download VB Source & Exe |
Lesson 8:Alpha Blending (Vertex Alpha) | |
![]() Now the lessons are starting to look good. There just aren't a lot of people who are impressed by a triangle & square, no matter how quickly they are rotating (the triangle and square, not the people). To the best of my knowledge, this lesson is done the 'proper' way. No quick hacks. The transparent triangles are drawn back-to-front, normals are set up so lighting works without any trickery. The Online Tutorial shows the changes from code in Lesson 7. NOTE : The dhSimpleMesh class is required to re-compile this lesson. It can be downloaded from this page. | |
Online Tutorial (Commented C++) | Download C++ Source & Exe |
Lesson 9:Moving Bitmaps in 3D Space | |
![]() This tutorial shows how to build a simple particle system. It loads a 2D image of a star and moves 50 of them around in 3D space. Since the particle is a 2D image, we have to make sure it always faces the camera. This is known as billboarding.
Features: Controls: NOTE : The dhEngine class is required to re-compile this lesson. It can be downloaded from this page. | |
Online Tutorial (Commented C++) | Download C++ Source & Exe |
Lesson 10:Moving in a 3D World | ||
![]() |
A first-person camera tutorial has been requested many times. This is a simple tutorial and as such we don't cover more advanced issues like collision detection. NOTE : The dhEngine class is required to re-compile this lesson. It can be downloaded from this page. | |
Online Tutorial | Download C++ Source & Exe |
Lesson 13:D3DXFont | ||
![]() |
The associated NeHe tutorial builds Font bitmaps using wglUseFontBitmaps. A close analog to that in Direct3D8 is the D3DXFont class. It's extremely easy to set up, and the results look really nice. D3DXFont supports anti-aliasing and kerning. The cost is that it's not incredibly fast. See my dhFastFont class for a faster (though less featured) alternative. If you've worked your way up through the tutorials, this one will be really easy for you. NOTE : The dhEngine class is required to re-compile this lesson. It can be downloaded from this page. dhFPSTimer is also required. | |
Online Tutorial (Commented C++ Source) | Download C++ Source & Exe |
X Rotations without D3DX | ||
![]() The D3DX library provides a number of helpful routines, the ones that build rotation matrices are particularly handy. Some people cannot use D3DX (using a compiler other than VC++) and others choose not to. This mini-tutorial is for both groups. Writing the function to do the rotations was trivial because the DX8 SDK includes the source for this function, so I just cut 'n' pasted. If they gave out the source for all of the D3DX functions things would be a lot easier for users of other compilers. DirectX uses 4x4 matrices for transformations (scaling/rotation/translation/etc). Creating a matrix for X-axis rotation is as simple as calculating the sine and cosine of the given angle (in radians) and plugging those values into the right places in a matrix. And that's what our new function dhMatrixRotationX() does. We rotate 2 triangles on their x-axis. The left one uses the D3DX function, the right one uses mine. As you can see they're in perfect sync which gives me a fair bit of confidence in the quality of the function. NOTE: You still need D3DX to recompile this tutorial because I use D3DX's RotateX to compare to mine, and I also use the Translation & Multiply functions. In future tutorials, I'll provide non-D3DX versions of these as well. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (28K) |
Y Rotations without D3DX | ||
![]() In this tutorial I provide a function to calculate matrices for Y-axis rotation. Otherwise it's identical to the X Rotation tutorial. NOTE: You still need D3DX to recompile this tutorial because I use D3DX's RotateY to compare to mine, and I also use the Translation & Multiply functions. In future tutorials, I'll provide non-D3DX versions of these as well. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (28K) |
Z Rotations without D3DX | ||
![]() In this tutorial I provide a function to calculate matrices for Z-axis rotation. Otherwise it's identical to the Y Rotation tutorial. NOTE: You still need D3DX to recompile this tutorial because I use D3DX's RotateZ to compare to mine, and I also use the Translation & Multiply functions. In future tutorials, I'll provide non-D3DX versions of these as well. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (28K) |
Translations without D3DX | ||
![]() In this tutorial I provide a function to calculate matrices for Translation (movement on the X, Y, or Z axis). Otherwise it's identical to the Rotation tutorials. NOTE: You still need D3DX to recompile this tutorial because I use D3DX's Translation to compare to mine. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (28K) |
Scaling without D3DX | ||
![]() In this tutorial I provide a function to calculate matrices for Scaling (size changing on the X, Y, or Z axis). Otherwise it's identical to the Rotation tutorials. NOTE: You still need D3DX to recompile this tutorial because I haven't replaced all of the D3DX Matrix functions yet. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (28K) |
Dancing Square | ||
![]() The basic purpose of this tutorial is to animate a simple shape, but I managed to
sneak in a few extras. In this tutorial we cover: | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (29K) |
Colour Key Transparency | ||
![]() DirectDraw supported blitting with a Colour Key. A Colour Key is a colour value which is to be treated as if it were completely transparent. Black was commonly used for the background on sprites and by specifying that black was the colour key, you could draw (blit) your sprite and the black areas wouldn't be drawn allowing the background to show. In Direct3D transparency is achieved with AlphaBlending. Each pixel (if using the alpha in a texture) and/or vertex has an Alpha or Transparency value. Since 255 is fully opaque and 0 is fully transparent, it's best thought of as the level of Opaqueness. With 256 levels of transparency some very cool effects can be achieved. Once you get used to AlphaBlending you'll never wish for Colour Keys again. There are times when it would be nice to simulate a Colour Key. Quite often it's good enough to specify a single colour as completely transparent and everything else as fully opaque. Another advantage is that you can use image formats like BMP which do not support alpha channels. To simulate Colour Keys with D3D8 we use D3DXCreateTextureFromFileEx, an unwieldy yet descriptively named function. It allows a Colour Key arguement. It loads your texture and then processes it setting the alpha value of each pixel to 0 wherever it finds your specified Colour Key. One big disadvantage of using Colour Keys is coloured jaggies. If you use any anti-aliasing on the edges of your sprite, it will blend with the background. So if your texture is white text drawn on a black background will have grey jaggies on it which will look wrong if you draw it over a green background. NOTE:When specifying your Colour Key you provide it as an ARGB quad (DWORD, 0xAARGGBB). The Alpha component is significant, if your background is opaque black (from a BMP all colours will be opaque since there is no alpha channel) then you have to give it as 0xFF000000 NOT 0x00000000. This is because D3D only looks for an exact match. This is probably the number 1 mistake people make when using D3DXCreateTextureFromFileEx. This lesson uses Lesson 2a as a base. The Online Tutorial describes the changes that were made to that code base.I removed a lot of comments from the source. By the time you reach this tutorial, the explanation of why I'm including windows.h shouldn't be necessary and only bloats the file. I haven't removed all of the comments, just some of the (by now) painfully obvious ones. The 'A' or 'B' key can be used to toggle blending off and on. They both do exactly the same thing, I use both because it's more intuitive. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (108K) |
Alpha Channel Transparency | ||
![]() Since we've discussed the limitations of Colour Keys, it's time to show you a better way. A small number of image formats (notably Targa & PNG) support per-pixel transparency by means of an alpha channel. When dealing with 32-bit colours, they are represented like this 0xAARRGGBB, where RR is the red channel, BB is the blue channel, GG is the green channel and AA is the alpha channel. Since they are each 1 byte in length they can have values from 0-255. For the red channel, 0 has no red, 255 has the full amount of red. Similarly, in the alpha channel 0 is full transparent while 255 is fully opaque. This extra byte per pixel can add to the images size, but that's about the only downside. Alpha channels allow incredible flexibility. This lesson uses the Colour Key lesson as a base. The Online Tutorial describes the changes that were made to that code base. The changes required were VERY minor. You can literally make the required changes in about 30 seconds. This means it's very important that you understand the Colour Key lesson before you tackle this one. The image being loaded is actually just a big red square. The alpha channel creates variable levels of transparency on this square so it looks like a solid dot that fades off on the edges. Toggling the transparency will show the dramatic difference. You cannot achieve this effect with a Colour Key. The 'A' or 'B' key can be used to toggle blending off and on. They both do exactly the same thing, I use both because it's more intuitive. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (111K) |
Computed Alpha Channel | ||
![]() In this lesson we load a simple grayscale image that does not have an Alpha Channel and we compute the alpha component based on the intensity of each pixel. A white spot will be opaque, a black spot will be transparent and gray will be semi-transparent. We do this by setting the alpha component equal to the red component, since it's a grayscale image we could have used blue or green and achieved the same result. Since it's a grayscale image with no alpha, the file sizes are quite small. This 64x64 texture is only 5K on disk. This technique could be used to load font textures that are anti-aliased against a black background. By adding a diffuse colour component to our vertices we could change the colours of our images while maintaining a small image on disk. This example builds off of the previous Alpha Channel Transparency lesson so please study it before reviewing this one. The 'A' or 'B' key can be used to toggle blending off and on. They both do exactly the same thing, I use both because it's more intuitive. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (111K) |
Loading a Texture from a Resource | ||
![]() This tutorial is based off of Lesson 6 (the first texture mapping tutorial). A lot of people have asked how to load a texture from a VC++ Resource, so I put this together. The online tutorial gives instructions on how to make a resource from your bitmap and then shows the code required to load it. Once you've seen it, it's pretty simple. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (266K) |
Additive Blending | ||
![]() This tutorial shows off the power of the D3DBLEND_ONE render state. By setting the source and destination blend states to D3DBLEND_ONE we're enabling Additive Blending. What this means is that each object we draw will add to what has already been drawn. Blue drawn over green will yield aqua, red over green will yield yellow. Black will magically be ignored, so we don't have to worry about the backgrounds on our sprites. No alpha channels are used, not in the texture, not in the vertices. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (119K) |
3D Font | ||
![]() This tutorial shows how to create a 3D mesh from a string/font combination. Here we create the string "Drunken Hyena" from the Arial font. After creating the string, we spin it in the middle of the display and have a light shine on it just for kicks. Note:This tutorial requires the dhEngine class. It's available here. | ||
Online Tutorial (Commented C++ Source) | Download Source & Exe (72K) |
Using CD3DFont | ||
![]() |
This tutorial shows how to use the CD3DFont class provided with the DirectX 8 SDK. If you look in your SDK folder in Sample/Multimedia/Common there's a source and include directory. There is a d3dfont source file and include, you'll need those for this tutorial. Note:This tutorial requires the dhEngine class. It's available here.dhFPSTimer is also required. | |
Download (49K) | Online Tutorial (Not Available) |