//////////////////////////////////////////////////////////////////////////////
/ 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