Today games are developed almost exclusively in 3D, and the era of the traditional 2D game is practically at an end. Although there are still many 2D games being developed for platforms such as Game Boy Advance, such games are in the minority and are highly proprietary. This chapter focuses on 3D graphics programming. You will learn the basics of how to create and draw 3D objects, such as triangles, rectangles, cubes, cones, and cylinders, as well as how to apply textures to such objects. This chapter provides you with what you might call a low-level view of 3D graphics, because you will have an opportunity to create 3D objects from scratch using source code, providing that extremely important foundation for more advanced techniques (such as meshes).
The one thing that this chapter does not do is bore you with 3D theory. Instead, I have designed this chapter to explain the specific DarkBASIC commands that you need to write 3D programs. There is value in understanding the underlying matrix mathematics involved in rendering a 3D scene, but the subject can become overwhelming quickly! Rather than spend time explaining the details, this chapter just shows you the steps for getting a 3D game up on the screen. After all, do you really care how a texture is wrapped around a mesh? If you do, then why are you reading a beginner book? Just kidding! But if you would like more depth, I recommend that you pick up a book dedicated to 3D programming, such as Beginning Direct3D Game Programming (Premier Press, 2001), which is listed in Appendix B, "Recommended Books and Web Sites."
This chapter is chock full of sample source code listings! If you struggle with any specific subject related to 3D graphics, you will surely be able to figure out what is going on by running the sample programs in this chapter. This chapter differs from the others in that the sample programs are for DarkBASIC Professional, rather than for standard DarkBASIC. If you are a regular DarkBASIC Pro user, then this will be welcome. However, if you have been using standard DarkBASIC throughout the book, you can load the projects (which are available for both versions) off the CD-ROM. You can also install DarkBASIC Pro to type in and run the programs in this chapter. (The DarkBASIC Pro demo is available on the CD-ROM.)
The subject of 3D graphics truly consists of a monumental amount of information. Not only have entire books been written just about the basics of 3D graphics, but entire sets of volumes have been dedicated to the subject of advanced 3D rendering techniques. The 3D graphics business is a multi-billion dollar industry that encompasses video games and the motion picture industry, as well as commercial aviation and military applications. The astonishing thing about 3D graphics is how much they have improved over the years, both in theory and in application. There are techniques in use today, such as mip-mapping and multi-texturing, that are staggering in their realism. It is quite possible to mistake a real-time 3D demonstration for a pre-rendered video because the quality of rendered graphics today is so astonishing. Figure 17.1 shows a sample program called Light1, which comes with
Figure 17.1: The Light1 example program from DarkBASIC Professional, rendered with an ATI Mobility M4 (a laptop graphics chip)
DarkBASIC Professional. It shows just one example (among the many examples that come with the compiler) of the 3D capabilities built into DarkBASIC. In this example, only two light sources are used.
Although visual quality is really just a factor of your video card's features and capabilities, it does not take extraordinarily complex scenes to make a great game. Realism is definitely a good thing, but only if the majority of PCs in the world are able to run the game! The one thing you definitely do not want to do is limit the potential audience for your game by putting in so many high-quality scenes and models that it requires the very latest generation of video card to run the game. The latest generation Nvidia graphics accelerator is the GeForce4 Ti 4600 chip, which is capable of drawing 136 million vertices and 4.8 billion pixels per second. These numbers might not mean anything to you, but later in this chapter you will learn more about vertices and pixel fill rate. Take a look at Figure 17.2 for a photo of an MSI video card based on the Nvidia GeForce4 Ti 4200 chip.
Figure 17.2: A GeForce4 Ti 4200 chip powers this video card. Notice the large heat sink and fan that keep the GPU chip from over-heating.
You might have a similar video card in your PC, or something even more exotic! The point is that the video card does all the complicated work involved in rendering the 3D graphics in a game. In the old days before 3D accelerators came along (such as during the early ’90s), the main CPU was tasked with doing all of the 3D calculations. Suffice it to say, CPUs in the early ’90s were not particularly fast in the first place, let alone when required to render a 3D scene. Today, a single ATI Radeon 9700 chip is capable of more than a trillion calculations per second— many thousands of times faster than an original Intel Pentium chip.
Due to such advances in silicon technology, extraordinarily powerful graphics workstations are available in the most common new PCs that you might peruse at a local computer store—usually for less than $2,000. Such a thing was unheard of just a few years ago! Figure 17.3 shows the same Light1 program running on a PC with a GeForce4, with all seven light sources enabled.
Figure 17.3: The Light1 example program rendered with a GeForce4 with all seven light sources enabled
DarkBASIC does a great job of simplifying the complexity of programming 3D graphics with DirectX 8.1, with a large assortment of special effects and nextgeneration graphical features made possible by the latest video cards. One of the goals of this chapter is to demonstrate the difference that the video card can make in visual quality and performance because these factors are so important when it comes to 3D graphics programming. If you have an older video card, such as an ATI Rage 128, Nvidia TNT2, 3Dfx Voodoo3, or another video card that does not provide hardware transform and lighting (the increasingly hyped T&L feature), then you will likely not be able to use the advanced features available with the DirectX 8.1-based DarkBASIC Pro. However, the original DarkBASIC (often referred to as DBV1), which is based on DirectX 7.0a, will work fine with pre-T&L video cards. As a matter of fact, you can still use DarkBASIC Pro with an older video card, but some code won't run properly or at all. Therefore, in some cases I will show a sample program running on a low-end system, and then the same program running on a high-end system with the frame rate inhibitor turned off. That way, you will be able to compare raw performance to visual quality.
Now let's jump into the details and learn the basics of 3D graphics. Trust me, you will appreciate this information down the road when you start working with advanced 3D scenes and 3D objects. It's okay if you have never written a 3D program before, because this chapter will show you how to load and draw 3D objects on the screen. For now, let's start at the beginning.
What Is a Vertex?
The first question that you must ask before doing anything in 3D is: What is a vertex? It is the atom of the 3D realm, the lowest common denominator, the most basic entity of a 3D world. If you think of a 3D world as a pool of water, then a vertex is analogous to an H2O molecule. A vertex is actually a point in geometric space. Do you have any experience with geometry? In high school, the class that unifies geometry and algebra is called trigonometry. Whether or not you are interested in the subject, I can't stress enough how a little background refresher in geometry will make you a more formidable 3D programmer. As the previous chapters in this book have testified, it takes a lot to explain the basics of something that is rather complicated—like programming a game.
Now, don't let me worry you. You won't need trigonometry to write a 3D game with DarkBASIC because it was designed to make game programming as simple as possible by handling all the math in the background, so to speak. In the 3D graphics world, trigonometry describes how 3D objects can be rotated, moved, and scaled on the screen. I will explain the different ways that DarkBASIC uses trigonometry to create 3D objects throughout this chapter.
Tip |
The Math League is an awesome online resource for information related to trigonometry, geometry, and 3D math. It has a useful Web page that describes vertices and polygons at http://www.mathleague.com/help/geometry/polygons.htm. |
A vertex is a point in 3D space with X, Y, and Z coordinates.
A vertex can be described as a 3D geometric point. The 3D world is mapped around the Cartesian coordinate system. A 3D point has three components: X, Y, and Z. Three vertices make up a polygon, the basis for 3D graphics. Take a look at Figure 17.4 for an illustration of vertices.
Figure 17.4: Three vertices make up a polygon.
Because 3D graphics are based on trigonometry, 3D formulas also use the Cartesian coordinate system for drawing, moving, rotating, and scaling vertices. The Cartesian coordinate system (shown in Figure 17.5) is the basis for all 3D graphics rendering.
Figure 17.5: 3D math is based on the Cartesian coordinate system.
However, in 3D space there are three dimensions on the coordinate system, requiring an additional axis called Z (see Figure 17.6). If you have a hard time visualizing the Z axis, just think of Z as moving away from you. Hold your hand in the air in front of your face and move it away from you, and then back toward you. That is the Z axis. The motion going away from you is the positive Z axis, and moving your hand back toward you is the negative Z axis. As for Figure 17.6, imagine the X and Y axes moving back and forth along the Z axis. That is exactly what happens when you are dealing with three dimensions. The lesser two dimensions are represented "on" the third dimension in what seems like many copies of those two dimensions. On the computer screen, when you are rendering an object in 3D space, the Z axis determines how far away the object is from the camera. Although there might be an absolute origin (0,0,0) in the 3D scene, you can think of the camera as the local origin. Every object in 3D space in relation to the game's camera can be represented by distance as a Z axis value.
Figure 17.6: A 3D coordinate system with a Z axis
Do this illustration and analogy help you to visualize the Z axis and the third dimension? If you understand this, then you also should be able to visualize the fourth dimension (or 4D), which is time. I don't want to sound like a guest speaker at a physics convention (or a science fiction convention, for that matter), but time is just as important in a 3D game as the other three dimensions. Unfortunately, there is no easy way to illustrate a 4D coordinate system on paper. Table 17.1 puts the four dimensions into words.
Dimension |
Axis |
Description |
---|---|---|
First |
X |
Left and right |
Second |
Y |
Up and down |
Third |
Z |
In and out |
Fourth |
T |
Forward and backward |
Let me take the illustration with your hand one step further to explain time. Hold up your hand again to represent an object in 3D space. If you move your hand left to right, it is moving on the X axis. Move your hand up and down, and that is the Y axis. As I explained before, move your hand away from you and then back, and that is the Z axis. Now what about the T axis, representing the fourth dimension of time? While still holding your hand out in front of you (and moving it any way you want), stand up and take a step forward. Now take a step back. You have just translated your imaginary hand coordinate system into the fourth dimension.
Interested in whacking your brain even further? It's really all just a matter of perspective. Imagine where you are located in relation to your surroundings. Your body is a coordinate system. You can move left to right, up and down, in and out, and forward and backward. But what if you are walking around doing this on a train or a commercial airplane? Your imaginary coordinate system stays with you, and yet that whole coordinate system is moving in another coordinate system itself! You have just imagined how a fifth dimension might work. Of course, that is not useful for anything other than a fascinating discussion.
Vertices Are the Point
A 3D scene is nothing more than a huge collection of points, which is all the computer really sees. The video card fills in the pixels between the points, and that's about all there is to 3D rendering. When you look at the stratospheric polygon counts announced with each new video card release, the figure is only relevant when you consider that a polygon can be made up of just three points. There is no rule that there must be something between the points, although common sense would dictate as much. Video card capabilities are published on tiny triangles, if not without pixels then perhaps with as few filled pixels as necessary to call it a polygon. What is the reasoning behind this? Why would anyone want to announce a polygon fill rate that is half the fill rate of a competitor's card? Realistically, fill rates are only as useful as the game that uses them, and that is the point at which true benchmarks should be measured. There might be a video card with published polygon fill rates of ten billion triangles that can only run Jedi Knight II: Jedi Outcast at 20 FPS at the highest resolution.
The quality of a rendered scene is far more important than raw fill rate. The latest video cards support not only hardware transform and lighting, but also full-screen anti-aliasing (or FSAA). This is a technique that smoothes the jagged edges of objects on the screen, making a game look more realistic and less pixelated. Transform and lighting (which is often referred to as T&L or TnL) is one of those unfortunate computing technologies, such as MMX, that everyone wants but that few understand. The first T&L chip was invented by Nvidia and called the GeForce GPU (Graphics Processing Unit). This new naming convention was nothing short of brilliant marketing on the part of Nvidia, and it made the GeForce chip clearly stand out as the next greatest thing in computer graphics.
The GeForce name comes from "geometry force," and sounds like the term "G-force," which is familiar to pilots and flight simulator fans. But to the core, this new chip is a geometry force—the first chip of its kind to offload the mathematics required to rotate, translate, and scale points in 3D, as well as apply lighting effects to a polygon. Thus the term transform and lighting was born. In fact, modern GPUs perform so many astounding special effects that T&L is hardly the latest thing any more. Now that a base standard for graphics has arisen from the competitive conflict between ATI and Nvidia—the two chief rivals of the PC graphics industry today—the technology has reached a plateau in which astounding quality in addition to breakneck performance is to be expected. New techniques such as bumpmapping are giving normally flat polygons a real-life texture that raises the quality bar a number of levels and brings cinema-quality graphics to computer games.
The ironic thing about all this new technology is that it all comes back to the vertices—the points that make up a polygon, which makes up an object, which creates a scene. Vertices are useless unless they are connected to form lines. Three connected lines make the simplest polygon—a triangle. Although it might seem like three lines would have six points, that is only relevant if the lines are disconnected. By adding each line to the end of another line, the three lines are connected with only three points. A polygon with three vertices is called a triangle. There are many types of polygons, as described in Table 17.2.
Figure |
Polygon Name |
Number of Vertices |
---|---|---|
Triangle |
3 |
|
Quadrilateral |
4 |
|
Pentagon |
5 |
|
Hexagon |
6 |
|
Heptagon |
7 |
|
Octagon |
8 |
|
Nonagon |
9 |
|
Decagon |
10 |
Drawing a Wire-Frame Triangle
Ready for your first sample 3D program? Okay, this one is really short, but the educational value of this small program is significant when you read the paragraphs that follow the listing. For now, type this program into DarkBASIC Pro and then save it as Wireframe. Alternatively, you can load this project off the CD-ROM under the folder for this chapter. Recall that this listing and those that follow were written for DarkBASIC Pro and may require modification to run under standard DarkBASIC. You can simply load the projects off the CD-ROM for whichever version you prefer. Note that some features covered here are not available with standard DarkBASIC.
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - Wireframe Program '--------------------------------- 'set up the screen SYNC ON SYNC RATE 30 COLOR BACKDROP RGB(0,0,0) INK RGB(255,255,255),0 'create a triangle MAKE OBJECT TRIANGLE 1,0,0,0,0,10,0,10,10,0 'center triangle at the origin MOVE OBJECT LEFT 1, 5 MOVE OBJECT DOWN 1, 5 'draw the triangle as a wireframe SET OBJECT WIREFRAME 1, 1 'drag camera back away from object MOVE CAMERA -12 'wait for a keypress REPEAT SYNC UNTIL ESCAPEKEY() = 1 END
Now go ahead and run the program, and you should see a triangle like the one shown in Figure 17.7. If you look closely at the figure, it might seem a bit fuzzy at the edges. In fact, the lines are not quite distinct, particularly when you look at the output of the program in contrast to the printed figure.
Figure 17.7: The Wireframe program draws a wire-frame triangle on the screen.
Here, let me zoom in on the figure and show you a closer view of the triangle in Figure 17.8. Do you see how smooth the edges of the lines that make up this triangle look?
Figure 17.8: The zoomed-in triangle produced by the Wireframe program
Now I will zoom in even closer, this time on the upper-right corner. Figure 17.9 has been scaled by a factor of eight so you can see up close what the lines of the triangle look like. Do you see how there is a somewhat brighter central line with several levels of darker shading around each pixel of the line? That dark-gray color was supposed to be white, because the Wireframe program was given a color of RGB (255,255,255), which is pure white. However, the GeForce4 automatically antialiased the scene, producing this altered representation of the white line. Although it is possible (and in some cases desirable) to turn off anti-aliasing in the Windows Display Settings (via the Control Panel), a fully textured game world looks magnificent with this feature enabled. The only downside is that simple wire-frame polygons like this triangle will emphasize the imperfection that anti-aliasing inflicts on the geometry of a scene.
Figure 17.9: A close-up view of one corner of the triangle produced by the Wireframe program shows anti-aliasing at work.
Some games look terrific with full-screen anti-aliasing (FSAA) turned on, while others run poorly, so it is up to you to decide whether to use FSAA (if your video card supports it, that is). There are also several different FSAA modes from which to choose. Consult your video card manufacturer as well as reviews to determine which FSAA method works best on your card. In the case of my GeForce4 Ti 4200, the card used to produce the triangle shown in the Wireframe program, I chose the Quincunx Antialiasing™ mode, as shown in the display settings in Figure 17.10.
Figure 17.10: Anti-aliasing settings can drastically affect the quality and performance of your video card, so take care when choosing a high-quality mode that might produce a lower frame rate.
One interesting thing you can do with the FSAA settings is select each mode in your display settings and then run a sample program in DarkBASIC Pro (such as the TexturedCube program later in this chapter) to see for yourself how each FSAA mode affects the quality and performance of the program. Better yet, run a complete game with each mode for a more effective demonstration!
Drawing a Wire-Frame Cube
Now you'll take the wire-frame concept a step further and draw a wire-frame cube. The only difference between a wired cube and a shaded cube is a command called SET OBJECT WIREFRAME, which must be set in order to view something in a wire-frame, but the results can be very interesting, not to mention educational. Figure 17.11 shows the WiredCube program with culling turned off. Culling is the process of removing non-visible polygons from an object in which a polygon is behind another polygon in the Z axis. Compare this to Figure 17.12, which shows the same cube with culling turned on (the default), hiding the invisible polygons.
Figure 17.11: The WiredCube program with culling turned off shows all of the triangles that make up the cube.
Figure 17.12: The WiredCube program with culling turned on shows only those triangles in view of the camera.
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - WiredCube Program '--------------------------------- 'set up the screen SYNC ON SYNC RATE 30 COLOR BACKDROP RGB(0,0,0) INK RGB(255,255,255),0 'create a triangle MAKE OBJECT CUBE 1, 50 'draw the triangle as a wireframe SET OBJECT WIREFRAME 1, 1 'uncomment to show away-facing polygons 'SET OBJECT CULL 1, 0 'move the camera out for a better view POSITION CAMERA 50, 50, -60 POINT CAMERA 0, 0, 0 'wait for a keypress REPEAT SYNC UNTIL ESCAPEKEY() = 1 END
Drawing a Shaded Polygon
Wire-frame models make for an interesting discussion on 3D theory, but they are really not much to see. After all, who is writing wire-frame vector graphics games today? That sort of thing ended a couple decades ago! If you have a modern video card, it should be against the law to use your billion-operations-per-second GPU to draw wire-frame models. Therefore, I'm going to teach you how to add some color and shading to a polygon. Later, I will show you how to fully texture a polygon with a bitmap image, which is the goal of this discussion, and the way games are designed today.
A simple triangle without the SET OBJECT WIREFRAME command will result in a shaded white surface, which is rather dull. Instead of white, it is desirable to apply some other color to the surface when dealing with shaded polygons. To do so you can employ the SET OBJECT COLOR command, as the following Triangle program demonstrates. Figure 17.13 shows the output of the Triangle program, which draws and rotates a triangle on the screen. Figure 17.14 shows another random triangle on the screen, but I have added some labels to it so you can see the vertices that make up the polygon.
Figure 17.13: A triangle is made up of three vertices (and therefore three sides).
Figure 17.14: The Triangle program demonstrates the simplest 3D object that can be rendered in DarkBASIC.
The Triangle program uses two new commands for working with polygons, XROTATE OBJECT and YROTATE OBJECT. These commands are passed the object number and a value by which the relevant axis should be rotated. To rotate an object in the same direction endlessly, you can use the OBJECT ANGLE X(), OBJECT ANGLE Y(), and OBJECT ANGLE Z() commands.
Note |
At this late stage in the book, I have opted not to display the syntax for every command due to space considerations; there are hundreds of 3D commands in DarkBASIC Pro! Instead, I will simply teach by example, and you will get the hang of using these new commands simply by practice. If you would like detailed information about any command, refer to the DarkBASIC Language Reference on the CD-ROM. |
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - Triangle Program '--------------------------------- 'enable manual screen refresh SYNC ON SYNC RATE 100 'set some initial settings HIDE MOUSE COLOR BACKDROP RGB(0,40,40) RANDOMIZE TIMER() 'create a colored triangle MAKE OBJECT TRIANGLE 1,-10,-10,0,-10,10,0,10,10,0 COLOR OBJECT 1,RGB(RND(255),RND(255),RND(255)) 'move camera back away from object MOVE CAMERA -20 'main loop REPEAT 'rotate the X axis of the triangle XROTATE OBJECT 1, OBJECT ANGLE X(1) + 1 'rotate the Y axis of the triangle YROTATE OBJECT 1, OBJECT ANGLE Y(1) + 1 'update the screen SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
Drawing a Shaded Quadrilateral
A quadrilateral is a polygon with four vertices and four sides, which might not be made up of right triangles. (In other words, it might not be a perfect rectangle.) Most flat surfaces in a 3D scene are made up of triangles of varying sizes and shapes, and that is what this sample program demonstrates. The Quadrilateral program creates a shape by combining two rectangles on the same plane. The result is a two-tone quadrilateral surface, as shown in Figure 17.15.
Figure 17.15: A quadrilateral is made up of two joined triangles.
Figure 17.16 shows the vertices that make up a polygon comprised of two triangles, called a triangle list. Although this is the best way to visualize the process while learning, there is actually an optimized way to render triangles that reduces the number of vertices by having adjacent triangles simply share vertices. This is called a triangle strip.
Figure 17.16: Polygons can be divided into interconnected triangles of varying levels of complexity.
Figure 17.17 shows another random quadrilateral, but I have inserted labels showing the position of each vertex and how the two triangles share two corners, similar to the diagram in Figure 17.16.
Figure 17.17: The output of the Quadrilateral program, with labels added to describe the vertices and triangles that make up the quadrilateral
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - Quadrilateral Program '--------------------------------- 'enable manual screen refresh SYNC ON SYNC RATE 100 'set some initial settings HIDE MOUSE COLOR BACKDROP RGB(0,40,40) RANDOMIZE TIMER() 'create a colored triangle MAKE OBJECT TRIANGLE 1,-10,-10,0,-10,10,0,10,10,0 COLOR OBJECT 1,RGB(RND(255),RND(255),RND(255)) MAKE OBJECT TRIANGLE 2,-10,-10,0,10,10,0,10,-10,0 COLOR OBJECT 2,RGB(RND(255),RND(255),RND(255)) 'move camera back away from object MOVE CAMERA -20 'main loop REPEAT 'rotate the X axis of the triangle XROTATE OBJECT 1, OBJECT ANGLE X(1) + 1 RXOTATE OBJECT 2, OBJECT ANGLE X(2) + 1 'rotate the Y axis of the triangle YROTATE OBJECT 1, OBJECT ANGLE Y(1) + 1 YROTATE OBJECT 2, OBJECT ANGLE Y(2) + 1 'update the screen SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
Drawing a Rectangle
DarkBASIC Pro has a MAKE OBJECT PLAIN command that creates a rectangle (a quadrilateral with 90-degree angles) without joining two triangles (as you did previously). Figure 17.18 shows the output of the Rectangle program, in which the rectangle is rotating in 3D space. I have also included a picture of the rectangle as a wire-frame by using the SET OBJECT WIREFRAME command, which you saw earlier. Figure 17.19 demonstrates how DarkBASIC Pro builds a stock "surface" out of triangles.
Figure 17.18: A simple plain object is made up of two right triangles and can be a root limb for a more complex object.
Figure 17.19: Setting the plain object to be drawn in wire-frame reveals that the object is actually made up of two triangles.
Note |
In standard DarkBASIC, you use the SET OBJECT command to turn on wire-frame. |
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - Rectangle Program '--------------------------------- 'enable manual screen refresh SYNC ON SYNC RATE 100 'set some initial settings HIDE MOUSE COLOR BACKDROP RGB(0,40,40) RANDOMIZE TIMER() 'create a colored triangle MAKE OBJECT PLAIN 1, RND(10) + 1, RND(10) + 1 COLOR OBJECT 1,RGB(RND(255),RND(255),RND(255)) 'uncomment to draw in wireframe 'SET OBJECT WIREFRAME 1, 1 'main loop REPEAT 'rotate the X axis of the triangle XROTATE OBJECT 1, OBJECT ANGLE X(1) - 0.75 'rotate the Y axis of the triangle YROTATE OBJECT 1, OBJECT ANGLE Y(1) + 1 'update the screen SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
That was quite a fast-paced first half of the chapter, wouldn't you agree? It has been fun, though, to learn all about wire-frame and solid objects and how DarkBASIC Pro creates objects and draws them. Now I would like to up the ante, so to speak, and give you more 3D graphics programming power by talking about some of the more powerful commands in DarkBASIC Pro.
Note |
Although this chapter is geared for DarkBASIC Pro, I have not forgotten about DBV1 users. The source code listings might be slightly different, but you can find DBV1 versions of the sample programs in this chapter on the CD-ROM. I am focusing on DBPro to provide as much up-todate information as possible. |
You have already seen some of the stock objects in DarkBASIC Pro, such as the triangle, plain, and cube. Now I would like to cover all of the stock objects and then provide you with a demonstration program to show you how to use them.
The MAKE OBJECT TRIANGLE Command
I'll start with the easiest object, just for reference. This command is used to create a simple triangle in whatever shape you prefer. The syntax for this command is MAKE OBJECT TRIANGLE Object Number, X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3.
There are so many parameters for this command because a triangle is the polygon by which all other 3D objects are constructed, and it requires the most flexibility. There are many different shapes and sizes possible with a triangle, not just the right-triangle variety with a 90-degree angle. With enough creativity, you can create any 3D object that you can imagine entirely out of triangles. This object is the building block of all others.
The MAKE OBJECT PLAIN Command
A plain is a quadrilateral (or rectangle) with two sets of equal sides and four right angles that equal 360 degrees in total. To create a rectangle, simply pass the width and height to the MAKE OBJECT PLAIN command. The syntax is MAKE OBJECT PLAIN Object Number, Width, Height.
The MAKE OBJECT CUBE Command
The MAKE OBJECT CUBE command constructs a cube that is comprised of six sides (and therefore 12 triangles). Due to the number of polygons involved, a cube has eight vertices—one for each corner. The important thing to remember is that this command constructs a cube of equal dimensions on all sides. (In contrast, the MAKE OBJECT BOX command builds an object with a different height, width, and depth.) The syntax for this command is MAKE OBJECT CUBE Object Number, Size.
The MAKE OBJECT BOX Command
The MAKE OBJECT BOX command creates a 3D object that is similar to a cube, but that might have different dimensions for the width, height, and depth. The result is akin to a 3D rectangle. (In contrast, the MAKE OBJECT CUBE command builds an object with the same height, width, and depth.) The format for this command is MAKE OBJECT BOX Object Number, Width, Height, Depth.
The MAKE OBJECT CYLINDER Command
To create a cylinder object, which you might use as a telephone pole or a drinking cup, use the MAKE OBJECT CYLINDER command. The syntax is MAKE OBJECT CYLINDER Object Number, Size.
The MAKE OBJECT CONE Command
The MAKE OBJECT CONE command creates a cone-shaped object that resembles an ice cream cone. The syntax is MAKE OBJECT CONE Object Number, Size.
The MAKE OBJECT SPHERE Command
A sphere is a complex 3D object consisting of many triangles in the proper orientation to give a spherical appearance (which you might use, for example, to render a planet in space). You can create a sphere using the MAKE OBJECT SPHERE command.
The syntax is MAKE OBJECT SPHERE Object Number, Size, Rows, Columns. You can use the Rows and Columns parameters for this command to provide DarkBASIC with more detail on the number of polygons in the sphere.
When you have created a stock 3D object using one of the commands covered earlier, you can then instruct DarkBASIC to manipulate and draw the object on the screen. Transforming is a process by which something changes orientation, position, or scale. The precise terms for this are rotation, translation, and scaling, respectively. Rotation refers to the angle by which an object is displayed on each of the three axes (X, Y, and Z). Translation is the process of moving an object in 3D space using the three axes. Scaling involves changing the size of an object.
Possibly the most important thing to consider when you are working in 3D is the viewpoint, or the position of the so-called "camera." Although there is no physical (or logical) camera in the 3D scene, it is a practical analogy to describe the process of setting the viewpoint (and viewport) of the scene. The camera can be moved and rotated independently of any 3D objects in the scene, which can be quite useful. Often the functioning of the camera will make or break a game, despite the amount of work that has gone into it. If the camera is unwieldy, moves too often, or prevents the player from seeing what is going on in the game (such as the infamous problem with the player walking "toward" the camera and thus being unable to see anything), it will simply ruin a game. You must take great care and pay attention to the code that positions the camera in a scene. Often the best policy is just to leave the camera at a bird's-eye view and let the game run normally below the camera. (This might be useful in a strategy war game, for example.)
Although scaling is also a transformation, I don't use it very often. Scaling might be useful if you wanted to use a common stock size for all enemies in a game, and you wanted to enlarge some models for boss characters. You might also have a stock size and want to reduce models; for instance, to render a flock of birds where the model size is rather large by default.
The MakeObjects program demonstrates how to create several stock 3D objects and then rotate and move those objects around in a circular formation. This program shows how to transform objects (remember: rotation, translation, and scaling) and position the camera. Figure 17.20 shows the output of the MakeObjects program running in normal mode, and Figure 17.21 shows the program running at the fastest possible speed (which is useful for benchmarking the game loop).
Figure 17.20: The MakeObjects program draws five stock 3D objects rotating in a circle on the screen.
Figure 17.21: The MakeObjects program, running without a frame rate limit
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - MakeObjects Program '--------------------------------- 'create some arrays DIM angle(5) DIM posx(5) DIM posz(5) 'initialize the program SYNC ON SYNC RATE 100 HIDE MOUSE COLOR BACKDROP RGB(0,40,40) 'create a cube MAKE OBJECT CUBE 1,50 COLOR OBJECT 1, rgb(255,0,0) 'create a cone MAKE OBJECT CONE 2,50 COLOR OBJECT 2, RGB(0,255,0) 'create a sphere MAKE OBJECT SPHERE 3,50 COLOR OBJECT 3, RGB(0,0,255) 'create a box MAKE OBJECT BOX 4, 50, 25, 25 COLOR OBJECT 4, RGB(255,255,0) 'create a cylinder MAKE OBJECT CYLINDER 5, 50 COLOR OBJECT 5, RGB(0,255,255) 'reposition the camera to get the whole view PITCH CAMERA DOWN 25 MOVE CAMERA -200 'set initial angles for each object angle(1) = 0 angle(2) = 72 angle(3) = 144 angle(4) = 216 angle(5) = 288 radius = 150 'start the loop REPEAT 'move the objects in a circle FOR n = 1 TO 5 'calculate X position using cosine posx(n) = COS(angle(n)) * radius 'calculate Y position using sine posz(n) = SIN(angle(n)) * radius 'increment the angle angle(n) = angle(n) + 1 'move and rotate the object POSITION OBJECT n, posx(n), 0, posz(n) XROTATE OBJECT n, OBJECT ANGLE X(n) + 1 YROTATE OBJECT n, OBJECT ANGLE Y(n) + 0.5 next n 'display frame rate and update the screen TEXT SCREEN WIDTH()-80, SCREEN HEIGHT()-30, "FPS: " + STR$(SCREEN FPS()) SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
For many years, video games used shaded polygons to build their 3D worlds; before that, they used wire-frame graphics. (Remember Battlezone?) What truly makes a game realistic, though, is the use of textures. Texturing is a process by which a bitmap image is pasted onto a polygon. That is the gist of it in simple terms. However, the process of mapping pixels to a polygon and even wrapping a texture around an entire 3D object is quite complicated. Add to this the real-world need for extreme speed in a texture mapper, and there can be some serious problems in a software-only solution. That is why all modern video cards paste textures to polygons in the hardware—the silicon 3D chip itself does the texture mapping. As you have probably noticed while playing a recent game, hardware 3D is impressive. Before hardware texture mapping was brought to the PC, software texture mapping code relied on a fast processor to work.
Half-Life featured a software texture mapper within its 3D engine that was quite sophisticated (which was no surprise, given that it was based on Quake II). However, the most impressive software-texturing algorithm in the world has no hope of competing with a hardware renderer. I remember the first time I saw a game running on a 3D-accelerated PC. It was the original Quake, running an OpenGL driver on a 3Dfx Voodoo card. The difference between software-rendered Quake and hardware-rendered Quake was astounding! Suffice it to say, it is a given today that all 3D games must be textured and hardware accelerated. Software-only solutions don't have a hope of competing (nor should anyone argue any longer against a game that is dependent on 3D hardware).
Loading a Texture
DarkBASIC makes texturing very easy. In fact, just slap yourself right now for not skipping to this part of the chapter. No wait, just kidding! There is true educational value to be had from going through the process. So many programmers today take the rendering pipeline for granted without considering exactly how much work is involved in drawing a complex textured 3D scene. I suppose after writing some 3D code in DarkBASIC, you will start to take it for granted too. Such is the nature of computers. Ah, well. Let me show you how to load a texture.
Basically, a texture is just a bitmap file. Why are they called textures then, rather than bitmaps? That's a funny question. Actually, doesn't "texture" have something to do with how things feel? When I think of the word texture, I am reminded of what the bark on a tree feels like, because that is a significant feeling. I also think of a brick wall as being very textured. Wait, that is bump-mapping. You know, computer science people are weird, okay? Please stop asking silly questions and just take my word for it that a texture is a bitmap.
You use the LOAD IMAGE command to load a texture. The format is LOAD IMAGE Filename, Image Number.
Note |
Actually, a texture could be a JPG, PNG, BMP, TGA, DDS, or DIB file! Just thought I'd throw that little tidbit in here to confuse you a little more. |
Applying a Texture to a Polygon
After you load a texture onto an image, you can apply that texture to a polygon using the TEXTURE OBJECT command. This command is quite easy to use, despite the complexity behind it. The format of the command is TEXTURE OBJECT Object Number, Image Number. Simply pass the object number and image number to the command, and the bitmap image stored in that image number will be textured onto the passed object (which can be a single polygon, a stock 3D object, or an object that you have constructed).
The TexturedCube Program
Texturing a 3D object is really easy to do, and I would like to provide you with a sample program to prove it. The TexturedCube program creates several stock objects, including a rotating cube in the center of the other objects with a texture applied to it. Figure 17.22 shows what the texture looks like. Hey, it's the DarkBASIC logo!
Figure 17.22: The DarkBASIC logo is used to texture a stock 3D object in the TexturedCube program.
The TexturedCube program is similar to the MakeObjects program. I have removed two of the objects and placed the new cube in the center, rotating opposite of the motion of the other objects. Figure 17.23 shows the program running at normal speed, and Figure 17.24 shows the program running at top speed.
Figure 17.23: The TexturedCube program draws a textured cube with several colored objects rotating around it.
Figure 17.24: Running the TexturedCube program without a frame rate limiter results in a very high frame rate.
You can type this program into DarkBASIC Pro or load the project from the CD-ROM. If you are using DarkBASIC 1.0, there is a separate version of this program available.
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - TexturedCube Program '--------------------------------- 'declare some arrays DIM angle(4) DIM posx(4) DIM posz(4) 'initialize program SYNC ON SYNC RATE 100 HIDE MOUSE COLOR BACKDROP RGB(0,60,60) 'create a light source SET AMBIENT LIGHT 0 MAKE LIGHT 1 MAKE OBJECT SPHERE 9, 10 COLOR OBJECT 9, RGB(255,255,255) 'create the central textured cube MAKE OBJECT CUBE 1, 75 LOAD IMAGE "pyramid.bmp",1 TEXTURE OBJECT 1, 1 'create a cone MAKE OBJECT CONE 2, 50 COLOR OBJECT 2, RGB(0,255,0) 'create a sphere MAKE OBJECT SPHERE 3, 50 COLOR OBJECT 3, RGB(0,0,255) 'create a cube MAKE OBJECT CUBE 4, 50 COLOR OBJECT 4, RGB(255,0,0) 'position the camera PITCH CAMERA DOWN 25 MOVE CAMERA -200 'set the starting position of each object angle(2) = 0 angle(3) = 135 angle(4) = 270 'set the radius of the rotation circle radius = 150 'start the loop REPEAT 'move the objects in a circle FOR n = 2 TO 4 'set the X position with cosine posx(n) = COS(angle(n)) * radius 'set the Y position wiht sine posz(n) = SIN(angle(n)) * radius 'increment the angle angle(n) = angle(n) + 1 'move the object POSITION OBJECT n, posx(n), 0, posz(n) NEXT n 'rotate the objects individually YROTATE OBJECT 1, OBJECT ANGLE Y(1) + 0.5 YROTATE OBJECT 2, OBJECT ANGLE Y(2) + 1 XROTATE OBJECT 3, OBJECT ANGLE X(3) + 1 XROTATE OBJECT 4, OBJECT ANGLE X(4) + 1 'move the light source according to mouse position POSITION LIGHT 1, MOUSEX() - 320, 0, 240 - MOUSEY() POSITION OBJECT 9, MOUSEX() - 320, 0, 240 - MOUSEY() 'display some text messages and refresh the screen TEXT 5, 5, "Use your mouse to move the light source." TEXT SCREEN WIDTH()-100,SCREEN HEIGHT()-30,"FPS: "+STR$(SCREEN FPS()) SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
The difference between a simple 3D game and a complex one is often the amount of varied lighting in the game. As one of the most complicated themes in 3D graphics programming, lighting is such a difficult task that many games feature pre-lit scenes to simulate the effects of light. For example, a streetlight might seem to emit a directional light on the ground when the texture of the ground below the light simply has been pre-rendered with the appearance of a light shining on it. This can result in a realistic scene that avoids the pitfalls involved in programming real-time lighting effects. Even when you are using a library that might include support for hardware lights supported in the video card, such as OpenGL or Direct3D, you must still design your game engine in such a way that textures and objects in the game are set up to support hardware lights. DarkBASIC Pro has support for many different types of real-time lights that affect the characters and surroundings in a game. The built-in lighting effects in DarkBASIC are so easy to set up and use that you will be surprised by the results.
Ambient light is the uniform level of lighting throughout an entire scene. If you are standing in a room that is lighted by fluorescent light bulbs, such as in an office building, the level of light might be viewed as ambient, and there would be a certain ambient level in the room. If you stand outside on a bright sunny day, though, ambient light will be significantly different from the light level in an office building. The sun is a large bright-point light source. The sun emits so much light (and heat) that it might seem to be ambient, but it is not. For one thing, sunlight creates shadows on the ground under trees, buildings, people, or anything else. Ambient light by nature does not create shadows. You might think of ambient light as a filler—somewhat light fog that is not emitted from a specific source. Some people, myself included, have a hard time visualizing ambient light. It is easy to understand a directional light, a point light, or a spot light, but ambient light is an abstract concept. When 3D objects are rendered in a scene with ambient light, all faces are lit equally without shadow.
Setting the Ambient Light Level
You can set the level of ambient light using the SET AMBIENT LIGHT command. The format is SET AMBIENT LIGHT Percentage Value.
This command expects a single parameter, 0 to 100, indicating the value of ambient light to apply to the scene as a percentage. Setting ambient light to 100 results in no shadows, while a value of 0 is useful when you want to use directional lights in the scene (which I'll discuss further in the upcoming "Directional Lights" section).
Setting the Ambient Color
In addition to changing the level of ambient light, you also have the ability to change the color of the ambient light to any RGB color value using the COLOR AMBIENT LIGHT command. The syntax is COLOR AMBIENT LIGHT Color Value.
The AmbientLight Program
The best way to demonstrate how to use ambient light is by showing you a sample program. The AmbientLight program draws a textured cube in the center of the screen, rotates the cube, and oscillates the light level and the color of the ambient light. Figure 17.25 shows the AmbientLight program while near the peak of full ambient color, and Figure 17.26 shows the cube at a low ambient level. At the same time, varying degrees of RGB color are being changed while the program is running, producing some interesting texture colors.
Figure 17.25: The AmbientLight program demonstrates varying levels of ambient light in a scene.
Figure 17.26: A low ambient light setting in the AmbientLight program results in dark, shadowed textures.
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - AmbientLight Program '--------------------------------- 'create some variables Ambient = 0 Direction = 1 Red = 0 Green = 0 Blue = 0 'initialize program SYNC ON SYNC RATE 60 HIDE MOUSE COLOR BACKDROP RGB(0,60,60) 'create a textured cube MAKE OBJECT CUBE 1, 75 LOAD IMAGE "cube.bmp",1 TEXTURE OBJECT 1, 1 POSITION OBJECT 1, 0, -20, -120 'position the camera PITCH CAMERA DOWN 25 MOVE CAMERA -30 'start the loop REPEAT 'rotate the objects individually YROTATE OBJECT 1, OBJECT ANGLE Y(1) + 1 'update ambient variable Ambient = Ambient + Direction IF Ambient > 100 Ambient = 100 Direction = -1 ENDIF IF Ambient < 0 Ambient = 0 Direction = 1 ENDIF 'set the ambient light SET AMBIENT LIGHT Ambient 'update the ambient color variables IF Red > 254 IF Green > 254 IF Blue > 254 Red = 0 Green = 0 Blue = 0 ELSE Blue = Blue + 1 ENDIF ELSE Green = Green + 1 ENDIF ELSE Red = Red + 1 ENDIF 'set the ambient color COLOR AMBIENT LIGHT RGB(Red,Green,Blue) 'display the ambient variable TEXT 10, 10, "Ambient level: " + STR$(Ambient) TEXT 10, 20, "Color: "+STR$(Red)+","+STR$(Green)+","+STR$(Blue) 'update the screen SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
Ambient light will suffice for almost any game that you plan to write. Most of the time, you need nothing more than the default ambient light level. However, you might want to add some pizzazz to your games. In addition to ambient light, DarkBASIC Pro provides three special-case lights that you can use in your programs.
Directional lights illuminate a scene in a conical shape that points to a specific location where the light source is located. A directional light is similar to a spotlight, but it does not have a changeable angle of effect. Probably the most obvious use for a directional light would be for a streetlamp or headlights on a car.
Creating a Directional Light
You can use the SET DIRECTIONAL LIGHT command to turn an existing light into a directional light. The syntax for this command is SET DIRECTIONAL LIGHT Light Number, DirX, DirY, DirZ. The DirX, DirY, and DirZ parameters define the direction that the light is pointing.
The DirectionalLight Program
I have written a program called DirectionalLight to demonstrate how to use directional lights. This program revolves a small sphere (representing the light source) in a circle around a larger sphere, constantly shining the directional light at the larger sphere. The result is a bright surface on the larger sphere that moves according to the position of the light source, as shown in Figure 17.27.
Figure 17.27: The DirectionalLight program demonstrates one of the many ways you can use directional lights.
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - DirectionalLight Program '--------------------------------- 'create variables posx = 0 posz = 0 angle = 0 radius = 200 'initialize program SYNC ON SYNC RATE 60 HIDE MOUSE COLOR BACKDROP RGB(0,40,40) 'create the floor MAKE MATRIX 1, 1000, 1000, 10, 10 LOAD IMAGE "floor.bmp", 2 POSITION MATRIX 1, -500, -100, -500 PREPARE MATRIX TEXTURE 1, 2, 1, 1 UPDATE MATRIX 1 'create the large sphere MAKE OBJECT SPHERE 1, 100 COLOR OBJECT 1, RGB(245,200,0) 'create the small sphere MAKE OBJECT SPHERE 2, 20 COLOR OBJECT 2, RGB(255,0,255) POSITION OBJECT 2, 200, 0, 200 'create the directional light MAKE LIGHT 1 SET DIRECTIONAL LIGHT 1, 0, 0, 0 'COLOR LIGHT 1, RGB(255,0,0) 'set up the camera POSITION CAMERA 0, 200, -400 POINT CAMERA 0, 0, 0 'start the loop REPEAT 'move the small sphere and light source posx = COS(angle) * radius posz = SIN(angle) * radius angle = angle + 1 POSITION OBJECT 2, posx + 20, 0, posz + 20 POSITION LIGHT 1, posx, 0, posz POINT LIGHT 1, 0, 0, 0 'update the screen SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
Point lights are fascinating because they emit light in all directions and have a limited range, which allows for local lighting effects. One possible use for a point light is a projectile fired from a weapon, such as a plasma bolt fired from a gun in a futuristic tank battle or first-person shooter. Having a projectile that lights up objects that it passes is a particularly impressive special effect in a game. Keep in mind, however, that DarkBASIC has only a limited supply of lights available, and some video cards might not support hardware lights (which will slow down the program, because lighting effects are a serious drag on the processor).
Creating Point Lights
You can set an existing light to a point light by using the SET POINT LIGHT command. The format is SET POINT LIGHT Light Number, PosX, PosY, PosZ. The PosX, PosY, and PosZ parameters define the position of the light.
The PointLight Program
The PointLight program demonstrates how to use point lights. I was really happy with the way this program turned out because it surprised me the first time I ran it! The scene was supposed to be lit already, but I inadvertently set the ambient light level to a very low value. The result is that the point light circling the object in the center of the screen actually lights the surface of the object, which is a yellow sphere. The result is very interesting, as you can see in Figure 17.28.
Figure 17.28: The PointLight program revolves a small point light around a sphere with low ambient light.
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - PointLight Program '--------------------------------- 'create some variables posx = 0 posz = 0 angle = 0 radius = 120 'initialize program SYNC ON SYNC RATE 60 HIDE MOUSE COLOR BACKDROP RGB(0,0,0) 'set the ambient light SET AMBIENT LIGHT 5 'create a point light SET POINT LIGHT 0, 0, 0, 0 COLOR LIGHT 0, RGB(245,200,0) SET LIGHT RANGE 0, 200 'create the central sphere MAKE OBJECT SPHERE 1, 100 COLOR OBJECT 1, RGB(245,200,0) 'set up the camera POSITION CAMERA 0, 50, -100 POINT CAMERA 0, 0, 0 'start the loop REPEAT 'orbit the point light around the sphere posx = COS(angle) * radius posz = SIN(angle) * radius angle = angle + 2 POSITION LIGHT 0, posx, 0, posz 'rotate the central sphere YROTATE OBJECT 1, OBJECT ANGLE Y(1) + 1 'update the screen SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
Spot lights are my favorite kind of light in DarkBASIC because color can be applied to a spot light with attractive results. A spot light is similar to a directional light in that there is a conical-shaped light source, but spot lights have the added benefit of having internal and external light cone angles that you can set. The inner cone determines how large the spot light will be when it strikes a surface, and the outer cone determines how much residual light will pour out of the inner cone onto an object in a faded manner.
Creating Spot Lights
You can set an existing light to a spot light by using the SET SPOT LIGHT command. The format is SET SPOT LIGHT Light Number, Inner Angle, Outer Angle.
The SpotLight Program
The SpotLight program is my favorite among the light source demos because it works so well and the result is fantastic (see Figure 17.29). By applying a different color to each of the two light sources in this program and shining them both at a textured cube, the result is very colorful and shows the great effects possible with spot lights. The only thing I might have done differently is to have the light sources move instead of the camera, but the result would have been attractive either way.
Figure 17.29: The SpotLight program demonstrates how to use spot lights.
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - SpotLight Program '--------------------------------- posx = 0 posz = 0 angle = 0 height = 150 radius = 400 'initialize program SYNC ON SYNC RATE 60 HIDE MOUSE COLOR BACKDROP RGB(0,60,60) 'create a textured cube MAKE OBJECT CUBE 1, 100 LOAD IMAGE "cube.bmp",1 TEXTURE OBJECT 1, 1 'create the "floor" MAKE MATRIX 1, 1000, 1000, 10, 10 LOAD IMAGE "floor.bmp", 2 POSITION MATRIX 1, -500, -100, -500 PREPARE MATRIX TEXTURE 1, 2, 1, 1 UPDATE MATRIX 1 'marker object for green light MAKE OBJECT SPHERE 10, 10 COLOR OBJECT 10, RGB(0,0,255) POSITION OBJECT 10, 200, 0, 200 'create a green spot light MAKE LIGHT 1 SET SPOT LIGHT 1, 30, 10 COLOR LIGHT 1, RGB(0,0,255) POSITION LIGHT 1, 200, 0, 200 POINT LIGHT 1, 0, 0, 0 'marker object for red light MAKE OBJECT SPHERE 11, 10 COLOR OBJECT 11, RGB(255,255,0) POSITION OBJECT 11, -200, 0, -200 'create a red spot light MAKE LIGHT 2 SET SPOT LIGHT 2, 30, 10 COLOR LIGHT 2, RGB(255,255,0) POSITION LIGHT 2, -200, 0, -200 POINT LIGHT 2, 0, 0, 0 'start the loop REPEAT 'rotate the camera around the scene posx = COS(angle) * radius posz = SIN(angle) * radius angle = angle + 1 POSITION CAMERA n, posx, height, posz POINT CAMERA 0, 0, 0 'update the screen SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
Earlier in this chapter, you saw some possible uses for the camera, such as moving it around the perimeter of a scene instead of moving individual objects in the scene—a very useful technique, particularly when you just want to show off a 3D model that you have loaded. The camera is the most important aspect of the 3D engine, and DarkBASIC is no exception, although support for multiple cameras is a fascinating idea. The concept of a "camera" in 3D graphics is abstract. As far as DarkBASIC knows, there is a 3D world and there really is no computer screen or monitor. The 3D objects, lights, and cameras move around and do their thing regardless of whether or not someone is watching. In this sense, the word "watching" refers to not only the player—you, the programmer—but also to a camera. By default, DarkBASIC sets up camera 0 as the standard camera and displays the camera's view on the screen. However, you can just as easily create another camera else where in the scene and set the screen to display what that camera is viewing! That is what I mean when I state that cameras are abstract views in 3D space. Often the impression is that a 3D scene is rendered on the screen using some sort of ray-tracing algorithm, and that impression somehow links the 3D objects to the screen as if they are glued in place. In fact, those objects are totally independent of the screen.
The 3D chip in your video card optimizes the mathematics involved in rendering these objects. The resulting impression of modern 3D graphics is that the scene can be rendered regardless of who is watching.
If there is no camera in place to display a scene on the screen, then the GPU will spend no time processing the scene. Although the CPU might continue to update the position of objects in the scene, rendering is by far the most intensive operation. This simply does not occur if there are no virtual cameras in place.
Note |
All of the camera commands covered in this section are demonstrated in the CameraView program at the end of the chapter. Not all commands are represented here, only those that I deemed practical. For a complete reference to all of the camera commands, please refer to the DarkBASIC Language Reference on the CD. |
DarkBASIC provides a default camera (0) that is set slightly back (in the Z axis) and focused on 0,0,0. You will almost always need to move the default camera out a certain distance to see the objects in your scene, depending on their size. If you are writing a game such as a third-person shooter, you will probably want to set the camera just above and behind the main object in the game. You can use the default camera or create additional cameras using the MAKE CAMERA command. The syntax is MAKE CAMERA Camera Number.
After you create a new camera, you can position and point it to a new location in the scene, and then easily switch from one camera to another by simply calling the SET CURRENT CAMERA command, which immediately sets the view to that seen by the specified camera. The syntax of this command is SET CURRENT CAMERA Camera Number.
If you would rather display the feed of a particular camera right on the screen, you can do just that using the SET CAMERA VIEW command, which sets up a portion of the screen as an overlay video. The syntax is SET CAMERA VIEW Camera Number, Left, Top, Right, Bottom.
It is your job to manage the camera's position. Although there is an AUTOCAM ON command, it simply focuses on the last 3D object that was created or loaded and does not follow the correct field of view. To set a camera's position in 3D space, you can use the POSITION CAMERA command in the syntax POSITION CAMERA Camera Number, X, Y, Z.
Any time you need to know the exact position of a camera or you need to move the camera based on its current position (for instance, to move the camera using absolute coordinates), you can use one of the following commands:
After positioning, the next most important factor to consider in camera management is the direction the camera is pointing. This determines what the camera is looking at and what is displayed on the screen (or in a window, as you will see later). To set a camera's direction, you can use the POINT CAMERA command, which is almost always necessary after moving the camera to a new location. The syntax is POINT CAMERA Camera Number, X, Y, Z.
Surprisingly, those are all the commands you need to effectively manage one or more cameras in a game. Again, if you would like to discover the more advanced camera-handling commands available, see the DarkBASIC Language Reference on the CD.
There are many more commands in DarkBASIC for manipulating and reading the status of the cameras in your programs, but I have covered only those commands that are immediately useful. To demonstrate how these commands work, I have written a program called CameraView. This program creates five cameras and positions them at various points in the scene, even moving the cameras in relation to objects. The top portion of the screen features five mini-overlays that show the view of each camera, in addition to the default camera (which fills the screen by default). See Figure 17.30 to get an idea what the output of the program looks like.
Figure 17.30: The CameraView program demonstrates how to position and orient cameras in a scene and then display the output from each camera on the screen.
Note |
For a more in-depth overview of all the camera commands, please refer to the DarkBASIC Language Reference on the CD. |
As has been the case throughout the book, I am taking liberty with the texture files that are referenced in this program and assuming that they exist. You can copy the texture files (floor.bmp and cube.bmp) to the program folder where you have saved the listing for CameraView, or you can create your own textures. The standard size for a texture is 512 pixels squared.
'--------------------------------- 'Beginner's Guide To DarkBASIC Game Programming 'Copyright (C)2002 Jonathan S. Harbour and Joshua R. Smith 'Chapter 17 - CameraView Program '--------------------------------- 'create some variables posx = 0 posz = 0 angle = 0 height = 150 radius = 300 screenw = SCREEN WIDTH() screenh = SCREEN HEIGHT() 'initialize program SYNC ON SYNC RATE 100 HIDE MOUSE COLOR BACKDROP RGB(0,60,60) 'create the "floor" MAKE MATRIX 1, 1000, 1000, 10, 9 LOAD IMAGE "floor.bmp", 2 POSITION MATRIX 1, -500, -100, -500 PREPARE MATRIX TEXTURE 1, 2, 1, 1 UPDATE MATRIX 1 'create a textured cube MAKE OBJECT CUBE 1, 100 LOAD IMAGE "cube.bmp",1 TEXTURE OBJECT 1, 1 'create the moving sphere MAKE OBJECT SPHERE 2, 50 COLOR OBJECT 2, RGB(245, 0, 200) 'create and set up the cameras MAKE CAMERA 1 SET CAMERA VIEW 1, 10, 10, 110, 110 MAKE CAMERA 2 SET CAMERA VIEW 2, screenw-110, 10, screenw-10, 110 MAKE CAMERA 3 SET CAMERA VIEW 3, 140, 10, 240, 110 MAKE CAMERA 4 POSITION CAMERA 4, 0, 600, 0 POINT CAMERA 4, 0, 0, 0 SET CAMERA VIEW 4, screenw-240, 10, screenw-140, 110 MAKE CAMERA 5 POSITION CAMERA 5, 900, 400, -900 POINT CAMERA 5, 0, 0, 0 SET CAMERA VIEW 5, screenw/2-50, 10, screenw/2+50, 110 POSITION CAMERA 0, 0, 100, -400 POINT CAMERA 0, 0, 0, 0 'start the loop REPEAT 'rotate the cube and point camera 2 at it YROTATE OBJECT 1, OBJECT ANGLE Y(1) + 1 SET CAMERA TO FOLLOW 2, 0, 0, 0, 0, 200, 30, 1.0, 0 'rotate a point around the scene posx = COS(angle) * radius posz = SIN(angle) * radius angle = angle + 1 'move camera 1 POSITION CAMERA 1, posx, height, posz POINT CAMERA 1, 0, 0, 0 'move the sphere POSITION OBJECT 2, -1*posx, COS(angle)*posz/2, -1*posz+200 'move camera 3 X = OBJECT POSITION X(2) Y = OBJECT POSITION Y(2) Z = OBJECT POSITION Z(2) SET CAMERA TO FOLLOW 3, X, Y, Z, 0, 100, Y, 1.0, 0 'display frame rate and update the screen TEXT screenw-70, screenh-20, "FPS " + STR$(SCREEN FPS()) SYNC UNTIL ESCAPEKEY() = 1 'clean up SHOW MOUSE END
Thus ends one of the longest and most complicated (but surely the most exciting!) chapters of the book thus far! I hope you have enjoyed this chapter, because 3D programming is where the action is, and this is what you should strive to master to write your own cutting-edge games. 2D games are fun and may always be around, but 3D is the place to be. To be honest, I personally find 3D programming just as easy as (if not easier than) 2D programming. It just seems that DarkBASIC handles all the details and makes it so much fun! It's wonderful to be able to write a 3D demo or even a complete game without having to learn matrix math or trigonometry. You can move or rotate any object, light source, or camera using only a single command. Now that's real programming power!
The chapter quiz will help you retain the information that was covered in this chapter, as well as give you an idea about how well you're doing at understanding the subjects. You will find the answers for this quiz in Appendix A, "Answers to the Chapter Quizzes."
1. |
How many vertices (or angles) are required to make up a triangle?
|
|
2. |
Which coordinate system is used to calculate the position of points in a 3D program?
|
|
3. |
What is the name of the process that smoothes jagged edges in a 3D scene?
|
|
4. |
Which command creates a 360-degree quadrilateral?
|
|
5. |
Which command sets the level of ambient light in the 3D scene to a uniform amount?
|
|
6. |
Which type of light source produces a colored light region in the shape of a sphere?
|
|
7. |
Which type of light source lets you set an inner and outer angle of effect?
|
|
8. |
How many sides do you need to make a cube?
|
|
9. |
Which command creates an overlay window on the screen for a camera?
|
|
10. |
Which version of DirectX does DarkBASIC Professional directly support?
|
Answers
1. |
B |
2. |
B |
3. |
D |
4. |
A |
5. |
C |
6. |
B |
7. |
D |
8. |
C |
9. |
C |
10. |
C |
Part I - The Basics of Computer Programming
Part II - Game Fundamentals Graphics, Sound, Input Devices, and File Access
Part III - Advanced Topics 3D Graphics and Multiplayer Programming
Epilogue
Part IV - Appendixes