| 
 Basic 
  3D Geometry 
Author 
  : 
  Jack Hoxley 
Written : 8th December 2000 
Contact : [Web] 
  [Email] 
Download : Graph_05.Zip 
  [14 Kb] 
 
Contents 
  of this lesson: 
  1. Introduction 
  2. 3D graphics theory 
  3. Depth Buffers 
  4. Geometry and Vertex buffers 
  5. Matrices 
  6. Rendering 
 
1. 
  Introduction 
Welcome 
  to lesson 5. Hopefully by this point you should be capable of setting up a Direct3D8 
  application and rendering some 2D triangles with texture; perfect if you want 
  to do a 2D game, but hardly exciting when it comes down to cutting edge 3D graphics. 
  Which is where this lesson is aimed at. By the end of this tutorial you'll be 
  well on the road to creating your first 3D world - maybe not as far as cutting 
  edge yet, but it's a step in the right direction. 
Unfortunately 
  for you, this lesson is going to be big - there are 3 brand new important features 
  that I need to introduce you to: 3D world space, Vertex Buffers, matrices, Depth 
  Buffers and culling. These topics are the very basis of 3D graphics; so you're 
  going to need to learn them - and learn them well.  
On 
  with the learning: 
 
2. 
  3D graphics theory 
Yet 
  more theory to start a lesson; this time it's very important - ignore this lot 
  and you'll be stumped later on. As I mentioned above, this stuff is the very 
  foundation of a 3D engine. 
3D 
  World Space 
  This isn't greatly difficult really - it's just an extension of what you learnt 
  in lesson 03. You can set up world space in many different ways; usually so 
  that the +Y axis is "up" and -Y is "down" (although position 
  of the camera can always muddle this up). 3D coordinates are specified on 3 
  axis - X, Y and Z. If you're looking straight down the Z-Axis, +Y will be up, 
  +X will be right, +Z will be behind you, -Y will be down, -X will be left and 
  -Z will be in front of you (the distance). Of course, the camera position can 
  change all of this... 
Vertex 
  Buffers 
  Vertex buffers are similiar to textures in that they store pre-made data. Using 
  vertex buffers can help a great deal when it comes to generating complicated 
  scenes - instead of remembering 100's of different arrays for each part you 
  can compile it all into a vertex buffer and then render it with very few calls. 
  These aren't complicated to setup or use - but you should know that they exist. 
Matrices 
  This is a fun topic, matrices (plural of matrix) are actually quite an advanced 
  mathematics technique - which you're only likely to come across if you do (or 
  have done) advanced maths courses. It doesn't matter if you dont understand 
  the mathematical usage of them fully (I dont), as you only really need a basic 
  knowledge of how they work, and more importantly how to use them. There are 
  three main types of matrix you'll use (there are more): World Matrix, View Matrix 
  and Projection Matrix. The world matrix affects vertices - if you apply a rotated 
  world matrix all subsequently rendered vertices will be rotated by that amount 
  (but you're original data wont be altered). The view matrix is basically a camera 
  - it defines where the "eye" is, and where it's looking at (two cordinates 
  in 3D space); you can also specify which direction is up - in most cases you 
  make +Y the up axis; but you dont have to. Finally, the projection matrix describes 
  how and what Direct3D renders onto the screen - the field of view (FOV) and 
  the view angle. We'll be using all of these later on, where I'll discuss their 
  usage further. 
Depth 
  Buffers 
  These are very useful indeed; easy to set up, and once set up require no additional 
  attention - they just sit there and work. Think about this: you render two triangles 
  in 3D space - how do you know which triangle is in front of the other, or if 
  they intersect which parts of which triangle you render? A depth buffer solves 
  this - when you send a triangle to be renderered it stores the distance from 
  the camera in the depth buffer - if another triangle is rendered it decides 
  which pixels it'll occupy and decide what depth it's at - if this depth is less 
  than any existing pixel it replaces it, otherwise it's not drawn (there's something 
  in front of it). Depth buffers come in different depths - usually 16 bit, 24 
  bit and sometimes 32 bit; the higher the depth the better the quality and accuracy 
  but the more memory it uses and time it requires to calculate. Depth buffers 
  are also known as Z-Buffers. 
Culling 
  This isn't greatly important unless you're designing and coding you're own geometry. 
  By default Direct3D doesn't render any triangles that are facing away from the 
  camera - this is good as it speeds things up a great deal. Although you can 
  change what it culls, Direct3D normally culls triangles with vertices in a counter-clockwise 
  direction and keeps clockwise ordered vertices. It's simple logic to work out 
  which one yours are - if the vertices go round in a clockwise order (left-Right-Bottom 
  for example) or counter-clockwise order (Bottom-Right-Left). You can tell Direct3D 
  not to cull any triangles - but this will produce quite a large performance 
  loss, yet it's extremely useful when debugging.... 
 
3. 
  Depth Buffers 
Depth 
  buffers, as I mentioned above, are extremely simple to setup, and once their 
  operating you can pretty much ignore their existence. To initialise a depth 
  buffer you can use this code; a slight modification of the existing initialisation 
  code: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        
'## INITIALISE() CODE ##
  D3DWindow.EnableAutoDepthStencil
= 1 
D3DWindow.AutoDepthStencilFormat = D3DFMT_D16 '//16 bit Z-Buffer
  '//Then, after you've created the D3DDevice:
  '//We need to enable our Z Buffer
 
D3DDevice.SetRenderState D3DRS_ZENABLE, 1 | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Well 
  done, you now have a functioning depth buffer attached to you're render device. 
  If you remember to do this each time you'll be fine. The only thing to note 
  is that you must have hardware support for the selected Z-Buffer depth (if you're 
  using a hardware device). If you select a depth that isn't available two things 
  will happen : 1) the device falls back to a mode it supports or 2) it disables 
  depth buffering. Both of which are unpreferable. To check if the device supports 
  the Z-Buffer setup you want you can use the following code: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        If
                                                                          D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT,
                                                                          D3DDEVTYPE_HAL,
                                                                          DispMode.Format,
                                                                          D3DUSAGE_DEPTHSTENCIL,
                                                                          _ 
                                                                                 
                                                                          D3DRTYPE_SURFACE,
                                                                          D3DFMT_D16)
                                                                          =
                                                                          D3D_OK
                                                                          Then 
    'We can use a 16 bit Z-Buffer
                                                                           
                                                                             
                                                                          D3DWindow.AutoDepthStencilFormat
                                                                          =
                                                                          D3DFMT_D16 '//16 bit Z-Buffer
                                                                           
                                                                          Else 
    'We could now check for different modes available...
                                                                           
                                                                          End If | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
If 
  you want to search for other depth buffer modes you can use this little piece 
  of enumeration code: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        If
                                                                          D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT,
                                                                          D3DDEVTYPE_HAL,
                                                                          DispMode.Format,
                                                                          D3DUSAGE_DEPTHSTENCIL,
                                                                          _  
                                                                                 
                                                                          D3DRTYPE_SURFACE,
                                                                          D3DFMT_D16)
                                                                          =
                                                                          D3D_OK
                                                                          Then 
                                                                             
                                                                          Debug.Print
                                                                          "16
                                                                          bit
                                                                          Z-Buffers
                                                                          are
                                                                          supported
                                                                          (D3DFMT_D16)" 
                                                                          End If 
                                                                           
                                                                          If
                                                                          D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT,
                                                                          D3DDEVTYPE_HAL,
                                                                          DispMode.Format,
                                                                          D3DUSAGE_DEPTHSTENCIL,
                                                                          _ 
                                                                                 
                                                                          D3DRTYPE_SURFACE,
                                                                          D3DFMT_D16_LOCKABLE)
                                                                          =
                                                                          D3D_OK
                                                                          Then 
                                                                             
                                                                          Debug.Print
                                                                          "Lockable
                                                                          16 bit
                                                                          Z-Buffers
                                                                          are
                                                                          supported
                                                                          (D3DFMT_D16_LOCKABLE)" 
                                                                          End If 
                                                                           
                                                                          If
                                                                          D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT,
                                                                          D3DDEVTYPE_HAL,
                                                                          DispMode.Format,
                                                                          D3DUSAGE_DEPTHSTENCIL,
                                                                          _ 
                                                                                 
                                                                          D3DRTYPE_SURFACE,
                                                                          D3DFMT_D24S8)
                                                                          =
                                                                          D3D_OK
                                                                          Then 
                                                                             
                                                                          Debug.Print
                                                                          "32
                                                                          bit
                                                                          divided
                                                                          between
                                                                          24 bit
                                                                          Depth
                                                                          and 8
                                                                          bit
                                                                          stencil
                                                                          are
                                                                          supported
                                                                          (D3DFMT_D24S8)" 
                                                                          End If 
                                                                           
                                                                          If
                                                                          D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT,
                                                                          D3DDEVTYPE_HAL,
                                                                          DispMode.Format,
                                                                          D3DUSAGE_DEPTHSTENCIL,
                                                                          _  
                                                                                 
                                                                          D3DRTYPE_SURFACE,
                                                                          D3DFMT_D24X4S4)
                                                                          =
                                                                          D3D_OK
                                                                          Then 
                                                                             
                                                                          Debug.Print
                                                                          "32
                                                                          bit
                                                                          divided
                                                                          between
                                                                          24 bit
                                                                          depth,
                                                                          4 bit
                                                                          stencil
                                                                          and 4
                                                                          bit
                                                                          unused
                                                                          (D3DFMT_D24X4S4)" 
                                                                          End If 
                                                                           
                                                                          If
                                                                          D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT,
                                                                          D3DDEVTYPE_HAL,
                                                                          DispMode.Format,
                                                                          D3DUSAGE_DEPTHSTENCIL,
                                                                          _ 
                                                                                 
                                                                          D3DRTYPE_SURFACE,
                                                                          D3DFMT_D24X8)
                                                                          =
                                                                          D3D_OK
                                                                          Then 
                                                                             
                                                                          Debug.Print
                                                                          "24
                                                                          bit
                                                                          Z-Buffer
                                                                          supported
                                                                          (D3DFMT_D24X8)" 
                                                                          End If 
                                                                           
                                                                          If
                                                                          D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT,
                                                                          D3DDEVTYPE_HAL,
                                                                          DispMode.Format,
                                                                          D3DUSAGE_DEPTHSTENCIL,
                                                                          _ 
                                                                                 
                                                                          D3DRTYPE_SURFACE,
                                                                          D3DFMT_D32)
                                                                          =
                                                                          D3D_OK
                                                                          Then 
                                                                             
                                                                          Debug.Print
                                                                          "Pure
                                                                          32 bit
                                                                          Z-buffer
                                                                          supported
                                                                          (D3DFMT_D32)" 
                                                                          End If 
 | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
There; 
  you now know about as much as you'll ever need to know about depth buffers. 
 
4. 
  Geometry and Vertex Buffers 
Geometry 
  creation in full 3D is not really that different from when we did it with 2D, 
  the only difference being that we use 3 dimensions rather than 2. Later on when 
  we do lighting it gets a little bit more complicated. 
The 
  first thing that we must do is define a new vertex format to use; we'll be using 
  the equivelent of the D3DLVERTEX type from DirectX7; where we give it a position 
  and a colour and Direct3D transforms it. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        '//We're
                                                                          using
                                                                          3D
                                                                          vertices,
                                                                          but
                                                                          we're
                                                                          not
                                                                          using
                                                                          Lighting
                                                                          just
                                                                          yet... 
                                                                          '  
                                                                          which
                                                                          means
                                                                          we
                                                                          need
                                                                          to
                                                                          specify
                                                                          the
                                                                          vertex
                                                                          colour
 
Private Type LITVERTEX 
    x As Single 
    y As Single 
    z As Single 
    color As Long 
    Specular As Long 
    tu As Single 
    tv As Single 
End Type 
 
'//The Descriptor for this vertex format...
 
Const Lit_FVF = (D3DFVF_XYZ Or D3DFVF_DIFFUSE Or D3DFVF_SPECULAR Or D3DFVF_TEX1) 
 
Dim Cube(35) As LITVERTEX | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Notice 
  that I've also put in the declaration for our geometry; 36 vertices for a cube 
  - sounds a lot; it is. Methods later on (using indices/index buffers) will allow 
  us to generate the same cube for only 8 vertices. If we were using triangle 
  strips we could do this cube for 24 vertices - but writing it to a vertex buffer 
  would have been more awkward. 
We'll 
  now re-write our InitGeometry( ) function so that it creates a cube. Two things 
  to note with this code - 1) I didn't bother with checking the the vertex order 
  (for culling) and 2) all vertices are generated around the origin - the middle 
  of the cube is going to be [0, 0, 0] and the rest of the vertices are equally 
  distributed around this (+- 1m); when you've finished reading about matrices 
  you'll understand why. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        Code
                                                                          In
                                                                          This
                                                                          Font/Size
                                                                          in
                                                                          these
                                                                          tables. 
      '//I used the Immediate window to
'   get the RGB() values for each of these...
Const C000 As Long = 255     '//Red
Const C001 As Long = 65280  '//Green
Const C100 As Long = 16711680   '//Blue
Const C101 As Long = 16711935 '//Magenta
Const C010 As Long = 65535 '//Yellow
Const C011 As Long = 16776960 '//Cyan
Const C110 As Long = 16777215 '//White
Const C111 As Long = 8421631 '//Orange
'//1. Fill the structures with the data
        'Front
        Cube(0) = CreateLitVertex(-1, 1, 1, C011, 0, 0, 0)
        Cube(1) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
        Cube(2) = CreateLitVertex(-1, -1, 1, C001, 0, 0, 0)
        Cube(3) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
        Cube(4) = CreateLitVertex(-1, -1, 1, C001, 0, 0, 0)
        Cube(5) = CreateLitVertex(1, -1, 1, C101, 0, 0, 0)
        'Back
        Cube(6) = CreateLitVertex(-1, 1, -1, C010, 0, 0, 0)
        Cube(7) = CreateLitVertex(1, 1, -1, C110, 0, 0, 0)
        Cube(8) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
        Cube(9) = CreateLitVertex(1, 1, -1, C110, 0, 0, 0)
        Cube(10) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
        Cube(11) = CreateLitVertex(1, -1, -1, C100, 0, 0, 0)
        'Right
        Cube(12) = CreateLitVertex(-1, 1, -1, C010, 0, 0, 0)
        Cube(13) = CreateLitVertex(-1, 1, 1, C011, 0, 0, 0)
        Cube(14) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
        Cube(15) = CreateLitVertex(-1, 1, 1, C011, 0, 0, 0)
        Cube(16) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
        Cube(17) = CreateLitVertex(-1, -1, 1, C001, 0, 0, 0)
        
        'Left
        Cube(18) = CreateLitVertex(1, 1, -1, C110, 0, 0, 0)
        Cube(19) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
        Cube(20) = CreateLitVertex(1, -1, -1, C100, 0, 0, 0)
        Cube(21) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
        Cube(22) = CreateLitVertex(1, -1, -1, C100, 0, 0, 0)
        Cube(23) = CreateLitVertex(1, -1, 1, C101, 0, 0, 0)
        'Top
        Cube(24) = CreateLitVertex(-1, 1, 1, C011, 0, 0, 0)
        Cube(25) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
        Cube(26) = CreateLitVertex(-1, 1, -1, C010, 0, 0, 0)
        Cube(27) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
        Cube(28) = CreateLitVertex(-1, 1, -1, C010, 0, 0, 0)
        Cube(29) = CreateLitVertex(1, 1, -1, C110, 0, 0, 0)
        'Top
        Cube(30) = CreateLitVertex(-1, -1, 1, C001, 0, 0, 0)
        Cube(31) = CreateLitVertex(1, -1, 1, C101, 0, 0, 0)
        Cube(32) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
        Cube(33) = CreateLitVertex(1, -1, 1, C101, 0, 0, 0)
        Cube(34) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
        Cube(35) = CreateLitVertex(1, -1, -1, C100, 0, 0, 0)
                                                                         | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Looks 
  great doesn't it. Just imagine how complicated it'd be to make a sphere or a 
  person... which is why you'll love using externally created objects and loading 
  them straight in. You'll notice that I've used constants for all the colours 
  - a cube is made up of 8 corners, so I designed 8 constants for colour - a colour 
  for each corner. As 3-4 vertices can share the same point I just placed the 
  constant as the colour; if you change the constant all required vertices will 
  change colour as well. 
You 
  may also have noticed that I haven't mentioned vertex buffers yet. Well, here 
  they are. Vertex buffers are basically an allocated amount of memory filled 
  with vertex data; specially formatted by Direct3D so it can access them easier 
  and faster (most of the time). The first step is to allocate enough memory for 
  the vertex buffer, then we fill it with the Cube( ) vertex data that we've just 
  defined. To do this, we use the following code: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        '//2. Create us a blank vertex buffer of the required size
 
 
Set VBuffer = D3DDevice.CreateVertexBuffer(Len(Cube(0)) * 36, 0, Lit_FVF,
D3DPOOL_DEFAULT) 
If VBuffer Is Nothing Then Exit Function '//Error handler
 
 
 
 
'//3. Fill the created vertex buffer with the data
 
D3DVertexBuffer8SetData VBuffer, 0, Len(Cube(0)) * 36, 0, Cube(0)
 | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Note 
  that we must specify the size of the vertex buffer in bytes - this MUST be accurate 
  or we'll cause a mess; too small and you'll get errors when filling it up, too 
  big and you'll waste memory. The size is going to be "Size of one vertex 
  * number of vertices" - we use the Len( ) function to work out the size, 
  then we multiply this by the number of vertices we have (36). we must also supply 
  the vertex format (FVF) so that Direct3D knows what it's looking at; finally 
  we then decide how Direct3D should manage our vertex buffer; D3DPOOL_DEFAULT 
  should suffice, otherwise you can specify D3DPOOL_MANAGED (Let it choose, and 
  move it around as it sees fit) or D3DPOOL_SYSTEMMEM (place it in system memory 
  (RAM)). 
Next, 
  we fill the vertex buffer using a hidden function (sort of hidden anyway). We 
  give it the name of our vertex buffer and the size of the area we wish to fill 
  and the offset (should we wish to start somewhere other than the beginning). 
  finally we pass the array of data that we want to pass; this must be equal in 
  size and format to that which we created the vertex buffer for - or nasty things 
  will probably happen. 
Assuming 
  nothing went wrong above we can move onto more interesting things.... 
 
5. 
  Matrices 
Matrices 
  are an extremely useful thing to understand; they allow you to do an enourmous 
  amount of things to 3D worlds. Matrices are quite a complicated mathematical 
  topic - so I wont go into how/why matrices work - just how you can use them. 
  A matrix, in Direct3D, is a 4x4 matrix - think of it like a grid, with 4 entries 
  along the top and 4 entries down the side. Direct3D uses these numbers to alter 
  various things during low-level processing - between the time you make calls 
  to render and the time they appear on screen. 
There 
  are a few things that you should bare in mind when using matrices: 
  1. You can combine matrices together to form a new matrix; for example, if you 
  multiply a rotation and a translation matrix you will get a single matrix that 
  rotates and translates anything it's given. 
  2. Unlike normal numbers where (A * B) = (B * A) multiplying matrices [A] * 
  [B] does not equal [B] * [A] - so it's important to do things the right way 
  around. 
  3. There are lots of functions in the D3DX8 library to help with manipulating 
  matrices 
There 
  are three types of matrix that you'll always have to use; others are for different 
  effects. The main types are outlined below: 
World 
  Matrix 
  This matrix alters the vertices - this is the one you'll use the most often. 
  All transformations of vertices work around the origin [0,0,0] - it rotates 
  vertices around the origin, scales vertices around the origin. This is why (earlier) 
  we created our cube around the origin. As already mentioned it is possible to 
  combine multiple matrices to form a single all-in-one matrix; but as you also 
  should remember, the order you multiply them matters. If you rotate something 
  around the X axis and the Z axis you'll not get the same result if you'd rotated 
  around the Z then the X. For example, if you have a car wheel and rotate it 
  around the X axis you'll get it rotating like a wheel should, if you then rotate 
  it around the Z axis it'll appear to be tilted in one direction - but it'll 
  still rotate like a wheel should. If you rotate around the Z axis the wheel 
  will appear to tilt, if you then rotate it around the X axis the wheel will 
  seem to wobble as it goes around; the effect is best seen when animated though. 
The 
  following code is from the sample for this lesson: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        Dim
                                                                          matWorld
                                                                          As
                                                                          D3DMATRIX Dim
                                                                          matTemp
                                                                          As
                                                                          D3DMATRIX
  D3DXMatrixIdentity
                                                                          matWorld '//Reset our world matrix
                                                                           
                                                                               
                                                                          D3DXMatrixIdentity
                                                                          matTemp 
                                                                          D3DXMatrixRotationX
                                                                          matTemp,
                                                                          RotateAngle
                                                                          * (pi
                                                                          / 180) 
                                                                          D3DXMatrixMultiply
                                                                          matWorld,
                                                                          matWorld,
                                                                          matTemp 
                                                                               
                                                                          D3DXMatrixIdentity
                                                                          matTemp 
                                                                          D3DXMatrixRotationZ
                                                                          matTemp,
                                                                          RotateAngle
                                                                          * (pi
                                                                          / 180) 
                                                                          D3DXMatrixMultiply
                                                                          matWorld,
                                                                          matWorld,
                                                                          matTemp 
                                                                               
                                                                                  
                                                                          D3DDevice.SetTransform
                                                                          D3DTS_WORLD,
                                                                          matWorld | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
okay, 
  not too complicated really. First we create two matrices, one is our "Master" 
  matrix, the other is a temporary one, because we're doing more than one transformation 
  we need something to store each step before multiplying it. Next we reset our 
  master matrix - this is very important as matrix multiplying and transforming 
  is a cumulative thing - if you alter it each frame without reseting it very 
  quickly things will go very strange. The Identity matrix isn't actually a matrix 
  where everything is set to '0', all the X=Y entries are filled with '1's [1,1] 
  [2,2] [3,3] [4,4]. After we've reset our matrix we start manipulating it; the 
  available transformations are: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        '//Normal Rotation D3DXMatrixRotationX(Out
                                                                          As
                                                                          D3DMATRIX,
                                                                          angle
                                                                          As
                                                                          Single) D3DXMatrixRotationY(Out
                                                                          As
                                                                          D3DMATRIX,
                                                                          angle
                                                                          As
                                                                          Single) 
                                                                          D3DXMatrixRotationZ(Out
                                                                          As
                                                                          D3DMATRIX,
                                                                          angle
                                                                          As
                                                                          Single)
  '//Rotation through a custom axis '  You must specify an axis using the VAxis setting '  FYI: X=[1,0,0] Y=[0,1,0] and Z=[0,0,1] D3DXMatrixRotationAxis(MOut
                                                                          As
                                                                          D3DMATRIX,
                                                                          VAxis
                                                                          As
                                                                          D3DVECTOR,
                                                                          angle
                                                                          As
                                                                          Single) 
  '//Misc Transforms 'This scales vertices by the amounts specified D3DXMatrixScaling(MOut
                                                                          As
                                                                          D3DMATRIX,
                                                                          x As
                                                                          Single,
                                                                          y As
                                                                          Single,
                                                                          z As
                                                                          Single) 'this moves vertices by the amounts specified D3DXMatrixTranslation(MOut
                                                                          As
                                                                          D3DMATRIX,
                                                                          x As
                                                                          Single,
                                                                          y As
                                                                          Single,
                                                                          z As
                                                                          Single)
  'Others are available, and are listed in the object browser - and can be found by going DxVBLibA -> D3DXMATH_MATRIX
 | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
One 
  thing to note about the angles specified when rotating - they're in radians 
  not degrees. If you're happy using radians thats fine, but if you prefer to 
  use degrees you can use this simple conversion: Degrees * (Pi / 180) where Pi 
  is 3.14159265358979 (which in turn can be worked out using (4 * atn(1))) 
Finally 
  we get to the point where we apply the transformation to our rendering device. 
  This can be done as often as you wish, but the less times the better. Once this 
  matrix is applied all vertices rendered after that point will be transformed 
  accordingly - and will continue to be until another matrix is set. 
View 
  Matrix 
  The view matrix can be thought of as the camera; whilst the projection matrix 
  (see later) controls some of the more complicated parts of the "camera", 
  the view matrix is the one you alter if you wish to move the camera around (as 
  most games do). Setting the view matrix is extremely simple, but you need to 
  think about it a little first - if nothing is appearing on screen then the chances 
  are that you've got the camera set up wrong... 
To 
  alter the view matrix we'll need this code: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        '//The function prototype D3DXMatrixLookAtLH(MOut
                                                                          As
                                                                          D3DMATRIX,
                                                                          VEye
                                                                          As
                                                                          D3DVECTOR,
                                                                          VAt As
                                                                          D3DVECTOR,
                                                                          VUp As
                                                                          D3DVECTOR)
  '//And this is an example: Dim
                                                                          matView
                                                                          as
                                                                          D3DMATRIX Dim
                                                                          vecFrom
                                                                          as
                                                                          D3DVECTOR Dim
                                                                          vecTo
                                                                          as
                                                                          D3DVECTOR Dim
                                                                          vecUP
                                                                          as
                                                                          D3DVECTOR
  '//The camera is at this point in 3D worldspace vecFrom.X
                                                                          = 0 vecFrom.Y
                                                                          = 10 vecFrom.Z
                                                                          = 10
  '//And it is looking at this point: vecTo.X
                                                                          = 0 vecTo.Y
                                                                          = 0 vecTo.Z
                                                                          = 0
  '//Unless you want to do something clever you '  Can leave this as it is for all applications vecUp.X
                                                                          = 0 vecUp.Y
                                                                          =
                                                                          1   vecUp.Z
                                                                          = 0
  '//Now we generate Our final Matrix
  D3DXMatrixLookAtLH
                                                                          matView,
                                                                          vecFrom,
                                                                          vecTo,
                                                                          vecUp
  D3DDevice.SetTransform
                                                                          D3DTS_VIEW,
                                                                          matView
 | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
As 
  you can see, it's quite easy to update the position of the camera. Check out 
  the DirectX 7 immediate mode tutorials on camera 
  placement - whilst it's using DirectX 7 interfaces, the maths will still be 
  the same to get the camera to follow a "person" around, or move according 
  to the user...  
Projection 
  Matrix 
  Finally we come to the projection matrix; this matrix isn't used as often 
  as the other two, but it's equally as important. The projection matrix controls 
  how the scene appears when we look through our camera - you can set the field 
  of view (the closest and furthest objects visible) and the view angle (wide 
  angle or tele-photo). Unless you're intending to make a game with a zoom feature 
  or some weird head-messing-up game you're unlikely to set this matrix very often; 
  normally it's setup during initialisation and left. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                         
      '//The function prototype:
D3DXMatrixPerspectiveFovLH( MOut As D3DMATRIX, fovy As Single, aspect As Single, zn As Single, zf As Single)
'Where Mout is the result
'fovy is the view angle
'Aspect is the aspect ratio
'zn is the nearest boundary for polygons - anything between here and the camera position are not rendered
'zf is the furthest boundary - anything beyond here is not drawn
'//Finally we create our matrix
D3DXMatrixPerspectiveFovLH matProj, pi / 4, 1, 0.1, 500
'//And then we commit it to our Direct3D device
D3DDevice.SetTransform D3DTS_PROJECTION, matProj 
                                                                         | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
That's 
  not greatly difficult is it. The only two stumbling blocks are the "fovy" 
  and "aspect" parameters; the fovy is an angle specified in radians 
  - for this it's much easier to keep it in radians, as you're only ever likely 
  to use a few values - all of them "pi / something" where something 
  is going to be in the range of 2 - 9, with 2 being wide angle and 9 being telephoto, 
  dont set it to 0, as you'll get nothing displayed, and quite probably a divide 
  by 0 error (pi / 0 ). Then there's the aspect ratio - you can usually leave 
  this as 1 (1:1 ratio); if you make it less than 1 it appears to stretch geometry 
  vertically, greater than 1 appears to stretch geometry horizontally.  
Matrices 
  aren't that difficult really - but you'll use them for almost every full-3D 
  scene that you render; so you'll probably learn them quite quickly. One final 
  thing to remember, which is common sense really: if world matrices transform 
  vertices you cant use them with transformed and lit vertices... 
 
6. 
  Rendering 
Rendering 
  isn't a big change, just a few new lines for you to look at, so I wont bother 
  spending much time going over it all again... 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        '//First off we'll alter the device clearing code: D3DDevice.Clear
                                                                          0,
                                                                          ByVal
                                                                          0,
                                                                          D3DCLEAR_TARGET
                                                                          Or
                                                                          D3DCLEAR_ZBUFFER,
                                                                          0, 1#,
                                                                          0  
  '//Secondly, we must change how we render our primatives: D3DDevice.SetStreamSource
                                                                          0,
                                                                          VBuffer,
                                                                          Len(Cube(0)) 
                                                                          D3DDevice.DrawPrimitive
                                                                          D3DPT_TRIANGLELIST,
                                                                          0, 12 | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Not 
  greatly difficult really; as we're now using Z-buffers (or Depth buffers - whichever 
  you prefer) we'll need to clear that buffer as well as the rendering target 
  - if you forget to clear the Z-Buffer you can get some weird effects happening 
  with the draw-order. Lastly, when using vertex buffers to hold our geometry 
  we must render them slightly differently; commit the vertex buffer to the specified 
  pipeline/stream and tell Direct3D how big each entry will be; once that's done 
  we can use the normal (and simpler) D3DDevice.DrawPrimative statement. Assuming 
  everything has gone okay (it should of) you should be looking at something similiar 
  to this: 
  
I 
  created a slightly different geometry set so that you could see each face 
  being rendered. 
 
As 
  per normal you can download the complete source code for this tutorial from 
  the top of this page, I advise that you do play around with the code and get 
  familiar with how things work. 
Assuming 
  you're ready to continue - onto Lesson 06 : Drawing 
  Text - Custom Rasterizers and Normal 2D text. 
                                       |