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


Drawing with Direct3D, Part 2: Lighting and Textures : Page 5

Learn how to use Direct3D's lighting model and textures to create more realistic three-dimensional scenes.

Illuminating Textures
You could improve the results of texture-rendering and make it more realistic by creating a different image for each side and then making some darker than others to simulate a lighting model. If the light sources in your scene never move, that would do the trick but it would be a lot of work.

Fortunately Direct3D provides a better solution by allowing you to combine textured surfaces with the Direct3D lighting model. To use textures with the lighting model, simply add lights, use a material, and use a texture. Direct3D combines the light values generated by its lighting model with those determined by the texture to give the result.

The only catch is that the images defined by textures are usually darker than a pure white surface, so they tend to darken the surface. When you are using the lighting model alone, you may want to use dimmer lights to produce a subtle, less harsh image. If you combine soft lights with a texture, the result may be very dark. To avoid that, you may need to use bright white lights. You may also need to experiment to find an acceptable result.

Figure 8 shows the d3dLightedTexturedCube program displaying the same cube shown in Figure 7 but this time with lighting added.

Figure 8. Bricks and Boards: The d3dLightedTexturedCube program draws a cube using textures and a lighting model.
You might think that texturing would be a performance killer, because the mathematics required to map an image onto an arbitrary triangle is moderately complicated and must be repeated a huge number of times to generate even a small image such as the one shown in Figure 8. Fortunately, most modern graphics hardware includes support for just this sort of mapping on the chipset which makes the calculations extremely fast.

The sample program d3dGasket (see Figure 9), draws a three-dimensional Sierpinski gasket. You can build one yourself by taking a wooden cube and carving square tunnels through its center parallel to the X, Y, and Z axes. Then carve smaller tunnels through each of the small cubes surrounding the tunnels. Continue carving smaller and smaller tunnels until you reach a satisfactory level.

To create Figure 9, d3dGasket uses three levels of recursion to carve three sets of tunnels. To render this scene, the program must cull, shade, and texture 96,000 triangles in real time. Despite the large number of triangles, the program has no trouble drawing the scene quickly enough to provide smooth rotation. However, at the next level of recursion, the program has some serious trouble, because it must draw some 1.92 million triangles, so it takes nearly a second to generate each frame.

Figure 9. Great Gasket: The d3dGasket program draws a Sierpinski gasket with 96,000 triangles.
Figure 10. Cube Farm: The d3dManyBoxes program rotates 120,000 triangles in real time.
The d3dManyBoxes program, shown in Figure 10, draws 10,000 rotating shaded and textured boxes (120,000 triangles) in real time. You can change the constants used by the program to try drawing different numbers of boxes. On my computer, the animation becomes noticeably rougher at around 1 million triangles.

When a program draws such huge scenes, you need to be aware of a new restriction. The Direct3D device's DrawPrimitives call can draw only a certain number of primitives at one time. You can learn the maximum by checking the device's DeviceCaps.MaxPrimitiveCount property. To draw more than that number, you must loop through the primitives making repeated calls to DrawPrimitives until you finish drawing them all.

Both d3dGasket and d3dManyCubes must draw their primitives this way. The following code shows that each time through the loop, the program draws m_MaxPrimitives triangles:

   Dim first_triangle As Integer = 0
   Dim num_triangles As Integer = m_MaxPrimitives
   Do While first_triangle < m_NumTriangles
       If first_triangle + num_triangles > m_NumTriangles Then
           num_triangles = m_NumTriangles - first_triangle
       End If
       m_Device.DrawPrimitives(PrimitiveType.TriangleList, _
           first_triangle * 3, num_triangles)
       first_triangle += num_triangles
That's the theory, anyhow; in practice I found that the d3dGasket program had trouble drawing the full number of primitives allowed according to the device's DeviceCaps.MaxPrimitiveCount property, so I reduced the number to 10,000, which works better for this program at least.

Go Forth and Draw
Direct3D's lighting models and textures let you produce some amazingly realistic scenes at performance levels capable of animating them in real time. Textures and lighting models add extra depth cues that make a scene appear more believable and engaging. If your light sources are stationary and you choose your textures carefully, you may even be able to provide some shadows to further enhance the illusion of reality.

Direct3D supports a few other methods for making scenes appear more realistic. These techniques include:

  • Bump Mapping – lets you perturb the normals on a surface to provide a little extra randomness.
  • Stencil Buffers – let you provide mirrors and shadows.
  • Environment Mapping – You can think of environment mapping as defining a three-dimensional "texture" wrapped around the outside of an object. Using this technique, you can make objects appear reflective, at least to a casual observer.
These techniques are complicated, and as the quest for ever more realistic scenes continues, the techniques become even more complicated and much slower. For example, Direct3D cannot reasonably produce true reflections on curved surfaces, or handle transparent or translucent objects. Ray tracing algorithms can handle those effects—and more—but they are very slow.

Even ray tracing is incapable of rendering effects such as light reflected and transmitted into the area surrounding an object. For that level of realism, you need to move to even more complicated algorithms such as radiosity and photonics. (For some remarkable results produced by a ray tracing and photonics program written in Visual Basic, take a look at Camil Moujaber's web page.)

Meanwhile, download the sample programs and try them out. Modify them—or build your own programs and create more complicated scenes. If you come up with one that's really interesting, email me at RodStephens@vb-helper.com, and I may post it for others to see on the VB Helper web site.

Rod Stephens is a consultant and author who has written more than a dozen books and two hundred magazine articles, mostly about Visual Basic. During his career he has worked on an eclectic assortment of applications for repair dispatch, fuel tax tracking, professional football training, wastewater treatment, geographic mapping, and ticket sales. His VB Helper web site receives more than 7 million hits per month and provides three newsletters and thousands of tips, tricks, and examples for Visual Basic programmers.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date