home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / PXDTUT1.ZIP / PXDTUT1.TXT < prev   
Text File  |  1997-04-17  |  21KB  |  544 lines

  1.  
  2.                   |====================================|
  3.                   |                                    |
  4.                   |   TELEMACHOS proudly presents :    |
  5.                   |                                    |
  6.                   |    Part 1 of the PXD trainers  -   |
  7.                   |                                    |
  8.                   |             DOOM-WALLS             |
  9.                   |      the technique and tricks!     |
  10.                   |                                    |
  11.                   |====================================|
  12.  
  13.          ___---__-->   The Peroxide Programming Tips   <--__---___
  14.  
  15. <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
  16.  
  17.  
  18. Intoduction
  19. -----------
  20.  
  21. "Hi there! This is Telemachos of HASH. Now you might be wondering who the hell
  22. HASH is. Well - HASH is a great upcomming danish group. We make everything
  23. from PPE's, demos, utilities, GFX, ANSI, an e-mag, music and now also
  24. programming tuturials. So keep an eye out for future releases from us :)"
  25.  
  26. Sigh! Well, some of you might have read the lines above before... YES this IS
  27. a re-release.
  28. But before nukin' this file from your HD please read the new information below.
  29.  
  30. The truth is : HASH died... but Peroxide raised from the dust - featuring many
  31. new talented members. The main reason why HASH died is, that some of the members
  32. were more serious than others. Myself along with our founder Candyman, our
  33. musician Punqtured and our Net-coordinator Notion wanted the group to be a
  34. group know for its great releases - but rather the group became known as a
  35. bunch of ever-arguing, ever-flaming idiots constantly in war with another
  36. danish demogroup called The Renegades.
  37. So we decided to kill the group and together we formed Peroxide with the 4
  38. before mentioned members as Seniors and a bunch of new (and some old) guys as
  39. group members.
  40.  
  41. I really wanted to continue the trainer-serie I once started in HASH, and
  42. therefore I decided to to re-release this tut - now under another name :
  43.  
  44. ___---__-->  The Peroxide Programming Tips  <--__---___
  45.  
  46.  
  47. The goal for this serie has also changed a little. Instead of just writing
  48. about all the common topics in graphic programming (fx. 3d-rotations, plasma,
  49. fire, scrolling and so on) I'll try and stay on the path I originally set when
  50. starting a trainer-serie with a topic as complex as texturemapped 3d-worlds :)
  51. I'll try and write about the stuff that other tut-writers seems to have
  52. overlooked - the not not-so-common effects, the things that might sound a
  53. little boring compared to all the colorfull demo-effects :)
  54. I can't promise, though, that I won't release some info on all the common stuff
  55. also :) So drop me a letter telling me what to do :)
  56.  
  57. If you got the original HASH-tut please replace it with this version.. a FEW
  58. minor bugs has been corrected in this version. Also please notice the new
  59. E-mail address.
  60.  
  61.  
  62. *************************** ATTENTION ARTISTS!!! *****************************
  63.  
  64. ARE YOU AN ARTIST ?
  65. DO YOU DRAW VGA-BITMAPS ?
  66. CAN YOU DO GFX IN ALL RESOLUTIONS - 320x200x256 AND VARIOUS SVGA-MODES ?
  67. DO YOU WANT TO SEE YOUR WORK IN AMAZING PRODUCTIONS ?
  68. CAN YOU DO GAME-GFX AS WELL AS BACKGROUNDS FOR DEMOS ?
  69.  
  70. IF YOU MEET THE ABOVE TERMS (or some at least :) ), THEN DROP ME (TELEMACHOS)
  71. A MESSAGE OR MAIL THE GROUP AT :  Peroxide@image.dk
  72.  
  73. ******************************************************************************
  74.  
  75.  
  76. In this trainer I will cover the techniques I used to draw 3d-walls similar to
  77. those in the famous computer game DOOM. I assume the reader have a basic
  78. understanding of how to program the VGA-card. Also I will be using quite a bit
  79. of math on high school level.
  80. If you don't understand vector-math you can still read this doc and end up
  81. beeing able to code some neat gfx, but then you won't understand what you're
  82. doing :=)
  83. I will drop code in Pascal, but it should be easy to convert into other
  84. languages.
  85.  
  86.  
  87. If you don't know how to program the VGA-card, you should read the trainers
  88. written by DENTHOR of ASPHYXIA. He has written (at this date) 21 great tuturials
  89. covering the basic VGA coding as well as quite a few nice demo effects.
  90. Search the I-net for DENTHOR and you will find the trainers somewhere.
  91. The 10 first trainers is also available through the PCGPE 1.0
  92.  
  93.  
  94. If you want to get in contact with me, there are several ways of doing it :
  95.  
  96. 1) Write me via FIDO-net   :      2:235/350.22
  97.  
  98. 2) E-mail me               :      tm@image.dk
  99.  
  100. 3) Snail mail me           :      Kasper Fauerby
  101.                                   Saloparken 226
  102.                                   8300 Odder
  103.                                   Denmark
  104.  
  105. 4) Call me  (Voice ! )     :    +45 86 54 07 60
  106.  
  107.  
  108.  
  109. Get this serie from the major demo-related FTP-sites or from our own homepage
  110. (soon at least ;) )        :  http://www.image.dk/~peroxide
  111. or directly from my own    :  http://www.image.dk/~tm
  112.  
  113.  
  114.  
  115. Well... enough talk - we wanna se some code !
  116. ----------------------------------------------
  117.  
  118. Oki... code u want - code u get!
  119. First of all lets make some definitions..
  120. My way of defining 3d-space is as follows :
  121.  
  122.           \   |
  123.             \ |
  124.          ----------------------------> X-axis
  125.               | \
  126.               |   \
  127.               |     \
  128.               |       \
  129.               |         \
  130.               |           \
  131.               |             \> Z-axis (dissapears into the screen - in case u
  132.               V                        don't understand my neat drawing :=)  )
  133.             Y-axis
  134.  
  135.  
  136.  
  137.  
  138. Also I have another way of doing 3d -> 2d than most others.
  139.  
  140. You have probably been told to use transformations like the following :
  141.  
  142.        X0 := 256*x div (z-Zoff)  ( + Xoffset )
  143.        Y0 := 256*y div (z-Zoff)  ( + Yoffset )
  144.  
  145. Well... I say - FORGET ALL ABOUT THE CRAP ABOVE!!!!
  146. The ONLY way to do correct 3d-transformations is to use the following formulas:
  147.  
  148.  X0 := Xofs  +  Round(X*(Zeye/(Zeye-Z)));
  149.  Y0 := Yofs  +  Round(Y*(Zeye/(Zeye-Z)));
  150.  
  151. I know, I know... It takes a little more calculations to use these formulas,
  152. but it is worth it - believe me!
  153.  
  154. With the above formulas 3 new constants has been introduced : Xofs, Yofs and
  155. Zeye. The three constants together makes the coordinate-set of THE EYE
  156. through wich the 3d-world is viewed. I personnally likes to use the following
  157. values : Xofs = 160, Yofs = 100 and Zeye = -200
  158. With these values the eye is placed in the middle of the screen (MCGA mode)
  159. some distance from the monitor. Yes that's correct - in your head :)
  160. The Xofs and Yofs defines the ORIGIN of your 3d-system - so the point (-5,4,0)
  161. will be at screen coord : (-5 + Xofs, 4 + Yofs), in my case (155,104)
  162.  
  163. That done we can move on to the REAL subject of this trainer - the DOOM walls.
  164.  
  165.  
  166. A little speculations - boring perhaps, but nessesary :)
  167. ---------------------------------------------------------
  168.  
  169. Well.. lets take a look at the poly we wanna texture map.
  170. As it's a doom-wall we know quite a few things about it.
  171.  
  172. 1)  Its left and right sides are ALWAYS parallel with the Y-axis of the screen.
  173.     Well.. what does that means... It means that we can draw the mapped poly as
  174.     a row of vertical lines - each with a different height and starting Y-pos.
  175.     Take a look at this, and you'll know what i mean :
  176.  
  177.         P1
  178.          |\
  179.          |   \
  180.          |   |  \ P2
  181.          |   |   |
  182.          |   |   |
  183.          |   |   |
  184.          |   |   |
  185.          |   |  / P3
  186.          |   /
  187.          |/  ^
  188.          P4  one of the vertical lines.
  189.  
  190.  
  191. 2)  Each of the vertical lines has a CONSTANT Z-value. Now this is VERY
  192.     important. If you follow a line with a constant Z-value, the corresponding
  193.     line in TEXTURE-SPACE - that is, the bitmap you want to map to the poly -
  194.     will have a CONSTANT SLOPE. Furthermore, if the line with constant z-value
  195.     is vertical - like the ones we look at - then the line in texture-space
  196.     will also be vertical.
  197.     What does that mean ? Well.. it means that each vertical line in the poly
  198.     just needs to be mapped with a scaled line from the texture.
  199.     Now we have a formula for mapping a vertical line of the poly...
  200.  
  201.     1) Find the height of the line in the poly - lets call it LH
  202.     2) We know the height of the texture - lets say it's 128.
  203.     3) Now we calculate the STEP we need to increse the Ypos in texture-space
  204.        with for each pixel in the poly-line. STEP = 128 / LH.
  205.     4) we'll define the following variables :
  206.        YposScreen, XposScreen - the start coordinate of the line in the poly.
  207.        YposTexture, XposTexture - The position in texture-space.
  208.     5) Now lets map the damn thing !
  209.  
  210.         for i := 1 to LH do
  211.           begin
  212.            mem[$a000:YposScreen*320 + XposScreen] := texture[XposTexture,
  213.                YposTexture];
  214.            inc(YposScreen);
  215.            YposTexture := YposTexture + STEP;
  216.           end;
  217.  
  218.       Voila - here you go.. a texture mapped vertical line.
  219.  
  220.  
  221.  
  222. Hey - neat, I hear you cry. Now this is easy.. I'll just calculate a STEP for
  223. movement along the X-side of the texture also.... and then just map each
  224. vertical line in the poly with a scaled line from the texture with the
  225. corresponding X-position in texture-space!
  226.  
  227. Well.. try it! You will soon find out that result of this method is not to
  228. good! The poly IS mapped and the vertical lines looks beautiful... The problem
  229. is that the poly does'nt look 3d after all! It just looks like the texture has
  230. been squeezed a little on one side and then slammed to the screen. It surely
  231. does look more like a scaling than a texture mapping.
  232.  
  233.  
  234. But what's wrong then ???
  235. --------------------------
  236.  
  237. WHY, I hear you cry! Now I thought it was so easy, and all I end up with is
  238. crap!
  239. Well.. dry your eyes - we'll find a way.
  240.  
  241. The problem with the above mentioned method is that the human eye sees things
  242. in another way.
  243.  
  244. When you look at something - a little from the side - notice that if you
  245. projected the object you look at to a 2d-screen, then the middle of the
  246. "texture" pasted to it WOULD NOT appear at the middle of the polygon !!!!
  247. Come on... Take a piece of paper and draw a line exactly down the middle of
  248. it. Then hold the paper at an arms length and look at it from the side. Does
  249. the line appear exactly at the middle of the projection you see of the paper ?
  250. NO... depending on the angle you are viewing the paper at, you will see the
  251. line move from the middle of the paper towards you.
  252.  
  253. So what we need to do is to find a way of determing the correct X-INDEX in
  254. texture-space for each screen-column occupied by the poly.
  255. If you don't understand this, read the above paragraph again until you do!
  256. This is the very key to texture-mapping.
  257.  
  258. Well.. we'll have to look at the wall a little more in 3d than we did before.
  259. Until now we have only looked at the PROJECTION of the wall.. now is the time
  260. to think 3d :=)
  261. And then again - we really don't have to! We just have to twist the view a
  262. little. Until now we have looked at the X,Y plane... Now lets take a look at
  263. the X,Z plane - ie. we look at the 3d-world from ABOVE the monitor :
  264.  
  265.  
  266.                      Z-axis
  267.                        ^
  268.                        |
  269.                        |    P1     a ray
  270.                        |      \    /
  271.                        |        \ /
  272.                        |         B\
  273.                        |        /   \
  274.                        |(0,0,0)/     P2 > A wall seen from above.
  275.                        |/     /
  276.   ----SL---------------O-----A----------SR----> X-axis
  277.       ^ (-160,0,0)     |    / (50,0,0)   ^ (160,0,0)
  278.                        |   /
  279.                        |  /
  280.                        | /
  281.                        E
  282.                        ^
  283.                       eye (0,0,-200)
  284.  
  285.  
  286. Well.. neat ehh? If we look at the walls from above we can just look at them
  287. as LINES in a 2d space!
  288. Now, the point SL defines the left side of our computer monitor and SR
  289. defines the right side of our monitor.
  290. If we then makes one point along the X-axis equal 1 pixel along the screen
  291. then all we need to do when we want to know the x-index in the wall
  292. corresponding to a screen-column, is to calculate the intersection between
  293. the line made by the wall and the line drawn from the eye, through the screen-
  294. column and finaly through the wall-line. This is called ray-casting.
  295.  
  296. As an example look at the ray drawn above. We know that the point A lies on
  297. the poly we get from projecting the wall P1,P2 to the screen. To find the
  298. correct index in texture-space we draw a virtual line from the eye E, through
  299. the point A and then finds the intersection with the wall - namely the point B.
  300. If we look at the drawing it looks like B is about 60% down the wall... If the
  301. texture is 128 pixels wide, then we know the correct X-index would be :
  302.  128 * 60%  = 76.8 ... Rounded to 77. Ie. the vertical line at point A should
  303. be mapped with line 77 in the texture - even though we can clearly see, that
  304. A would be one of the first lines in the poly !
  305.  
  306. Here you go... do this with all of the screen columns occupied by the poly,
  307. and you have done a perspectively correct texture-maping!
  308.  
  309.  
  310. Now for the really ugly part... the vector math :=)
  311. ----------------------------------------------------
  312.  
  313. But in real life we can't just say : Humm... it looks like the intersection
  314. between the wall and the ray through screen coloumn X is about xx % down the
  315. wall..
  316. We need to find a way of CALCULATING the exact intersection.
  317. Now it's time to introduce our good friend  :  -=[ Mr. Vector ]=-.
  318.  
  319.  
  320. If we set up the parametric equation for the ray and a parametric equation for
  321. the line representing the wall, all we have to do is to calculate the
  322. intersection between those two equations.
  323.  
  324. Now, as long as we don't move our eye position during runtime we can
  325. precalculate all the parametric equations we'll ever need for our rays.
  326. All we have to do is to store the X and Z vector components in a small array.
  327. Since all the rays has an angle associated with it - namely the angle
  328. between the ray and the Z-axis - we can calculate a ray's vector components as
  329. COS and SIN of this angle.
  330.  
  331. Here is how I did it :
  332.  
  333. PROCEDURE Build_table;
  334. VAR
  335.  counter : integer;
  336.  angle : real;
  337. BEGIN
  338.  for counter:=0 to 319 do
  339.  BEGIN
  340.    angle:=ARCTAN((counter-Xofs)/ABS(Zeye)*((2*pi)/360));
  341.    raytable[counter,1]:=Cos((2*pi)/360)*angle);
  342.    raytable[counter,2]:=Sin((2*pi)/360)*angle);
  343.  END;
  344. END;
  345.  
  346. Now the array RAYTABLE contains the vector components of the ray through each
  347. screen column. I stored the components so Raytable[X,1] was the Z-comp and
  348. Raytable[X,2] was the Xcomp.
  349.  
  350.  
  351. So the parametric equation for a ray is :
  352.  
  353. RayX = s * (X component of the ray)
  354. RayZ = s * (Z component of the ray) + Zeye
  355.  
  356.  
  357. Now all we need is the equation for the wall... Let the wall be difined by the
  358. points P1 and P2 - where P1 ALWAYS is the point farthest to the left.
  359. Then let P1X be the X-value for P1 and let P1Z be the Z-value. Guess what we'll
  360. call the X and Z value for P2 :=)
  361.  
  362. To make the wall a vector subtract the left end values from the right end
  363. values.
  364. Ie. the parametric equation for the wall is :
  365.  
  366. WallX = t * (P2X - P1X) + P1X
  367. WallZ = t * (P2Y - P1Y) + P1Y
  368.  
  369.  
  370. Now where does these two lines cross? They cross where WallX = RayX and
  371. WallZ = RayZ. So we get :
  372.  
  373. s * (X component of the ray) = t * (P2X - P1X) + P1X
  374. s * (Z component of the ray) + Zeye = t * (P2Y - P1Y) + P1Y
  375.  
  376. Now, because we used the hole wall to define the vector used in the line
  377. equation we know that if we solve the two equations above for t, then t will
  378. range from 0 to 1. It'll be the percent of the wall length where the two lines
  379. collide! To get the correct X-position in the texture multiply t by the
  380. textures width - in this case 128.
  381.  
  382. Lets make our brains bleed, shall we ?
  383. We don't care about the variable s so lets isolate it in both equations :
  384.  
  385.         t *(P2X-P1X) + P1X
  386. 1)  s = --------------------
  387.              Xcomp
  388.  
  389.         t*(P2Z-P1Z) + P1Z - Zeye
  390. 2)  s = --------------------------
  391.              Zcomp
  392.  
  393.  
  394. well ... combine the two and get :
  395.  
  396. t * (P2X-P1X) + P1X        t * (P2Z-P1Z) + P1Z - Zeye
  397. --------------------   =   ----------------------------
  398.       Xcomp                        Zcomp
  399.  
  400.  
  401. We don't like that divisor - lets get rid of it :
  402.  
  403. t*Zcomp*(P2X-P1X) + P1X*Zcomp = t*Xcomp*(P2Z-P1Z) + P1Z*Xcomp - Zeye*Xcomp
  404.  
  405. well ... lets get the t's on one side :
  406.  
  407. t*(Zcomp*(P2X-P1X) - Xcomp*(P2Z-P1Z)) + P1X*Zcomp = P1Z*Xcomp - Zeye*Xcomp
  408.  
  409. humm... lets isolate t :
  410.  
  411.     P1Z*Xcomp - Zeye*Xcomp - P1X*Zcomp
  412. t = -----------------------------------
  413.      Zcomp*(P2X-P1X) - Xcomp*(P2Z-P1Z)
  414.  
  415. finally lets save a costly multiply :
  416.  
  417.  
  418.      Xcomp * (P1Z-Zeye) - P1X*Zcomp
  419. t = ------------------------------------
  420.      Zcomp*(P2X-P1X) - Xcomp*(P2Z-P1Z)
  421.  
  422.  
  423. TADA... easy huh ? Now you got all you need to do texture mapping with correct
  424. perspective :)
  425.  
  426.  
  427.  
  428. What ? You're to lazy to do the routines yourself ?
  429. ----------------------------------------------------
  430.  
  431. Well.. this section should be superfluous, but I'll do it anyway :)
  432. In this section I'll drop some pascal code to do texture mapping.
  433.  
  434. I'll write it in plain pascal though, so you'll have to do the optimizations
  435. yourself - that is : use fixed point math, add clipping, convert it to
  436. assembler and find a better way of storing the texture data.
  437. As for the last point watch out for my next trainer, wich will cover the
  438. use of memory above the 640K base memory.
  439.  
  440. Also you c(sh)ould add features as "see through" colors, to make your engine
  441. capeable of doing textures with windows, grates and more.
  442. All this is fortunately quite easy to do - trust me 8)
  443.  
  444. Anyway here you go :
  445.  
  446.  
  447. VAR raytable : Array[0..319,1..2] of real;  {each ray is Z-comp, X-comp}
  448.     walltex : Array[0..128,0..128] of byte;
  449.  
  450.  
  451.  
  452. FUNCTION index(X1,Z1,X2,Z2,C : integer) : real;
  453. BEGIN
  454. index:=(raytable[C,2]*(Z1-Zeye)-X1*raytable[C,1])/((X2-X1)*
  455.          raytable[C,1]-(Z2-Z1)*raytable[C,2]);
  456. END;   {given the line X1,Z1,X2,Z2 this function returns the parameter}
  457.        {for the intersection of the line and the ray through coloumb C}
  458.  
  459.  
  460. PROCEDURE Loadtexture(Picture : string);
  461. VAR
  462.  i,j : integer;
  463. BEGIN
  464.  Display(picture,Vaddr,0,0);
  465.  For i:=0 to 128 DO
  466.   For j:=0 to 128 DO
  467.    WallTex[j,i]:=GetPixel(j,i,Vaddr);
  468.  Clear(0,Vaddr);
  469. END;
  470.  
  471.  
  472. PROCEDURE Texturemap(X1,Y1,X2,Y2,X3,Y3,X4,Y4,X1wall,Z1wall,X2wall,Z2wall
  473.                      :integer);
  474. VAR
  475.  Xpos,Ypos,height : real;
  476.  topslope,botslope : real;
  477.  step : real;
  478.  offset: word;
  479.  width : integer;
  480.  i,j : integer;
  481.  
  482. BEGIN
  483.  topslope:=(Y2-Y1)/(X2-X1);
  484.  botslope:=(Y3-Y4)/(X3-X4);
  485.  width:=ABS(X2-X1);
  486.  height:=Y4-Y1+topslope-botslope;
  487.  
  488.  For i:=0 to width DO
  489.   BEGIN
  490.    Ypos:=0;
  491.    Height:=height-topslope+botslope;
  492.    step:=128/height;
  493.    offset:=X1+i+(Round(topslope*i+Y1)*320);
  494.  
  495.    Xpos:=index(X1wall,Z1wall,X2wall,Z2wall,X1+i)*128;
  496.      If Xpos<0 THEN Xpos:=0;      {in case of small rounding-errors}
  497.      If Xpos>128 THEN Xpos:=128;  {we set Xpos to outer rim of texture}
  498.     For j:=0 to Round(height) DO
  499.       BEGIN
  500.        Mem[$a000:offset]:=WallTex[Round(Xpos),Round(Ypos)];
  501.        Inc(offset,320);
  502.        Ypos:=Ypos+step;
  503.       END;
  504.   END;
  505. END;
  506.  
  507.  
  508. Well... off with you !  Go make some stunning games and amaze the world :=)
  509.  
  510.  
  511.  
  512. Last remarks....
  513. -----------------
  514.  
  515. Well, that's about all for now.
  516. Hope you found this doc useful - and BTW : If you DO make anything public using
  517. these techniques please mention me in your greets or where ever you se fit.
  518. I DO love to see my name in a greeting :=)
  519.  
  520. For a simplified demo of my current 3d-engine check out the archive demo.zip
  521. It contains a demo of my wall-drawing routines, but I have left out my monster
  522. routines 'cause they are still under development and the AI is not too great
  523. at this point either :)
  524. Humm.. the GFX is from the computer game MIGHT & MAGIC 4 and 5. I hope New
  525. World Computing won't sue me for using their great gfx in this tut :=)
  526. Even though my engine is running in stepmode these routines should be fast
  527. enough to make a fluid movement engine like DOOM.
  528. I use stepmode 'cause I like that kind of engines and I find them better when
  529. you're writing RPG's and not simple action games.
  530.  
  531.  
  532. As mentioned earlier, I'll do another trainer in near future about memory
  533. management. But if you wish me to continue doing trainers, you'll have to let
  534. me know someone's reading them. Also I would like to know if you find any
  535. errors in this text. No - NOT spelling errors! I live in Denmark, and in DK we
  536. speak DANISH! You're lucky to get this doc in english!
  537. Anyway - respond to this tut, or the serie will probably die!
  538.  
  539.  
  540. Keep on coding and CuL8'er M8's
  541.  
  542. Telemachos - April '97
  543.  
  544.