         Ŀ
  80x50!   How to make a 3D texture mapped tunnel effect  
         

         ... by Ilvatar of Nordic Line (a.k.a. Kari Salminen) 060795


  BTW this the first documentation for an effect I have ever written, because
  usually I just keep those thingies in my mind and don't release them...
  It's 6:30 am at the time I'm writing this so let's get to the point...

  First you'll need about 128Kb of free memory for the precalculations... ;)
  Check... Ok.

  Then you need a nice 256x256/256c. picture to be the texture map...
  Check... Ok.

  So far so fine - but how is the effect done... Ok, a little piece of maths
  is coming right up...

  I suppose that you know the common perspective projection that is :

  (Some variables first though...)
  Xp,Yp = Projected X and Y-coordinates
  X,Y,Z = The original coordinates of a 3D point
  D     = Eye's distance from the projection plane
  P     = Projection plane = screen (Only needed for the picture)

  We can derive from the picture's similar triangles the following stuff :
  (Hey you there look at the nice ascii triangles below!)

   Y     Yp           Y*D
   =   *D  -->   = Yp
  D+Z    D            D+Z



                 /   So the Y-perspective projection calculation is :
                / 
               /     Yp = Y*D/(D+Z)
              /   
             /       And the X is calculated similarly :
            /     
           /         Xp = X*D/(D+Z)
          /      
         /         Check... Ok.
        /       
       /         
      /   Yp     Y
     /           
    /           
   /            
  /             
  
   <--D-->P<--Z-->


  And I suppose that you know something about radians and trigonometry too.
  (More ascii art coming up...)

  In a circle with a radius of 1 the X-coordinate is cos and
                                 the Y-coordinate is sin... simple 8:)


     \             Usually cos=b/c and sin=a/c but when c=1 then
      \                    cos=b/1 and sin=a/1 so it all comes down to
       \ c=radius          cos=b   and sin=a and yet more simplified
        \                  cos=x   and sin=y... great ;)
  a=y    \
          \        Check... Ok.
           \
           \
     
        b=x


  Now you know all the basic math to begin to make the tunnel effecto...

  The tunnel is an infinite series of circles repeated another after
  another. So now we have to make a mathematical equation for the tunnel...
  Let's give it a shot! (BOOM!)

  BTW : We can discard the D from the D+Z (divider) of the perspective
        projection equation. So Xp = X*D/(D+Z) comes Xp = X*D/Z and
        Yp = Y*D/(D+Z) comes Yp = Y*D/Z, this is sufficient for the tunnel
        calculation and works fine otherwise too.
        R = Constant radius of the tunnel (Determined by YOU!).
        D = Eye's constant distance from the screen (Determined by YOU!).
        You can try different values for R and D but I suggest that something
        from 32 to 256 are good values for R and D. More math coming up...


  COS*R*D
   = Xp  (Equation for the projected X-coordinate on the tunnel wall)
      Z


  SIN*R*D
   = Yp  (Equation for the projected Y-coordinate on the tunnel wall)
      Z

  What we now need is the  (angle) and the Z (depth)...
  Let's first solve the Z...
  (You can use the equation with SIN too, if you like to.)


  COS*R*D                                             COS*R*D
   = Xp *Z  -->  Xp*Z = COS*R*D :Xp  -->  Z = 
      Z                                                   Xp

  Ok... And now going for the angle!


  COS*R*D   SIN*R*D            COS   SIN          COS*Yp        
   =  :R*D  -->   =  *Yp -->   = SIN :COS
     Xp         Yp                Xp     Yp              Xp          


  Yp   SIN       Yp                       Yp
   =   -->   = TAN  -->   = ATAN 
  Xp   COS       Xp                       Xp


  Math equations... Check... Ok.

  Now you just go thru the whole screen from
  -WIDTH/2  TO WIDTH/2-1  for the X and
  -HEIGHT/2 TO HEIGHT/2-1 for the Y.

  For a 320x200 screen you would go from -160 to 159 for the X and from -100
  to 99 for the Y.

  And for every pixel you calculate the following :

           Y
   = ATAN   (Calculate this first for every pixel)
           X


  When you calculate this value, the ARCTAN function of you favorite
  programming language will give the angle in radians _VERY_ probably. So we
  need to convert the  from radians to degrees with 256 angles circle. That
  is done by multiplying the  by half of the angles in the circle and
  dividing this by  (pi) -->  = ARCTAN(Y/X)*(256/2)/.
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^

  This is the angle in the tunnel wall at the current pixel. So what do
  we do with it? We must have already allocated a 64Kb precalculation table
  for the angles... So we store this value in the table at the position
  X+WIDTH/2+(Y+HEIGHT/2)*WIDTH... Simple. With a 320x200 screen we would
  put the value to X+160+(Y+100)*320. Remember that X goes from -160 to 159
  and Y from -100 to 99. Angle takes values 0-255. We can think of the angle
  as the X-texture coordinate, so increasing the texture X-coordinate would
  rotate the tunnel.

       COS*R*D
   Z =   (Calculate this too for every pixel)
           X

  Because we have just calculated the  we can put it in this equation and
  voila! It works... (BTW : You _MUST_ use the radian version of the just
  calculated angle value, because SIN and COS functions need their parameters
  in radians. So you should convert angle to degrees only after you have
  calculated this Z-value!) Now we have the Z value too... We must have
  already allocated a 64Kb precalculation table for the depths too... Now we
  put this value in the table at the position X+WIDTH/2+(Y+HEIGHT/2)*WIDTH...
  With a 320x200 screen we would put the value to X+160+(Y+100)*320. Remember
  that X goes from -160 to 159 and Y from -100 to 99. Depth takes values
  0-255. We can think of the depth value as the Y-texture coordinate, so
  increasing the texture Y-coordinate would zoom in the tunnel.

  Once we have gone all this precalculating we just do this :

  We go from 0 to WIDTH-1 for X and from 0 to HEIGHT-1 for Y and
  look up the X-texture coordinate from the angle-lookup-table and
  look up the Y-texture coordinate from the depth-lookup-table. If we want
  to rotate or zoom the tunnel we can add texture-x-adder to the retrieved
  angle value and texture-y-adder to the retrieved depth value. Then we just
  take the pixel from the texture map at the retrieved X and Y coordinates
  and put it onscreen, voila! A rotating and zooming 3D texture mapped tunnel
  with a _FAST_ method... (Needs a bit of precalculating though...;))

  An example in Pascal :

  for y:=0 to 199 do
  for x:=0 to 319 do
  begin
    texture_x:=(angles[x+y*320]+texture_x_adder) and 255;
    texture_y:=(depths[x+y*320]+texture_y_adder) and 255;
    video_screen[x+y*320]:=texture_map[texture_x+texture_y*256];
  end;

  Quite trivial if I wouldn't say...

  PS. There can be some messing around with the arcus tangent function,
      because when I precalculated the angles with Pascal, the tunnel
      went partly to the wrong direction... You can correct this by
      precalculating only one fourth of the precalculation tables and by
      flipping and mirroring that data to construct the other three fourths
      of the precalculation table. Have fun!

  This fast (And quite crappy too I think) explanation of a 3D tunnel effect
  was done by Ilvatar of Nordic Line (a.k.a. Kari Salminen). I was first
  inspired by the CapaCala's "The Real Thing" demo's sewer zoomer part.
  So I went on and thought of ways of doing such an effect and came up with
  this one. After that I have seen this kind of effect in Napalm's "Noname00"
  and Fascination's "Hive" (With some crossfading added though) and in one
  demo by Ground Zero...

  If you want to contact me for some strange reason :

  You can e-mail me at :

  ksalmi@kummeli.edutec.pori.fi  (Primary)
  kari.salminen@under.nullnet.fi (Secondary)

  Or snail mail me at :

  Kari Salminen
  Patsaskuja 17
  29600 Noormarkku
  Finland

  There can be some typos in the text so if something looks _HORRIBLY_ wrong
  then it probably is. After all I hope you figured out those things that I
  wrote about... If you  didn't you can always send me a letter or an e-mail.
  Hope this helped! Have fun and live long (and prosper ;))

  Clock check... 9:19 am, I must be off to sleep now... Bye!

  Ilvatar of Nordic Line 060795