'=========================================================================== ' Subject: 3D TUTORIAL Date: 07-25-99 (11:59) ' Author: Krusty Code: QB, QBasic, PDS ' Origin: santa@tir.com Packet: GRAPHICS.ABC '=========================================================================== 'Here y'all go 'this is *substansially* commented, and progesses from the very 'simplest stuff (rotating dots), to the good stuff (acually still 'fairly easy) such as rotating cubes 'I noticed a few bugs in the last progs. i sent you: '1: i dimmed somthing wrong {i think it was angl()} ' it should have been AS SINGLE, not AS INTEGER '2: I rote "rotating at *t* radians per second" it should have ' read "*speed* radians per second" '3: I neglected to take into acount screen 9's dodgey x-coords to ' y-coords ratio '-----EXAMPLE 1----- 'Screen 9 is dodgey SCREEN 9 PRINT "Example 1" PRINT "Screen 9 is dodgey" DO: LOOP UNTIL INKEY$ <> "": CLS 'press a key PRINT "100 pixels by 100 pixels square:" DO: LOOP UNTIL INKEY$ <> "": CLS 'press a key LINE (0, 0)-(100, 100), 15, B 'should be a square right? it's not though (try it) DO: LOOP UNTIL INKEY$ <> "": CLS 'press a key PRINT "100 pixels by 73 pixels square:" DO: LOOP UNTIL INKEY$ <> "": CLS 'press a key LINE (0, (35 / 48) * 0)-(100, (35 / 48) * 100), 15, B 'this time we multiply all y-coords by 35/48, to correct the problem '-----EXAMPLE 2----- 'dot going in an oval DO: LOOP UNTIL INKEY$ <> "": CLS PRINT "Example 2" PRINT "Dot going in an oval" DO: LOOP UNTIL INKEY$ <> "" 'press a key CLS DIM t AS SINGLE, y AS INTEGER, x AS INTEGER 't can have decimal places, x and y cannot (speeds things up) CONST PI = 3.141596 CONST speed = .1 'set up the constants LINE (100, 0)-(100, (35 / 48) * 200), 8 CIRCLE (100, (35 / 48) * 100), 100, 8, , , .22 'draw the axis, and path of the dot SCREEN 9 DO DO: LOOP UNTIL TIMER > stoptime: stoptime = TIMER + .025 'just a little delay loop-ignore it t = t + speed y = 30 * SIN(t) x = 100 * COS(t) PSET (x + 100, (35 / 48) * (y + 100)) 'notice that (35/48)*y-coord is used here [refer to last example] 'i have added 100 to both y and x, to display it on screen LOOP UNTIL INKEY$ <> "" 'the formula y=A*sin(t),x=B*cos(t) gives a circle 'in this case x and y are in the ratio 10:3, giving 'an oval around the midpoint (100,100) '-----EXAMPLE 3----- 'applying vid-pages CLS PRINT "Example 3" PRINT "Using vid pages" PRINT "(to get a smooth movement)" DO: LOOP UNTIL INKEY$ <> "" 'press a key CLS 'I have already DIMed t, x and y SCREEN 9, , 0, 1 'draw on page 0, but view page 1 DO PCOPY 0, 1 'copy what is on page 0 to page 1 LINE (0, 0)-(200, 200), 0, BF 'erase the last image, by drawing a black image 'over it. Strangly this is quicker than CLS LINE (100, 0)-(100, (35 / 48) * 200), 8 CIRCLE (100, (35 / 48) * 100), 100, 8, , , .22 'draw the axis and the dot's path (why not?) DO: LOOP UNTIL TIMER > stoptime: stoptime = TIMER + .05 'just a little delay loop-ignore it t = t + speed y = 30 * SIN(t) x = 100 * COS(t) PSET (x + 100, (35 / 48) * (y + 100)) LOOP UNTIL INKEY$ <> "" '-----EXAMPLE 4----- 'doing more dots CLS SCREEN 9, , 0, 0 PRINT "Example 4" PRINT "Doing more dots" PRINT "(to create a rotating plane)" DO: LOOP UNTIL INKEY$ <> "" 'press a key CLS 'I have already DIMed t DIM dots AS INTEGER DIM x(100) AS INTEGER, y(100) AS INTEGER, angle(100) AS SINGLE 'not much has changed, but now we have up to 100 dots 'each with different angles dots = 6 'say how many dots we actually want FOR m = 1 TO 6 angle(m) = PI * m / 3 NEXT m 'give them angles between 0 and 2*PI (360 degrees), 'and have them uniformly spaced: '1/3 PI, 2/3 PI , PI , 4/3 PI , 5/3 PI , 2 PI SCREEN 9, , 0, 1 DO PCOPY 0, 1 LINE (0, 0)-(200, 200), 0, BF LINE (100, 0)-(100, (35 / 48) * 200), 8 CIRCLE (100, (35 / 48) * 100), 100, 8, , , .22 'copy the old image, erase the "active" screen (invisible), 'draw the axis and draw the dot's path (...in that order) DO: LOOP UNTIL TIMER > stoptime: stoptime = TIMER + .05 'just a little delay loop-ignore it t = t + speed FOR m = 1 TO dots y(m) = 30 * SIN(t + angle(m)) x(m) = 100 * COS(t + angle(m)) PSET (x(m) + 100, (35 / 48) * (y(m) + 100)) NEXT m 'draw the 6 dots 'draw them at differnt angles, by using SIN{t+angle(m)} not SIN{t} 'where m is the dot's "reference number" (1,2,3,4,5 or 6) LOOP UNTIL INKEY$ <> "" '-----EXAMPLE 5----- 'using elevation and distance from axis CLS SCREEN 9, , 0, 0 PRINT "Example 5" PRINT "Using elevation" PRINT "(to create a rotating cuboid)" DO: LOOP UNTIL INKEY$ <> "" 'press a key CLS 'I have already DIMed t, x() , y() , angle() and dots DIM elev(100) AS INTEGER, dist(100) AS INTEGER 'not much has changed, but now we have differnt heights and distances 'from the y-axis (vertical) too. dots = 8 FOR m = 1 TO 4 angle(m) = PI * m / 2 angle(m + 4) = PI * m / 2 dist(m) = 100 dist(m + 4) = 100 elev(m) = 50 * SQR(2) elev(m + 4) = -50 * SQR(2) NEXT m 'Set up the variables in such a way as to create a cuboid: '(distance of points from the axis of rotation is the same, 'there are two elevations : 50 and -50, 'and the points are uniformally spread out SCREEN 9, , 0, 1 DO PCOPY 0, 1 LINE (0, 0)-(300, 300), 0, BF LINE (100, 0)-(100, (35 / 48) * 300), 8 CIRCLE (100, (35 / 48) * (150 - (50 * SQR(2)))), 100, 8, , , .22 CIRCLE (100, (35 / 48) * (150 + (50 * SQR(2)))), 100, 8, , , .22 'copy the old image, erase the "active" screen (invisible), ',draw the axis and draw the two oval things DO: LOOP UNTIL TIMER > stoptime: stoptime = TIMER + .05 'just a little delay loop-ignore it t = t + speed FOR m = 1 TO dots y(m) = 1 / 3 * dist(m) * SIN(t + angle(m)) + elev(m) x(m) = dist(m) * COS(t + angle(m)) PSET (x(m) + 100, (35 / 48) * (y(m) + 150)) NEXT m 'draw the 8 dots 'the x/y formula get a little more tricky 'what has been added since Example 4: ' " +elev(m) " to create more than one plane ' " dist(m)*... has replaced 100*... " ' " 1/3*dist(m)*... has replaced 30*... " 'to take into ' acount the distance from the axis (althogh as it happens ' dist(1),dist(2)..dist(8) are all 100 anyway LOOP UNTIL INKEY$ <> "" '-----EXAMPLE 6----- '3D lines CLS SCREEN 9, , 0, 0 PRINT "Example 6" PRINT "3D rotating lines" PRINT "(or join the dots)" DO: LOOP UNTIL INKEY$ <> "": CLS 'press a key 'I have already DIMed t,x(),y(),angle(),elev(), dist(100) and dots. 'Also these variables are already set to that of a cube, so 'i do not need to redo that either DIM join1(100) AS INTEGER, join2(100) AS INTEGER, lines AS INTEGER lines = 12 'self explanatory really FOR m = 1 TO 4 join1(m) = m join2(m) = m + 4 join1(m + 4) = m join2(m + 4) = m + 1: IF join2(m + 4) = 5 THEN join2(m + 4) = 1 join1(m + 8) = m + 4 join2(m + 8) = m + 5: IF join2(m + 8) = 9 THEN join2(m + 8) = 5 NEXT m 'do all the lines: ' join1(m) = m ' join2(m) = m + 4 'refer to the 4 horizontal line's - 'it joins points 1 to 5 , 2 to 6 , 3 to 7 and 4 to 8 ' join1(m + 4) = m ' join2(m + 4) = m + 1: IF join2(m + 4) = 5 THEN join2(m + 4) = 1 'refers to the bottom 4 lines - 'it joins points 1 to 2 , 2 to 3 , 3 to 4 and 4 to 1 ' join1(m + 8) = m +4 ' join2(m + 8) = m + 5: IF join2(m + 8) = 9 THEN join2(m + 8) = 5 'refers to the top 4 lines - 'it joins points 5 to 6 , 6 to 7 , 7 to 8 and 8 to 5 SCREEN 9, , 0, 1 DO PCOPY 0, 1 LINE (0, 0)-(300, 300), 0, BF LINE (100, 0)-(100, (35 / 48) * 300), 8 CIRCLE (100, (35 / 48) * (150 - (50 * SQR(2)))), 100, 8, , , .22 CIRCLE (100, (35 / 48) * (150 + (50 * SQR(2)))), 100, 8, , , .22 'view the current image, and erase it ,etc etc t = t + speed FOR m = 1 TO dots y(m) = 1 / 3 * dist(m) * SIN(t + angle(m)) + elev(m) x(m) = dist(m) * COS(t + angle(m)) y(m) = (35 / 48) * (y(m) + 150) x(m) = x(m) + 100 'i have put these two lines here to make a line further 'on easier to read. NEXT m FOR m = 1 TO lines LINE (x(join1(m)), y(join1(m)))-(x(join2(m)), y(join2(m))), 15 NEXT m 'that last bit is a little harder to explain than the rest, 'join1(m) and join2(m) store the "reference numbers" of the 'two points connected by line m 'we then draw a line between the point[join1(m)] and the point[join2(m)] LOOP UNTIL INKEY$ <> "" '-----EXAMPLE 7----- 'One way to only display visible faces CLS SCREEN 9, , 0, 0 PRINT "Example 7" PRINT "A way to only display visible faces" PRINT "(The end is nigh)" DO: LOOP UNTIL INKEY$ <> "": CLS 'press a key 'I have already DIMed and set up everything SCREEN 9, , 0, 1 DO PCOPY 0, 1 LINE (0, 0)-(300, 300), 0, BF LINE (100, 0)-(100, (35 / 48) * 300), 8 CIRCLE (100, (35 / 48) * (150 - (50 * SQR(2)))), 100, 8, , , .22 CIRCLE (100, (35 / 48) * (150 + (50 * SQR(2)))), 100, 8, , , .22 'all as before t = t + speed FOR m = 1 TO dots y(m) = 1 / 3 * dist(m) * SIN(t + angle(m)) + elev(m) x(m) = dist(m) * COS(t + angle(m)) y(m) = (35 / 48) * (y(m) + 150) x(m) = x(m) + 100 'still nothing new NEXT m FOR m = 1 TO 4 LINE (x(join1(m + 8)), y(join1(m + 8)))-(x(join2(m + 8)), y(join2(m + 8))), 15 'Draw the top face IF y(m) > 144 THEN LINE (x(join1(m)), y(join1(m)))-(x(join2(m)), y(join2(m))), 15 'draw the 3 visible vertical lines IF y(m) > 178 THEN mp = m + 5: IF mp > 8 THEN mp = 5 mm = m + 3: IF mm < 5 THEN mm = 8 LINE (x(join1(m + 4)), y(join1(m + 4)))-(x(join2(m + 4)), y(join2(m + 4))), 15 LINE (x(join1(mm)), y(join1(mm)))-(x(join2(mm)), y(join2(mm))), 15 'draw the two visible bottom lines END IF NEXT m 'this method only works for objects that we know about, 'such as a pre-programmed cube. 'It is not a general algorithm. 'All it does is draw the top four lines, and draws the others 'if their y value is big enough (and they must 'therefore be visible) 'more over this method is imperfect-watch the cube closely LOOP UNTIL INKEY$ <> "" SCREEN 9, , 0, 0: CLS PRINT " That's all folk's" PRINT " Thanks for watching" PRINT PRINT PRINT "To find out what was going on read the comments" PRINT " within this .BAS file" PRINT "To find out about other 3D stuff read the comments" PRINT " at the bottom of this .BAS" PRINT PRINT " Maths/Algorithms: Krusty" PRINT " Coding: Krusty" PRINT " Graphics: Krusty" PRINT " With special thanks to: Krusty, Al" PRINT " (for getting me into all this kewl 3D stuff again)" PRINT PRINT " E-Mail Krusty at christie@intonet.co.uk" ' -----Final Comments----- ' 'As i said earlier, the method i used for showing 'only some faces of the cube was not really good enough ',as a general solution. 'To do that you can ' ' '