////////////////////////////////////////////////////////////////////////////// / A BASIC GUIDE TO A BASIC LANGUAGE / / DOCUMENT 1: 3D PROGRAMMING / / WRITTEN BY CHRONOMASTER / ////////////////////////////////////////////////////////////////////////////// Disclaimer ---------- If this thing messes you up don't come complaining to me. All I can tell you is that this has been tested numerous times with success and that none of the commands used to make this 3D Engine are harmful to your computer. I ain't gonna bother you to give me credit for using this tutorial, however I would like you to e-mail me if you find it helpful. My e-mail address is GenerationX2@msn.com. There really is no risk at all in making this but like every programmer should know: Risk is part of the game. ------------------------------------------------------------------------------ Introduction To 3D Worlds ------------------------- The concept of 3D Programming to beginning programmers is quite frankally impossible. The reason's obvious, you only have 2D screen and no commands that are included with QBASIC runtime library have three dimensions, only two. So of course it would seem impossible to draw a 3D coordinate on a 2D screen, infact when you think about it, it is impossible. Commands like PSET, LINE, CIRCLE... are all limited to X,Y axis'. There's nothing we can do about that, and there's no reason why we should. The answer to 3D Programming is to take a 3D Object and turn it into a 2D Object. Confused all ready? Well simply take a pen and paper and draw a "3D" Cube, the cube ain't 3D, it's 2D, that third dimension is simply an illusion. If you took that cube and drew the lines individually on a different section of the paper the lines would no longer look 3D. Well drawing a cube on paper's great but how do we take it and put it on a computer screen? The answer's much, much simpler then you think. ------------------------------------------------------------------------------ 3D Transformations ------------------ Geometry is a great thing, and one of the strangest things that I find about it is that an 3D object can be converted to a 2D object, and even stranger is that a 4D object(existence only in math) can be transformed into a 3D object. The question here is how. Well the best way to do it would be to make a FUNCTION in QBASIC with the formula(we'll get to them in a sec). Incase you don't know how to make a function, simply click EDIT and go down to NEW FUNCTION. We'll call this function POINTX%, and it will be used to transform a 3D coordinate into the X position(if you don't get it, don't worry it'll be explained). The function will have the following formula and should look like this: FUNCTION POINTX%(X, Z, ZOff, XOff) POINTX% = ((256 * X) / (Z - ZOff) + XOff END FUNCTION Q: Hold on!? What are the parameters for? A: X and Z are the axis' you wish to draw, ZOff is how far away the object is from you, and XOff is how much to the right the object is away from you. For example if you want to ZOOM IN on the object you would set ZOff to a lower number, if you wanted to ZOOM OUT on the object you would set ZOff to a greater number. If you wanted the object more to the right you would set XOff to a greater number and so on. Okay so that's great, but what about the Y axis? All we need to do to get the Y axis is take the same formula and change slightly. The next function you need to make is POINTY%, this will transform a 3D coordinate into the Y position. The function is simply: FUNCTION POINTY%(Y, Z, ZOff, YOff) POINTY% = ((256 * Y) / (Z - ZOff) + YOff END FUNCTION Same thing apply's in this FUNCTION as the previous, ZOff to zoom in and out, YOff for up and down. Great! I have two functions, now how do I use them? These two formula's are in essence all you need for a 3D engine, but I won't quit on you yet. I want to make sure you use them properly. So move on to the next section. ------------------------------------------------------------------------------ Creating 3D Objects ------------------- We're almost there, now remember that cube you drew on paper. Let's now draw it on the screen. Because resolution is of no importance we'll use SCREEN 13. Now a cube is basically the simplest 3D Object to draw. All sides are equal so all our coordinates will basically be the same number(if that confuses you just hang on). The most efficient way to do this is to place all the 3D coordinate of a cube into an array (a variable that can hold more than one number). However a normal integer array can't do the job, we need to make our own type of array. Our array needs to be able to hold 3 values per coordinate. So let's make that first. The array type will be called PNT for Point (we can't use POINT because it's already a QBASIC command). To declare a new type of array we simply do the following: TYPE PNT X AS INTEGER 'X axis Y AS INTEGER 'Y axis Z AS INTEGER 'Z axis END TYPE Now before we declare the array we need to know only one thing about the object were making. How many lines does it have. A cube has 12, now it's not necessary to do this now but it will be later on, we will have a variable that holds the number of lines in the cube. Well call it CUBELINES, simple enough, this is how it's done: CONST CUBELINES = 11 Q: Excuse me? Eleven lines, I thought you said 12. A: Your right but in QBASIC 0 counts as a number. The value 0 can hold a number, so from 0 to 11 there are 12 values, 12 lines and everything works out. Now we're ready to declare an array that will hold the values for the cube. The array will hold the amount of lines in our object as well as the X,Y,Z coordinates for it. It's should look like this: DIM CUBE (CUBELINES, 1) AS PNT CUBELINES because that holds the amount of lines and 1 because we need two values (remember 0 is a value so when we say 1 we mean 2, when we say 2 we mean 3 and so on). Now where do we write the values for a cube. QBASIC comes with a vary useful command, the DATA command. All this thing does is hold numbers for whatever purpose. I'm not going to explain the the coordinates of a cube, but if you take a close look you'll understand: CUBE: 'Name of our object 'X1, Y1, Z1, X2, Y2, Z2 DATA -10,-10,-10, 10,-10,-10 'Line1 DATA -10,-10,-10,-10, 10,-10 'Line2 DATA -10, 10,-10, 10, 10,-10 'You know the rest DATA 10,-10,-10, 10, 10,-10 DATA -10,-10, 10, 10,-10, 10 DATA -10,-10, 10,-10, 10, 10 DATA -10, 10, 10, 10, 10, 10 DATA 10,-10, 10, 10, 10, 10 DATA -10,-10, 10,-10,-10,-10 DATA -10, 10, 10,-10, 10,-10 DATA 10, 10, 10, 10, 10,-10 DATA 10,-10, 10, 10,-10,-10 Q: What's X1, Y1, Z1, X2, Y2, Z2? A: X1, Y1, Z1 is where to line begins. X2, Y2, Z2 is where it ends. Now we have the coordinates for a cube, but the array's still empty. What we need to do now is put this information, put all the DATA into the array. Well once again QBASIC has a useful command to do that. Infact it's a really straight forward command to. The READ command. All it does is read the numbers we put in DATA number after number. This is how it's used in our case: RESTORE CUBE 'Start reading DATA from our CUBE line FOR Loop1 = 0 TO CUBELINES 'Read 12 lines for our CUBE 'Read first three numbers as start coordinates READ CUBE(Loop1, 0).X, CUBE(Loop1, 0).Y, CUBE(Loop1, 0).Z 'Read last three numbers as end coordinates READ CUBE(Loop1, 1).X, CUBE(Loop1, 1).Y, CUBE(Loop1, 1).Z NEXT 'Do it again until all 12 lines are read We've now made our 3D Object and it's finally ready to be drawn. So let's move on to the next section to learn how to place our object on the screen. ------------------------------------------------------------------------------ Drawing A 3D Object ------------------- The last step to fully creating a 3D Object is obviously drawing it on the screen. This is quite complicated but if you take a good look at it you'll understand. What we need to do is now transform the 3Dcoordinates stored in the array into 2D coordinates and draw a line from the start point to the end. Look closely at the code and comments and you'll do just fine: SCREEN 13 'SCREEN 13 looks the best in my opinion FOR Loop1 = 0 TO CUBEL 'We must transform and draw 12 lines 'Convert coordinate for the X axis of the beginning point X1 = POINTX(CUBE(Loop1, 0).X, CUBE(Loop1, 0).Z, 100, 160) 'Convert coordinate for the Y axis of the beginning point Y1 = POINTY(CUBE(Loop1, 0).Y, CUBE(Loop1, 0).Z, 100, 100) 'Convert coordinate for the X axis of the end point X2 = POINTX(CUBE(Loop1, 1).X, CUBE(Loop1, 1).Z, 100, 160) 'Convert coordinate for the Y axis of the end point Y2 = POINTY(CUBE(Loop1, 1).Y, CUBE(Loop1, 1).Z, 100, 100) LINE (X1, Y1)-(X2, Y2), 4 'Draw the line using color 4, RED NEXT 'Do this 12 times for 12 lines Yay, come on cheer, you finished. You can now draw 3D objects in QBASIC something many programmers can't or don't bother doing. Well there's still rotations that need to be covered but that's another tutorial. For now just try and understand the whole concept of 3D transformations and try to figure out how to zoom in on objects (real simple task, I mean real simple). Also try to make objects of your own. If you make anything other then a cube e-mail me with the code so I can see someone learned something. Well I hope this helps you and any questions or comments are welcome. ------------------------------------------------------------------------------ Example Program --------------- DEFINT A-Z DECLARE FUNCTION POINTY (Y, Z, Zoff, Yoff) DECLARE FUNCTION POINTX (X, Z, Zoff, Xoff) TYPE PNT X AS INTEGER Y AS INTEGER Z AS INTEGER END TYPE CUBEL = 11 DIM CUBE(CUBEL, 1) AS PNT RESTORE CUBE FOR Loop1 = 0 TO CUBEL READ CUBE(Loop1, 0).X, CUBE(Loop1, 0).Y, CUBE(Loop1, 0).Z READ CUBE(Loop1, 1).X, CUBE(Loop1, 1).Y, CUBE(Loop1, 1).Z NEXT SCREEN 13 FOR Z = 400 TO 50 STEP -2 FOR Loop1 = 0 TO CUBEL X1 = POINTX(CUBE(Loop1, 0).X, CUBE(Loop1, 0).Z, Z, 160) Y1 = POINTY(CUBE(Loop1, 0).Y, CUBE(Loop1, 0).Z, Z, 100) X2 = POINTX(CUBE(Loop1, 1).X, CUBE(Loop1, 1).Z, Z, 160) Y2 = POINTY(CUBE(Loop1, 1).Y, CUBE(Loop1, 1).Z, Z, 100) LINE (X1, Y1)-(X2, Y2), 4 NEXT WAIT &H3DA, 8 FOR Loop1 = 0 TO CUBEL X1 = POINTX(CUBE(Loop1, 0).X, CUBE(Loop1, 0).Z, Z, 160) Y1 = POINTY(CUBE(Loop1, 0).Y, CUBE(Loop1, 0).Z, Z, 100) X2 = POINTX(CUBE(Loop1, 1).X, CUBE(Loop1, 1).Z, Z, 160) Y2 = POINTY(CUBE(Loop1, 1).Y, CUBE(Loop1, 1).Z, Z, 100) LINE (X1, Y1)-(X2, Y2), 0 NEXT WAIT &H3DA, 8 NEXT FOR Loop1 = 0 TO CUBEL X1 = POINTX(CUBE(Loop1, 0).X, CUBE(Loop1, 0).Z, Z, 160) Y1 = POINTY(CUBE(Loop1, 0).Y, CUBE(Loop1, 0).Z, Z, 100) X2 = POINTX(CUBE(Loop1, 1).X, CUBE(Loop1, 1).Z, Z, 160) Y2 = POINTY(CUBE(Loop1, 1).Y, CUBE(Loop1, 1).Z, Z, 100) LINE (X1, Y1)-(X2, Y2), 4 NEXT CUBE: DATA -10,-10,-10, 10,-10,-10 DATA -10,-10,-10,-10, 10,-10 DATA -10, 10,-10, 10, 10,-10 DATA 10,-10,-10, 10, 10,-10 DATA -10,-10, 10, 10,-10, 10 DATA -10,-10, 10,-10, 10, 10 DATA -10, 10, 10, 10, 10, 10 DATA 10,-10, 10, 10, 10, 10 DATA -10,-10, 10,-10,-10,-10 DATA -10, 10, 10,-10, 10,-10 DATA 10, 10, 10, 10, 10,-10 DATA 10,-10, 10, 10,-10,-10 FUNCTION POINTX (X, Z, Zoff, Xoff) POINTX = ((256 * X) / (Z - Zoff)) + Xoff END FUNCTION FUNCTION POINTY (Y, Z, Zoff, Yoff) POINTY = ((256 * Y) / (Z - Zoff)) + Yoff END FUNCTION