Greg Dolley’s Weblog

A Blog about Graphics Programming, Game Programming, Tips and Tricks

  • Archives

  • June 2008
    M T W T F S S
     1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30  
  • Blog Stats

    • 1,071,666 hits
  • Subscribers

  • Twitter

DirectX 9 C++ Graphics Tutorial Part 3 – Drawing a Simple 3D Room

Posted by gregd1024 on June 15, 2008

Welcome to part three of the DirectX native C++ tutorials. In this part we’re going to look at drawing a set of 3D triangles. These triangles will make up a cube and the camera will be positioned inside of it (like you’re standing in a square room). While the last tutorial technically had a 3D triangle – after all, we specified z coordinates for every vertex – the scene was not truly 3D as far as DirectX is concerned. Try changing the z coordinate for any of those vertices and you’ll see what I mean – the triangle still doesn’t look like it’s in perspective.

Requirements

The tutorial sample code was built and tested with Visual Studio Express 2008. However, using the code “as-is” in Visual Studio 2005 should work too.

You’ll need the DirectX 9 SDK for compiling the sample code. Use this link for downloading: click here.

Tutorial Source and Project Files

Download the project files, binaries, and source with this link:

Getting Started

DirectX needs three matrices in order to render a true 3D scene – a world transformation matrix, a camera view matrix, and a projection matrix. If you’re unfamiliar with mathematical matrices, read the next section for a brief introduction. Those already seasoned in this subject can just skip it.

Introduction to Matrices

Matrices are basically mathematical tables used in linear algebra. They look like a grid and contain numbers. An example is shown below:

4_by_4_identity_matrix

This is known as a 4-by-4 matrix since it has four columns and four rows. It doesn’t necessarily have to be a square – an m-by-n matrix is quite common. However, the world, view, and projection matrices are all squares (4×4).

Just like regular numbers, matrices can be multiplied together or added to one another. A matrix like the one above is known as an identity matrix because of this special property: some matrix (let’s call it “M”) multiplied by an identity results in the same M matrix.

For this tutorial I’m going to show you how to multiply a m-by-m matrix by a m-by-1 matrix. If you’d like to know about the other rules for matrix addition and multiplication, search for “matrix mathematics” on Wikipedia. For this tutorial, however, it would only be helpful to know the procedure behind multiplying a square matrix by a one column matrix. Here’s how it would be done given a 2-by-2 and 2-by-1 matrix:

matrix_mult_2_by_2_and_2_by_1 

A 3-by-3 matrix multiplied by a 3-by-1 matrix would look like this:

matrix_mult_3_by_3_and_3_by_1 

For the sake of discussion, let’s call the bigger matrix “A” and the one column matrix “B.” The values in each row of A are multiplied by the values in B and the results are summed making a matrix with the same dimensions as B.

So why is this useful? Well, for one, we can represent a lot of common formulas in a table format as opposed to writing them out long-hand. For example, the regular way of expressing the 2D point rotation formula is this:

x_y_rotation_formulas

Now if we put the sine and cosine coefficients into a 2-by-2 matrix and put the x and y coordinates into a 2-by-1 matrix, we can represent the above formula like this instead:

x_y_rotation_formula_in_matrix

Try multiplying these two matrices as described above and you’ll find that it evaluates to exactly the same as the long-hand version. In other words, we can rotate any 2D point just by multiplying it with this 2-by-2 matrix! The same holds true for 3D points – we multiply them against a 3-by-3 matrix to get the newly rotated point (however, the 3-by-3 rotation matrix is much more complicated than its 2D counterpart as you’ll see shortly).

The reason that matrices are used in many 3D graphics applications, and what makes them unique, is the fact that fairly complex mathematical calculations can be simplified with just one or two matrix computations. For example, if you wanted to rotate a line segment around the z-axis in 3D space, you could do it via a brute-force method – apply the same long-hand trigonometric rotation equations to each point:

x_y_rotation_formulas_with_z

Note that the z component stays the same. To take the resulting vector and then rotate it around the y-axis, you’d use the same equations but apply them to the x and z components of each point:

x_z_rotation_formulas_with_y

Note that this time the y component stays the same and that x’ (the result of rotation #1) is used to calculate the new position instead of the original x. To do a third rotation, around the x-axis, the same equations would apply except Zrot and Yrot would be used as inputs (Xrot would stay the same).

Now here’s the drawback to doing it brute-force versus using a matrix: we’re always rotating around one of the three coordinate system axes. What if we want to rotate a point around some arbitrary vector instead of the x, y, or z axis? Using the long-hand equations to do that gets extremely complicated. However, there is one kind of matrix you can construct that, if multiplied by a 3-by-1 matrix representing a point, will result in a new 3-by-1 matrix containing values for the rotated point!

In case you’re wondering, this special type of matrix is called an angle/axis matrix and it looks like this:

angle_axis_matrix 

It may look scary at first, but you really only need to plug in two things: the components for vector V (which is the vector you want to rotate the point around) and Θ (the angle you want the point rotated). Note, however, that vector V must be normalized (it’s length must equal 1) for this matrix to work.

There’s another special property to this matrix – after plugging in your angle/vector combination and calculating the number values for each element, those numbers actually represent vectors themselves – each column corresponds to a vector (so three total). These three vectors have one special property – they’re always perpendicular to each other. That’s right, no matter what angle or V vector you plug in, you’ll always end of with three vectors that are aligned just like the x, y, z coordinate system axes. But there’s more! If you were to rotate the coordinate system axes around vector V by your angle, the new coordinate system axis vectors would match the vectors contained in each column of this matrix! Can you see now what this matrix is really doing?

It’s called an angle/axis matrix because you’re actually calculating how the coordinate system axes would be oriented if you rotated them by a given angle around a certain vector. Considering these properties, you could rewrite the above matrix like this:

3_by_3_xyz_vector_matrix  

The X vector, column one, holds the new x-axis after rotation. Column two, vector Y, holds the new y-axis after rotation. And as you can probably guess, column three, vector Z, holds the new z-axis after rotation.

Rotation is not the only type of operation that can be done with matrices – you can also translate a point (move it to a new position). A typical translation matrix looks like this:

translation_matrix 

The Tx, Ty, and Tz components in the fourth column determine how much to move along the x, y, and z axes respectively. Since this is a 4-by-4 matrix, you need to change the dimensions of the point matrix into 4-by-1. You do this by just inserting 1 into the fourth row. In other words, the entire operation would look like this:

translation_matrix_times_point 

Now you’re about to see the second beauty of matrices and why they’re really used in 3D graphics: if you want to rotate and translate a point, you can actually combine the rotation matrix with the translation matrix! The new matrix becomes:

translation_matrix_times_point_result 

With just this one matrix you can specify not only how much to rotate a point, but also how to translate that point as well! A matrix which combines rotation and translation is called a “transformation” matrix. As you can probably guess, this type of matrix moves a 3D world around the player.

Now that you’ve had an introduction to matrices and how a transformation matrix works, we can move on to the rest of the tutorial.

About the Code

As usual we’re going to build off of the example program from the last tutorial. Details about creating a window, setting up DirectX, and drawing a 2D triangle will not be covered here. If you need to know about those things, then I suggest reading the previous tutorial before moving on. Also, the example program for this segment uses DirectInput to capture keystrokes from the user. I won’t be covering details on DirectInput, but those parts of the code are clearly marked.

Also, unlike some of the previous posts, I won’t include a full listing – the code has simply grown too large. However, I will go over all the pertinent parts so you can learn the most from this tutorial. Anything that was changed or modified will be shown.

Going from 2D to 3D

The code in the last tutorial drew a simple 2D triangle on the screen. Even though we specified a z-coordinate for each vertex of that triangle, it was still not really 3D. Changing the z-coordinate for any of the vertices still didn’t draw the triangle in perspective. Why is this?

The vertex type used was D3DFVF_XYZRHW – the type used for pre-transformed vertices. DirectX expects these vertex types to have already gone through a 3D transformation pipeline. Once through the pipeline, z-coordinates become irrelevant – only screen coordinates (x and y) are used.

In order to render a true 3D scene, we need to add and/or change two things:

  • Feed the following matrices to DirectX so it knows how to transform the vertices from world space to the screen: world transformation matrix, view matrix, and projection matrix.
  • Change the vertex types to D3DFVF_XYZ – these vertices are untransformed and relative to world space.

Adding the Transformation Matrices

Before getting into the code, let’s briefly go over the purpose of each matrix. As the last section mentioned, DirectX needs the following three matrices:

  • The world transformation matrix.
  • The view transformation matrix.
  • The projection transformation matrix.

The world transformation matrix tells DirectX how to rotate, translate, and possibly scale 3D model coordinates into world space. In a typical 3D video game, polygonal models are the objects which tend to be reused in different parts of the world (weapons, bonus items, enemy players, monsters, etc.). Their vertices are defined relative to their own local coordinate system. The world transformation matrix converts these local coordinates into absolute positions in the 3D world (hence the name).

The view matrix (sometimes called the camera matrix, or camera-view matrix) tells DirectX how to transform world coordinates into camera coordinates (basically, where are you and what are you looking at). The world coordinates become relative to the camera axes after this matrix is applied.

If you have some experience in 3D graphics programming, don’t confuse the world matrix with the view matrix. Many tutorials and books about graphics sometimes refer to the world matrix and view matrix as one of the same. This is due to a certain optimization that can be done where you combine the world matrix and the view matrix into one master transformation matrix resulting in just one matrix update per frame instead of two.

The projection matrix tells DirectX about your 2D viewport into the 3D world. It holds the following information about the screen and camera: field of view, aspect ratio of the screen, how far the camera can see (far clipping plane), and how near the camera can see (near clipping plane).

The process of creating a world, view, and projection matrix isn’t difficult – if you use the Direct3D Extensions Utility library. Among other things, this library contains a few useful functions that return fully populated matrices given certain parameters. For example, provide an angle for the D3DXMatrixRotationY() function, and it will return a world transformation matrix that does rotation around the y-axis. If you ever need to calculate these matrices yourself, without the library’s help, you can refer to DirectX’s SDK documentation – it contains the layout and formulas for each matrix.

The order in which you feed these matrices to DirectX is irrelevant – although it internally applies them to the scene in the same order (world -> view -> projection). Since the order doesn’t matter, we set the projection matrix at initialization time and then forget about it. This matrix would only need to change if the screen’s aspect ratio, field of view, or clipping planes were altered.

We add the following code in order to create and set the projection matrix:

D3DXMATRIXA16 ProjectionMatrix;

D3DXMatrixPerspectiveFovLH(&ProjectionMatrix, PI/4, 1.0f, 1.0f, 500.0f);

g_pDirect3D_Device->SetTransform(D3DTS_PROJECTION, &ProjectionMatrix);

The call to D3DXMatrixPerspectiveFovLH() creates a projection matrix given the following values:

  • Field of view (in radians).
  • Aspect ratio.
  • Z-value of the near clip plane.
  • Z-value of the far clip plane.

These values go in parameters two through five, respectively. The first parameter holds a pointer to the matrix object which will receive the result.

The last line calls SetTransform(). This function is used to feed DirectX all the different types of matrices. The first parameter distinguishes which matrix type you want to set. D3DTS_PROJECTION indicates a projection matrix is contained in the second parameter.

Next we create the world transformation matrix. This is also set at initialization time. Why? Our example program has no 3D polygonal models and therefore doesn’t need to use it. As such, we simply send DirectX an identity matrix so it doesn’t affect any of the math in the 3D pipeline. Here’s what that code looks like:

D3DXMATRIXA16 WorldTransformMatrix;

D3DXMatrixIdentity(&WorldTransformMatrix);

g_pDirect3D_Device->SetTransform(D3DTS_WORLD, &WorldTransformMatrix);

We initialize the world transform matrix to an identity with the D3DXMatrixIdentity() function and then call SetTransform() just as we did with the projection matrix. The first parameter, D3DTS_WORLD, tells DirectX to use this matrix as the world transform. One thing to note: instead of calling D3DXMatrixIdentity(), we could have easily set the matrix manually through the object’s constructor:

D3DXMATRIXA16 WorldTransformMatrix(1, 0, 0, 0,

                                   0, 1, 0, 0,

                                   0, 0, 1, 0,

                                   0, 0, 0, 1);

I used the function call instead for clarity, but both methods are equivalent.

Now for the view/camera matrix. This one we must set on every frame since the direction of the camera can change at any time. If you take a look at the code, you’ll notice a function named CalcMatrices() – this is where the matrix is being populated. That code looks like:

void CalcMatrices(void)

{

   D3DXMATRIXA16 ViewMatrix;

  

   // set the view matrix

   D3DXVECTOR3 EyePoint(g_Camera.Location.x,

                        g_Camera.Location.y,

                        g_Camera.Location.z);

   D3DXVECTOR3 LookAt(g_Camera.Location.x+cos(g_Camera.Rotation),

                      g_Camera.Location.y,

                      g_Camera.Location.z+sin(g_Camera.Rotation));

   D3DXVECTOR3 UpVector(0.0f, 1.0f, 0.0f);

   D3DXMatrixLookAtLH(&ViewMatrix, &EyePoint, &LookAt, &UpVector);

  

   g_pDirect3D_Device->SetTransform(D3DTS_VIEW, &ViewMatrix);

}

In this function we must give DirectX two points and something called an “up” vector. The first point is the camera’s position – its location in 3D space. The second is any point along the camera’s direct line-of-sight – in other words, any point that, if you were to look through the camera, would be centered in the camera’s field of view. DirectX simply uses these two points to calculate the camera’s view vector – what direction the camera is pointing. Since the look-at point can be any point along the camera’s line-of-sight, I just use the sine and cosine functions to calculate some point directly in front of the camera. The y-coordinate doesn’t change because, in this example program, I’ve tried to keep things simple and not allowed the camera to look up or down (only side-to-side). The “up” vector defines which direction points directly up from the camera’s point of view.

You may be wondering why the up-vector is needed if we already have two points describing the camera’s direction. Here’s why: suppose that the camera is looking straight ahead, directly down the z-axis. Now turn the camera up-side down (in other words, rotate it 180 degrees around the z-axis). Did the camera’s viewing direction change? Nope. What if the camera was turned side-ways (or rotated 90 degrees around the z-axis)? Even then, the viewing direction doesn’t change (it’s still looking down the z-axis). So using just two points gives enough information to know where the camera is pointing, but it doesn’t describe the “roll” of the camera relative to itself. In this tutorial I haven’t allowed the camera to roll over, so the up-vector stays at (0, 1, 0) – in other words, the camera can’t look up or down.

Once we’ve created the camera point, look-at point, and up-vector, we pass all of them to D3DXMatrixLookAtLH() – a function that calculates a view/camera matrix and puts it into the first parameter, ViewMatrix.

Finally we call SetTransform() to feed DirectX our newly calculated matrix. The first parameter, D3DTS_VIEW, tells DirectX to use this matrix as the view/camera matrix. The second parameter is a pointer to the matrix itself.

The Rendering Loop

Now that all the matrices have been set, we’re ready to tackle the main rendering loop. Just as in the last tutorial, we begin by setting up the vertex format structure:

struct D3DVERTEX {float x, y, z; DWORD color;} vertices[NUM_VERTICES];

This time we don’t need the “rhw” component. We’re feeding DirectX non-transformed vertices so therefore a “w” component doesn’t apply. DirectX just needs the (x, y, z) components and the color of each vertex.

We then fill in the “vertices” array. Here’s an example of the first point:

vertices[0].x = -64.0f*3;

vertices[0].y = -64.0f;

vertices[0].z = 0;

vertices[0].color = FRONT_WALL_COLOR;

<…more vertices here…>

Once we’ve filled in all the vertices, we must feed them to DirectX. The code which feeds DirectX is exactly the same as before (see last tutorial) with one exception – the vertex format is different.

LPDIRECT3DVERTEXBUFFER9 pVertexObject = NULL;

void *pVertexBuffer = NULL;

 

if(FAILED(

g_pDirect3D_Device->CreateVertexBuffer(NUM_VERTICES*sizeof(D3DVERTEX), 0,

D3DFVF_XYZ|D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &pVertexObject, NULL)))

   return;

 

if(FAILED(pVertexObject->Lock(0, NUM_VERTICES*sizeof(D3DVERTEX), &pVertexBuffer, 0)))

   return;

 

memcpy(pVertexBuffer, vertices, NUM_VERTICES*sizeof(D3DVERTEX));

pVertexObject->Unlock();

The vertex type, D3DFVF_XYZRHW, gets replaced with D3DFVF_XYZ because we’re feeding in (x, y, z) components instead of (x, y, z, 1/w). I’m not going to go into the inner-workings on this code because it was already covered in the last tutorial.

Now we’re ready to render the scene. Again, this code looks much like the last tutorial except the vertex format has changed, plus, we’re now calculating the transformation matrices before rendering.

g_pDirect3D_Device->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); // clear frame

 

if(SUCCEEDED(g_pDirect3D_Device->BeginScene()))

{

   CalcMatrices();

   g_pDirect3D_Device->SetStreamSource(0, pVertexObject, 0,

   sizeof(D3DVERTEX));

   g_pDirect3D_Device->SetFVF(D3DFVF_XYZ|D3DFVF_DIFFUSE);

   g_pDirect3D_Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, NUM_VERTICES/3);

   g_pDirect3D_Device->EndScene();

}

 

g_pDirect3D_Device->Present(NULL, NULL, NULL, NULL);

pVertexObject->Release();

This time around, when we call SetFVF(), we supply the (x, y, z) vertex format instead of (x, y, z, 1/w) using the D3DFVF_XYZ constant as opposed to D3DFVF_XYZRHW. Also, we call CalcMatrices() before drawing any primitives so DirectX knows which transformations to apply to the scene. The rest of the code behaves exactly the same as the last tutorial, so I’m not going to cover it again.

Handling Keyboard Input

The tutorial program uses DirectX/DirectInput to capture keyboard actions, but I’m not going to cover how DirectInput works here. Instead, I’m going to show how the program reacts to different key presses.

The function HandleKeys() is called on every frame and is responsible for updating the global camera position tracking variables depending on the keyboard state.

void HandleKeys(void)

{

   float RotationStep = PI/175.0f;

   float WalkStep = 3.0f;

 

   //——————————————-

   // adjust the camera position and orientation

   //——————————————-

   if(dx_keyboard_state[DIK_UP]&0x80) // moving forward

   {

      g_Camera.Location.x += cos(g_Camera.Rotation)*WalkStep;

      g_Camera.Location.z += sin(g_Camera.Rotation)*WalkStep;

   }

 

   if(dx_keyboard_state[DIK_DOWN]&0x80) // moving backward

   {

      g_Camera.Location.x -= cos(g_Camera.Rotation)*WalkStep;

      g_Camera.Location.z -= sin(g_Camera.Rotation)*WalkStep;

   }

 

   if(dx_keyboard_state[DIK_LEFT]&0x80) // look left

   {

      g_Camera.Rotation += RotationStep;

 

      if(g_Camera.Rotation > PI*2)

         g_Camera.Rotation = g_Camera.Rotation-PI*2;

   }

 

   if(dx_keyboard_state[DIK_RIGHT]&0x80) // look right

   {

      g_Camera.Rotation -= RotationStep;

 

      if(g_Camera.Rotation < 0)

         g_Camera.Rotation = PI*2+g_Camera.Rotation;

   }

 

   if(dx_keyboard_state[DIK_W]&0x80) // strafe left

   {

      float SideStepAngle = g_Camera.Rotation+(PI/2.0f);

 

      if(SideStepAngle > PI*2) // handle wrap-around

         SideStepAngle = SideStepAngle-PI*2;

 

      g_Camera.Location.x += cos(SideStepAngle)*WalkStep;

      g_Camera.Location.z += sin(SideStepAngle)*WalkStep;

   }

 

   if(dx_keyboard_state[DIK_E]&0x80) // strafe right

   {

      float SideStepAngle = g_Camera.Rotation-(PI/2.0f);

 

      if(SideStepAngle < 0) // handle wrap-around

         SideStepAngle = PI*2+SideStepAngle;

 

      g_Camera.Location.x += cos(SideStepAngle)*WalkStep;

      g_Camera.Location.z += sin(SideStepAngle)*WalkStep;

   }

}

Walking forward and backward is a simple matter of updating the camera’s (x, z) position. We don’t update the y-coordinate because there’s no way to “jump” or float in the air for this example. If we were using a polar coordinate system (where point positions are based on angle and ray length), moving the camera forward or backward would be easy – just increase or decrease the ray length. But since we’re in the rectangular coordinate system (where point positions are determined by x, y, and z), we must convert this increase or decrease of ray length into the (x, z) equivalent. We do this with the sine/cosine functions and then add the result to the camera’s last position in order to get the new position (or subtract from the camera’s last position if we’re moving backwards). I’m not going to get into the basics of simple trigonometry, but if you want a detailed explanation of how these trajectory formulas work, email me through the Contact page.

Strafing, or side-stepping, is done just like moving forward or backwards except the angle used in the calculation is 90 degrees plus or minus the camera’s real angle. If you’re moving left the angle is plus 90, and if you’re moving backwards, the angle is minus 90.

For looking left or right we just add or subtract from the camera’s current angle to get the new angle. However, we must check to make sure the angle hasn’t “overflowed” or gone below zero. After all, a circle has a maximum of 360 degrees – so rotating by 370 degrees is really the same as rotating by just 10 degrees. Same goes for the other side – rotating by negative 10 gets you to the same point as +350.

All this updating of the camera’s global position/orientation object is eventually used by the CalcMatrices() function in order to create a new view matrix on every frame. In other words, DirectX always has the most current camera position and renders the room based on the camera position controlled by the keyboard.

Screenshot

Here’s what the output looks like:

directx_tutorial_3_room_screenshot

Conclusion

Wow, this post ended up being _way_ longer than expected! Anyway, if you have any questions about any of the material covered, please post a comment or send me an email through my Contact page.

Thanks for reading! 😉

-Greg Dolley

Advertisement

40 Responses to “DirectX 9 C++ Graphics Tutorial Part 3 – Drawing a Simple 3D Room”

  1. Added. Nice work on this one. Btw, my blog is dofollow, stop by and grab a link. Bompa

  2. Hackelberry Finn said

    Hey Guy.

    Your Tutorial seems nice 😉
    good night

  3. JokkiW007 said

    Your tutorials are great! Will this tutorial come for C#? (I can’t wait)

  4. gregd1024 said

    JokkiW007 – Yeah, I’m going to make a C# version of this. The code is quite similar to the C++ version, except the Managed DirectX API has a few shortcuts.

    -Greg

  5. gem said

    Hi,

    Nice tutorial, But I can compile the source code. It says, “Cannot open include file: ‘d3dx9.h’: No such file or directory”. I’m using Visual C++ 2008 Express Edition.

    I hope you can help. Thanks

  6. gregd1024 said

    Hi Gem,

    Check your “include” directories. Make sure they are pointing to the headers of the DirectX SDK. “d3dx9.h” is the main DirectX header. My project code uses the DirectX environment variable to get the “include” location. Make sure you have this set.

    -Greg

  7. Kurtis said

    Hey..

    Nice tutorials..

    When I try to compile I get 7 errors that look like this:

    1>Main.obj : error LNK2019: unresolved external symbol _D3DXMatrixPerspectiveFovLH@20 referenced in function _WinMain@16

    Any resolutions?

    Thanks

  8. gregd1024 said

    Hey Kurtis,

    I think the compiler can’t find dx3d.lib (or one of the other DirectX libraries listed in the linker options). I’d check that first. Second, make sure your installation of the DirectX SDK is at least the version mentioned in my tutorial (Nov. 2007 release).

    -Greg Dolley

  9. Z said

    Hey, Greg, thanks a lot for the tutorials! I know how busy life can get, and I appreciate the amount of time and work that went in to these :- )

    Any idea if/when you might get to the C# version, or how much further you will take the tutorials?

  10. gregd1024 said

    Hi Z,

    Thank you for the kind words! 🙂 As far as the C# version, I really don’t know since I’ve had virtually no free time to write it. But when I do have the time, I plan to take these tutorials to the texture mapping/lighting stage – similar to my OpenGL renderer shown in the old post about OpenGL lighting. Then I want to write some OpenGL tutorials.

    -Greg Dolley

  11. Brendan said

    you could use Code2Code.net for changing some of the code here to visual C# format. I am trying to do so, but it is quite annoying; matrices will not be converted to C# code, so this poses a problem…

  12. Lars said

    Hey Gred Nice Tut… Well G I V E M E a C# TUT PLEASE!

  13. Peter said

    Thank you so much!

    If you were to make a complete book or complete tutorial on how to end up with a simple character and a small map in some sort of game I would pay alot of money for it:D

    Seeing as you’re so busy perhaps you could just recommend me a good book for the rest of the 3d basics you havn’t covered? 🙂

    Regards, Peter

    • gregd1024 said

      Peter – how much money? LOL! 😉 As far as books go, you aren’t going to get any help from DirectX books because none of them include a graphics engine that is capable of handling the number of polygons in a real commercial game. The z-buffer hardware on 3D cards just isn’t fast enough to handle millions of polygons; but it’s good for small prototype engines, like the ones found in DirectX game programming books. You’ll have to mix the z-buffer with a BSP tree and a good PVS (potential visibility set) algorithm. Pick up the last 3D programming book written by Andre’ LaMothe (“Tricks of the 3D Game Programming Gurus-Advanced 3D Graphics and Rasterization”) for a good explanation on these techniques.

      -Greg Dolley

  14. Peter said

    Also why is the turning so choppy in the tutorial? Is there a way to set the framerate higher to fix this?

    • gregd1024 said

      As far as the choppiness goes, I’m not exactly sure why it’s like that. You’d think DirectX could handle more than 12 polygons! Well, it obviously can, but I’ve seen this same problem in a number of other tutorials too. I think it has something to do with the rendering frame being scaled to the viewport size (something that’s never done in commercial games – since the scene could get stretched and squished by resizing the main window).

  15. Peter said

    So if we got rid of the resize capability it would most likely work smoothly?

    • gregd1024 said

      Peter – it might work smoothly, or might not. Try it and see. 🙂 You add textures with a couple DirectX function calls. It’s in the DX9 help file. 😉

  16. Peter said

    Also how can you add a texture to one of these solid walls?

    Sorry if I’m asking too many questions, I’m only 14:P

  17. Tobias said

    Hello, do you prefer C# or C++?
    Is C# more of a hobby-programming language while C++ is for advanced stuff?
    C# seems a lot easier, but I havn’t seen many big companies using C# for their programming.

    • gregd1024 said

      Tobias – depends on the job. Some stuff C++ is better for, some stuff, C#. I prefer whatever is best for the task at hand. No, I wouldn’t say C# is a “hobby” programming language. C# is pretty much used everywhere for applications that aren’t video games and device drivers. So I don’t know why you say, “haven’t seen many big companies using C# for their programming.” I don’t see any companies using C++ anymore, unless it’s a legacy app, a video game, or device driver. Those are pretty much the only three cases. C++ seems to be dead for everything else. And, yes, C++ can do more advanced stuff.

  18. Tobias said

    Oh, ok 🙂
    Thanks for the answer. Well, I have mostly asked game developers, thats why..hehe 🙂

  19. Brendan said

    Hey Greg, I was wondering if you could point me in the direction of a site that would have a tutorial like the one your going to sometime make for C# for the 3D room? I am quite anxious and have grown a tad hopeless of your tutorial coming out by the end of summer, so no offense intended, but do you know of any others like yours (easy to read and understand)?

    • gregd1024 said

      Brendan – I would check out a book called “Managed DirectX 9.” The first couple chapters should give you everything you need to know to port my C++ room tutorial to C#. As far as other blogs go, sorry, I don’t know of any that have a similar type of tutorial.

      -Greg Dolley

  20. Brendan said

    Hey again, I think I actually will try learning some C++ now, and follow the tutorials for C++. always good to learn something new 😀 thanks for the reference though!

  21. fl00de said

    ..

    Hi! Nice tutorials!

    I’ve tried to download the source code, but it’s unavailable (I’m only getting timeout). Is there another link to it?

    Thanks!

    • gregd1024 said

      The links are going to be replaced soon. I’ve moved hosting providers and everything has taken longer than I expected with the new account. Don’t worry, they will be back up! 😉

      • Wd40bomber7 said

        It’s still not up?
        Oh and g_Camera.Location is not defined anywhere, it’s just magically used in the CalcMatrices function. I get the program to compile easily enough, but it just displays the black background, so I’m anxious to be able to download the source file to see where I went wrong.

  22. deype0 said

    Thank you!

  23. Anindita said

    Its really a good tutorial. Well I would like to know when Part 4 for the tutorial will be provided for C++.

  24. Mihai said

    Have you finished the C# tutorial for 3D room? I need something like this for a project at my school, and didn’t too much. I would appreciate if you could send me at least a code for a 3D room in C#. Tank you very much!

  25. JDM Parts said

    Nice tutorial I like it so much.

  26. yohan said

    nice graphics tutorial 🙂

  27. Glav said

    How do you manage to create a 17Kb file that works on every PC ? When I compile a Release version of your project, I get a ~40Kb EXE that only works on *my* PC (“MSVCR100.dll is missing” on PCs than haven’t Visual Studio installed). To avoid this error, I changed project Properties->Configuration Properties->C/C++->Code Generation->Runtime Library setting->”Multi-threaded DLL (/MD)” to “Multi-threaded (/MT)” and now it works everywhere but the EXE size is 68Kb…

    Can you tell us what configuration you are using to build such tiny EXEs ?

  28. steven said

    I really do not understand why everytime we strafe left, we need to get the camera’s real angle plus 90 degrees. Could you explain or recommend an ebook explaining something like this, please?.

    Thank you

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: