RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Drawing with Direct3D, Part 1: Getting Started : Page 4

Learn how to produce amazing, high-performance, three-dimensional pictures in Visual Basic or C# by using Direct3D.

Making a Cube
Now that you understand the basics of how to create the Direct3D device, create data buffers, define transformations, and display the results, you can display just about anything.

Figure 5. Cubist Art: The d3dDrawCube program draws a single triangle list containing 12 triangles that make up a cube.
The d3dDrawTriangle and d3dRotatingTriangle sample programs each display a single triangle from the list of vertices, but it's easy enough to add other triangles to the list. Figure 5 shows the d3dDrawCube program. Like programs d3dDrawTriangle and d3dRotatingTriangle, this program displays a single triangle list. In this program, however, the list defines 12 triangles that together make up the cube's sides.

The code used by the d3dDrawCube program contains a few additions you haven't seen in the other programs. Obviously, it contains code to define the triangles that make up the cube. The MakeTriangle helper method shown in the following code makes it easy to define a triangle. It takes as parameters the vertex array, the index at which it should place the triangle's first point, the triangle's color, and the coordinates of its points. The code simply fills in the data in the vertex array:

   ' Add a triangle to the vertex buffer.
   Private Sub MakeTriangle( _
    ByVal vertices() As _
       CustomVertex.PositionColored, _
    ByRef i As Integer, ByVal clr As Color, _
       ByVal x0 As Single, ByVal y0 As Single, ByVal z0 As Single, _
       ByVal x1 As Single, ByVal y1 As Single, ByVal z1 As Single, _
       ByVal x2 As Single, ByVal y2 As Single, ByVal z2 As Single)
       vertices(i).X = x0
       vertices(i).Y = y0
       vertices(i).Z = z0
       vertices(i).Color = clr.ToArgb
       i += 1
       vertices(i).X = x1
       vertices(i).Y = y1
       vertices(i).Z = z1
       vertices(i).Color = clr.ToArgb
       i += 1
       vertices(i).X = x2
       vertices(i).Y = y2
       vertices(i).Z = z2
       vertices(i).Color = clr.ToArgb
       i += 1
   End Sub
The program's CreateVertexBuffer method uses this code to create the triangles it needs:

   ' Top +Y.
   MakeTriangle(vertices, i, Color.Green, _
       1, 1, -1, -1, 1, -1, -1, 1, 1)
   MakeTriangle(vertices, i, Color.Green, _
       -1, 1, 1, 1, 1, 1, 1, 1, -1)
   ' Bottom. -Y
   MakeTriangle(vertices, i, Color.White, _
       1, -1, -1, 1, -1, 1, -1, -1, 1)
   MakeTriangle(vertices, i, Color.White, _
       -1, -1, 1, -1, -1, -1, 1, -1, -1)
   ... Code to create other triangles omitted...
The following code shows the change to this program's Render method. This code is very similar to the code used by the previous programs except it passes the number of triangles (12) to the call to DrawPrimitives to tell Direct3D how many triangles are in the triangle list:

   ' Draw the primitives in the data stream.
   m_Device.DrawPrimitives(PrimitiveType.TriangleList, _
       0, NUM_TRIANGLES)
Program d3dDrawCube contains two other significant differences from the previous programs. First, this program introduces the concept of culling. Culling is a process that lets Direct3D quickly eliminate some of the triangles from the drawing. Culling can be very fast if you are drawing a convex polyhedron made up of consistently oriented faces.

A polyhedron is convex if every angle between two faces is at least zero. In other words, it contains no nooks and crannies that dent into the solid. Or to think of it another way, for every face on the solid you can place the solid on a flat surface so that every point on that face touches the flat surface. Cubes, tetrahedrons, and rectangular boxes are all convex.

You can determine a triangle's orientation by arranging its points so they are ordered clockwise or counterclockwise when seen from the outside of the polyhedron. If you a look at Figure 5, you can imagine the points defining one of the triangles ordered either clockwise or counterclockwise.

Here's where culling comes in. If you are drawing a convex polyhedron and the faces are oriented, then you can tell which ones to draw simply by looking at whether their points are arranged clockwise or counterclockwise as seen from the camera. Suppose all of the faces are oriented clockwise as seen from outside the solid. Then if a triangle's points are arranged counterclockwise as seen by the camera, then the camera must be looking through the solid to that triangle. That means the triangle is a backface, a face on the back of the solid, so it doesn't need to be drawn. For a convex solid, removing all the backfaces is sufficient to remove all the hidden triangles, so the displayed image presents the solid as you would expect.

To provide this kind of culling, the d3dDrawCube program's InitializeGraphics method uses the following code:

   ' Cull triangles that are oriented counter clockwise.
   m_Device.RenderState.CullMode = Cull.CounterClockwise
The second significant change this program contains is the ability to display its data as solid colored triangles, as a wireframe (as shown in Figure 5), or as a collection of points. When users click any of the program's three option buttons, the following event handler sets the Direct3D device's RenderState.FillMode property to the appropriate value. The Render method draws the data as usual and Direct3D produces the desired representation:

   ' Remember the selected fill mode.
   Private Sub FillMode_CheckedChanged( _
    ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles radSolid.CheckedChanged, radWireframe.CheckedChanged, _
      If m_Device Is Nothing Then Exit Sub
      If radSolid.Checked Then
         m_Device.RenderState.FillMode = FillMode.Solid
      ElseIf radWireframe.Checked Then
         m_Device.RenderState.FillMode = FillMode.WireFrame
         m_Device.RenderState.FillMode = FillMode.Point
      End If
   End Sub
The InitializeGraphics method also uses the following code to make Direct3D draw points larger than the default, so they're easy to see when it displays the data as points instead of solid faces or a wireframe:

   ' Make points bigger so they're easy to see.
   m_Device.RenderState.PointSize = 4

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date