×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
• Talk With Other Members
• Be Notified Of Responses
• Keyword Search
Favorite Forums
• Automated Signatures
• Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

#### Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

# QBasic FAQ

## Graphical Techniques in QB

 3D Graphics Fundamentals by logiclrd faq314-361 Posted: 24 Dec 00 3D Graphics Fundamentals------------------------So you want to do 3D graphics? First, you have to understand the math. There's no other way to do it. The concepts behind the graphics are not difficult, however. What we're dealing with is basically the transformation of points from this:       |y       |       |   /z       |  /       | /       |/-------*------      /|     x     / |    /  |   /   |       |.. to this:                ___________               / =======  /|  ____________/_=======__/_|______ /                               /|+-------------------------------+ ||  .-------------------------.  | || |             |y            | | || |             |             | | || |             |             | | || |             |             | | || | ------------*------------ | | || |             |           x | | || |             |             | | || |             |             | | || |             |             | | ||  '-------------------------'  | ||  o o o o o o             [0]  |/+----------__--------___--------+          / /._____.\  /\         /____________/ /        /_____________\/If we take a closer look at what we're given to work with -- that is, the 3D space, or the so-called 'worldspace', in which our points are originally represented, from top-down, we see this:               |z               |               |               |               |               |               |---------------*--------------               |y            x               |               |               |               |               |               |The Y axis is no longer visible since it extends directly upwards from the diagram, away from your screen. Now, let's place a typical point into worldspace:               |z               |               |               |---P(x,y,z)               |   |               |   |               |   |---------------*--------------               |y            x               |               |               |               |               |               |The point P is at coordinates (x,y,z). Now, the concept of what we want to do is that we want to place the point on the screen so that it will be along the line of sight between the eye and the real point P, in the hopes that we can fool the eye into believing that it IS the point P. To do this, we need some representation of the screen in our 3D world. This is easier than it sounds, because the screen is nothing more than a section of a plane -- perfectly flat. Things become substantially simpler if we restrict the screen to be parallel to the XY plane. Our diagram now looks like this:               |z               |               |               |     P(x,y,z)               |               |          |---------|               |               |---------------*---------------               |y             x               |               |               |               |               |               |               |               |Two points are important in setting up the line-of-sight between the eye and the point P, and those are the eye and the point P themselves. We know where the point P is, but we haven't declared where the eye is yet. Having placed the screen like this, somewhat away from the XY plane, we can use the origin as the point that we're projecting from. Representing this in the diagram gives us this:               |z               |               |               |-----P(x,y,z)               |    /               |   /          |-------S-|               | /               |/---------------E---------------               |y             x               |               |               |               |               |               |               |               |.. where S is the point whose coordinates we need to know to place the pixel on the screen in the line-of-sight from E to P. Getting the coordinates of this point is easy. We know that the 'z' coordinate is the same as the screen, and we can put the screen wherever we want to. For simplicity, we can make this value 1. Getting the X and Y coordinates is a little bit more complicated, but still not hard. Notice that a system of similar triangles has been set up: the triangle with ES as hypotenuse has the same angles as the triangle with EP as hypotenuse. This means that there is proportionality between the edges of the two triangles. To simplify things, let's add two points to the diagram:               |z               |               |               K-----P(x,y,z)               |    /               |   /          |----J--S-|               | /               |/---------------E---------------               |y             x               |               |               |               |               |               |               |               |Using these 5 points, and denoting the distance between two points by specifying the two points (eg, EP for the distance from the eye to the point), the following proportionalities can be observed:  JS      ES      EJ ---- == ---- == ----  KP      EP      EKWe can construct a similar system as viewed from the right-hand side:               |y               |               |               |     P(x,y,z)               |    /|               | --/ |               |  S  |               | /|  |               |/ |  |---------------E--J--K---------               |x |           z               |  |               |  |               | ---               |               |               |               |               |Because of this, the above proportionalities can be expanded to:  Sx      Sy      Sz ---- == ---- == ----  Px      Py      PzSince we know that Sz -- the Z coordinate of the screen -- is 1, we can re-arrange these proportionalities into the following equations:         Px  Sx == ----         Pz         Py  Sy == ----         PzThus, the conversion from worldspace to the screen, which is referred to as viewspace, is a straightforward set of divisions. All that remains to be attended to are minor technicalities, such as the dimensions of the screen. It's not as simple as saying that one unit is one pixel, because by simplifying Sz as 1, that would require that the user be 1 pixel away from the screen, which is not the typical scenario. Assuming that we're dealing with SCREEN 13, which is 320x200x256 with roughly 1 mm per side on the pixels, the user is usually about 75 cm away from the monitor, which translates to 750 pixels. With larger screens, the user usually places themselves farther away, and with smaller monitors, the user usually sits closer to the monitor, so any inequities in pixel size with respect to monitor size tend to balance out proportionally and can be ignored. Now, if the user is 750 pixels away from the screen, the point on the screen S has a z value of 1, that means that the unit of z in worldspace is equivalent to 750 pixels. Since the system uses the same units for x and y as it does for z, the screen's boundaries in worldspace must be (-160 / 750, -100 / 750) to (160 / 750, 100 / 750). The x and y coordinates of S are thus scaled down by 750 from the corresponding screen coordinates, and they must be multiplied by 750 to get these values. The distance 75 cm is arbitrary, and it can be modified or calculated from angles to get different fields of vision, or FOVs (like in Quake). Once you have the coordinates, you can do whatever you want with them. Some sample code to demonstrate this follows. As usual, the code is optimized for readability, rather than speed.CONST PixelsFromEyeToCentreOfScreen# = 750CONST SphereStripes% = 32CONST SphereDotsPerStripe% = 24CONST NumDots% = SphereStripes% * SphereDotsPerStripe%CONST SphereRadius# = 1CONST SphereCentreX# = 0CONST SphereCentreY# = 0CONST SphereCentreZ# = 8TYPE pointType x AS DOUBLE y AS DOUBLE z AS DOUBLE oldScreenX AS INTEGER oldScreenY AS INTEGEREND TYPEDECLARE SUB makeSphere (dot() AS pointType)DIM dot(1 TO NumDots%) AS pointTypemakeSphere dot()SCREEN 13DO '0.003 radians == 17.2 degrees rotation# = rotation# + .003 IF rotation# > 6.283185 THEN rotation# = rotation# - 6.283185 FOR i% = 1 TO NumDots%  thisX# = dot(i%).x  thisY# = dot(i%).y  thisZ# = dot(i%).z  'rotate point around Y axis at Sphere Center (X,Y,Z)  rotatedX# = COS(rotation#) * (thisX# - SphereCentreX#) - SIN(rotation#) * (thisZ# - SphereCentreZ#) + SphereCentreX#  rotatedY# = thisY#  rotatedZ# = SIN(rotation#) * (thisX# - SphereCentreX#) + COS(rotation#) * (thisZ# - SphereCentreZ#) + SphereCentreZ#  'translate to screen coordinates  pointSX# = rotatedX# / rotatedZ#  pointSY# = rotatedY# / rotatedZ#  screenX% = 160 + pointSX# * PixelsFromEyeToCentreOfScreen#  screenY% = 100 - pointSY# * PixelsFromEyeToCentreOfScreen#  'do a little bit of depth queuing (very simple =D)  IF rotatedZ# > SphereCentreZ# THEN   colour% = 8 'dark gray  ELSEIF rotatedZ# > SphereCentreZ# - SphereRadius# / 2 THEN   colour% = 7 'light gray  ELSE   colour% = 15 'white  END IF  'draw pixel  PSET (screenX%, screenY%), colour%  'erase old pixel in a fairly flicker-free way  IF (dot(i%).oldScreenX <> screenX%) OR (dot(i%).oldScreenY <> screenY%) THEN   PSET (dot(i%).oldScreenX, dot(i%).oldScreenY), 0  END IF  'store new pixel's position for next time  dot(i%).oldScreenX = screenX%  dot(i%).oldScreenY = screenY% NEXT i%LOOP UNTIL INKEY\$ <> ""SCREEN 0: WIDTH 80, 25SUB makeSphere (dot() AS pointType)FOR i% = 1 TO SphereStripes% heading# = 6.283185 * i% / SphereStripes% FOR j% = 1 TO SphereDotsPerStripe%  pitch# = 3.141592 * (j% - 1) / (SphereDotsPerStripe% - 1) - 1.570796  thisDotX# = SphereRadius# * SIN(heading#) * COS(pitch#)  thisDotY# = SphereRadius# * SIN(pitch#)  thisDotZ# = SphereRadius# * COS(heading#) * COS(pitch#)  thisDotIndex% = (i% - 1) * SphereDotsPerStripe% + j%  dot(thisDotIndex%).x = thisDotX# + SphereCentreX#  dot(thisDotIndex%).y = thisDotY# + SphereCentreY#  dot(thisDotIndex%).z = thisDotZ# + SphereCentreZ# NEXT j%NEXT i%END SUB Back to QBasic FAQ Index Back to QBasic Forum

Close Box

# Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

• Talk To Other Members
• Notification Of Responses To Questions
• Favorite Forums One Click Access
• Keyword Search Of All Posts, And More...

Register now while it's still free!