Author Topic: DemoCoding - Tunnel Effect  (Read 7927 times)

0 Members and 1 Guest are viewing this topic.

Offline va!n

  • Pentium
  • *****
  • Posts: 1398
  • Karma: 108
    • View Profile
    • http://www.secretly.de
DemoCoding - Tunnel Effect
« on: May 28, 2007 »
Hi out there...
long time ago, i wrote an article explaining how to to code an oldskool tablebased tunnel effect. the article has been published in the first issue of the german coding magazine "PB.CM"! However, all rights are reserved. The article is sadly only in german - but the sources and its documenations are in english ^^ (if you or someone want to translate my tutorial to english or any other language, please let me know... it would be nice) However, maybe some of you may find the stuff interest enough and can use google translation to understand what i wrote... So lets start the show ;)


Quote
DemoCoding - Tunnel Effect:

Hallo und herzlich willkommen in der Wunderwelt der sogenannten Tabellenbasierten DemoEffekte. Was sind Tabellenbasierte DemoEffekte und warum werden hierfür Tabellen benutzt? Viele ältere DemoEffekte wie Tunnel, Sphere, BumpMap usw. sind oft lediglich 3D fakes und basieren auf vorberechnete 2D Daten, welche für die spätere Verwendung in Tabellen (Arrays) gespeichert werden. Da die benötigen Daten vorberechnet werden, brauchen wir diese später nicht im MainLoop und in Echtzeit immer wieder neu zu berechnen. Hierdurch ersparen wir uns einige Berechnungen und können die Performance des einzelnen Effekts oft um einiges steigern.

Heute werden wir uns Schritt für Schritt die Grundlagen zur Programmierung eines TunnelEffektes anschauen und Schritt für Schritt einen solchen selber Programmieren.

Was brauchen wir überhaupt um unseren ersten TunnelEffekt zu realisieren und wie funktionert dieser Effekt? Der TunnelEffekt an sich besteht aus drei wichtige Elementen. Wir hätten da zum einen die Texture, welche wir später auf unseren Tunnel mappen (kleistern). Als Texture werden wir uns eine eigene 256x256 große - sogenannte XOR - Texture berechnen. Selbstverständlich könnten wir auch einfach per Zufall Punkte, Linien oder Kreise auf unserer Texture zeichen - oder sogar zum Beispiel eine 256x256 große "tileable" Texture als BMP benutzen.

Nun werden wir unsere erste XOR Texture berechnen, in dem wir ein 256x256 großes Image erstellen und dieses nach Fertigstellung auf unserer Festplatte unter ""c:\TunnelFx_Texture.bmp" speichern. Als Ergebniss erhalten wir unsere fertige Texture als BMP Datei.

Code: [Select]
Listing: Part1_Texture.pb

Desweiteren benötigen wir zwei große Texturen (Distance und Angle), die unserer darzustellenden Bildschirmgröße 640x480 entsprechen. Wenn wir uns den Blick in einen runden Tunnel vorstellen, so könnte man dieses mit einer Röhre vergleichen, die aus vielen Ringen besteht und die Ringe mit zunehmender Distance immer kleiner werden. Wir werden nun eine entsprechende "Distance Texture" erstellen und diese ebenfalls als BMP speichern. Um einen kleinen Eindruck zu erhalten, wie eine solche "Distance Texture" ausschaut, einfach die fertige BMP Datei öffnen und anschauen.

Code: [Select]
Listing: Part2_Distance.pb

Nach dem wir nun die "Distance Texture" erstellt haben, benötigen wir noch die sogenannte "Angle-Texture" (Winkel). Diese Texture wird benötigt um unsere XOR Texture im Tunnel richtig anzupassen und unseren Tunnel später u.a. rotieren zu lassen. Die "Distance Texture" wird u.a. benötigt, um in den Tunnel zu fliegen.

Code: [Select]
Listing: Part3_Angle.pb

Bisher haben wir die drei wichtigsten Elemente für einen TunnelEffekt und ihre jeweiligen Routinen kennengelernt, dessen Ergebnisse wir bisher immer auf eine Bitmap darstellen und als BMP speichern. Nun werden wir die berechneten Daten direkt die Tabellen (Arrays) "aTexture", "aDistance" und "aAngle" speichern und  die einzelnen Routinen von Part1-Part3 zusammenlegen und somit ein wenig optimieren. Im SourceCode von Part1 erstellen wir unsere 256x256 große XOR Texture, bei der wir die x und y Schleife von 0 bis 255 durchlaufen lassen. Da wir keine weitere Routine verwenden, in der wir ebenfalls von 0 bis 255 zählen, lassen wir diese Routine wie zuvor unverändert.

Allerdings verwenden wir für die Berechnung der "Distance Table" und "Angle Table" in beiden Fällen Schleifen, dessen Werte in beiden Routinen identisch sind. Daher können wir diese beiden Routine ohne Probleme zusammenfassen und uns Zeit für die Vorberechnung sparen und kleineren Programmcode erzeugen.

Code: [Select]
Listing: Part4_MergingStuff.pb

Wir werden das bisher gelernte nun anwenden, einen Screen öffnen  und das erste Resultat unseres Tunnels auf dem Bildschirm darstellen.
Um den Programmcode einfacher zu lesen, werden wir einfach den Plot() Befehl verwenden und nicht auf DirectScreenAccess aufbauen.

Mit unserer "aDistance" und "aAngle" Table können wir nun ohne Probleme einen Tunnel darstellen. Damit nun aber auch unsere 256x256 große XOR Texture (aTexture) im Tunnel richtig gemapped (abgebildet) wird, werden wir diese beiden Tabellen im Innerloop einfach auslesen und wir erhalten die entsprechende X und Y Koddinaten unserer XOR Texture. Das Ergebniss speichern wir in unsererm Array aBuffer, welches wir zuvor noch zu unserem Code hinzufügen müssen! Wir könnten nun in unserem aBuffer weitere Manipulationen vornehmen oder das Ergebniss wie in der nächsten Zeile zu sehen ist, mit Plot() auf den Bildschirm darstellen lassen.

Code: [Select]
        aBuffer(x,y) = aTexture (aDistance(x,y), aAngle(x,y))
        Plot(x, y, aBuffer(x,y) )

Der komplette Sourcecode würde nun wie folgt aussehen und wir würdeb beim ausführen des Sources ein Standbild des TunnelEffektes erhalten..

Code: [Select]
Listing:  Part5_FirstTunnel.pb

Um unseren Tunnel nun zu animieren, werden wir diesen drehen lassen und dabei in den Tunnel hineinfliegen. Hierzu benötigen wir die Variablen dSpeedX.d und SpeedY.d, um die Geschwindigkeit für die X und Y Bewegung des Tunnels zu defininieren.  Desweiteren benötigen wir im Innerloop die Variablen lShiftX.l und lShiftY.l, um die entsprechenden Bewegungen in den Tabellen zu berechnen und später auszulesen. In unserem Beipspiel werden wir für die Animation die Variable dAnimation.d nehmen, welche wir pro Loop um 0.005 erhöhen! (Anmerkung: Bitte für eigene Projekte mit DeltaTimes arbeiten, damit der Effekt auf jeden Rechner gleich schnell läuft!).

Code: [Select]
  dAnimation.d = dAnimation.d + 0.005           
  If dAnimation.d >= 1.0 : dAnimation = 0.0 : EndIf
 
  lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d)
  lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)

Nun haben wir alle wichtigen Berechnungen vorgenommen, damit der Tunnel animiert werden kann. Um nicht wieder wie zuvor nur ein Standbild zu erhalten, müssen wir bei der Darstellung des Tunnels folgende Zeilen hinzufügen bzw abändern.

Code: [Select]
    lCoordinateX.l = (aDistance(x,y) + lShiftX) % lTextureSize   
    lCoordinateY.l = (aAngle(x,y)    + lShiftY) % lTextureSize 
    aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l)
    Plot(x, y, RGB(0, 0, aBuffer(x,y) ))

Der komplette Sourcecode für einen komplett animierten Tunnel, würde nun wie folgt aussehen:

Code: [Select]
Listing:  Part6_AnimateTunnel.pb

An dieser Stelle sind wir nun bei unseren animierten Tunnel angelangt. Leider wirkt das ganze auf eine Art doch noch ein etwas langweilig. Um unseren aktuellen
animierten Tunnel noch ein wenig aufzumotzen und interessanter wirken zu lassen, werden wir ein paar kleine Änderungen vornehmen. Dabei werden wir den
eigentichen Tunnel tanzen (bzw bewegen) lassen. Es ensteht der Eindruck, als würde man die Kamera im Tunnel bewegen ;-)

Da unserer Tunnel nur auf Tables und nicht auf echtes 3D basiert, werden sich nun sicher einige Fragen, wie man den Effekt mit der Kamera umsetzen will. Wir werden hierfür einen absolut einfachen und zugleich fiesen Trick verwenden. Unser Bildschirm und unserer aDistance und aAngle Tables sind alle für 640x480 ausgelegt. Wir werden nun die Breite und Höhe der Tables aDistance und aAngle verdoppeln, um später immer nur den gewünschten Ausschnitt auf den Bildschirm darzustellen.

Code: [Select]
    Dim aDistance (lScreenWidth*2, lScreenHeight*2)
    Dim aAngle    (lScreenWidth*2, lScreenHeight*2)

Bei den Berechnungen unserer aDistance und aAngle Tables, haben wir bisher z.B. immer "lScreenWidth / 2" (geteilt durch 2) gerechnet, da lScreenWidth mit der Größe von aDistance und aAngle waren. Da wir aber nun die Größe von aDistance und aAngle verdoppelt haben, brauchen wir bei der Berechnung dieser Tabellen nicht mehr "/ 2" (geteilt durch 2) rechnen!! Vorsicht!

Um unseren Tunnel nun schön tanzen zu lassen, verwenden wir einfach SIN() und fügen die Variablen lLookX und lLookY hinzu. Dafür werden folgende Zeilen geändert:

Code: [Select]
    lLookX = lScreenWidth /2 + Int(lScreenWidth /2 * Sin(dAnimation * 4.0 ))
    lLookY = lScreenHeight/2 + Int(lScreenHeight/2 * Sin(dAnimation * 6.0 ))

Bei der Darstellung des Tunnels müssen wir nun selbstverständlich die Werte lLookX und lLookY berücksichtigen. Dafür ändern wir den Code wie folgt ab:

Code: [Select]
    lCoordinateX.l = (aDistance(x+lLookX, y+lLookY) + lShiftX) % lTextureSize     
    lCoordinateY.l = (aAngle   (x+lLookX, y+lLookY) + lShiftY) % lTextureSize   

Wenn jetzt keine Fehler unterlaufen sind, sollten wir nun einen schönen texturierten und  animierten Tunnel haben, dessen Kameraposition sich ständig zu verändern scheint. Hier nun nochmal der komplette Sourcecode:

Code: [Select]
Listing:  Part7_MovingTunnel.pb

Ich hoffe, das dieses Tutorial halbwegs verständlich gestaltet ist und den einen oder anderen gefällt. Viel Spaß, Thorsten Will aka va!n.
 


Sources and Tutorial (c) by Thorsten Will aka va!n
All rights reserved.



Part1_Texture.pb
Code: [Select]
; *************************************************************************************
; *   P r o j e c t :    T u n n e l - F x
; *************************************************************************************
; *
; *   Part1: Creating Mapping Texture:
; *   --------------------------------
; *   This small example shows you, how to create an easy XOR 256x256 sized texture.
; *   We will use this texture later for texturemapping of our tunnel. Ofcourse you
; *   can use any other created or loaded tileable texture too :)
; *
; *   Source and Tutorial (c) by Thorsten Will aka va!n
; *   All rights reserved.
; *
; *************************************************************************************

lTextureSize.l  = 256                     
CreateImage (0, lTextureSize, lTextureSize)
 
; -------- Generating Mapping Texture --------

StartDrawing(ImageOutput(0))               

  For y.l = 0 To lTextureSize -1     
    For x.l = 0 To lTextureSize -1
      lColor.l = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)                     
      Plot (x, y, RGB( 0, 0, lColor.l) )               
    Next
  Next

StopDrawing()

; -------- Saving Texture --------

SaveImage (0, "c:\TunnelFx_Texture.bmp")               
End

; *************************************************************************************


Part2_Distance.pb
Code: [Select]
; *************************************************************************************
; *   P r o j e c t :    T u n n e l - F x   
; *************************************************************************************
; *
; *   Part2: Creating Distance Table / Texture:
; *   -----------------------------------------
; *   This small example shows you, how to to create the needed distance table and how
; *   does this looks like for doing the flying trip into our tunnel.
; *
; *   Source and Tutorial (c) by Thorsten Will aka va!n
; *   All rights reserved.
; *
; *************************************************************************************

lTextureSize.l  = 256
lScreenWidth.l  = 640
lScreenHeight.l = 480

CreateImage (0, lScreenWidth, lScreenHeight)
 
; -------- Generating Distance Table / Texture --------

StartDrawing(ImageOutput(0))

  dDistance.d = 32.0
           
  For x = 0 To lScreenWidth -1     
    For y = 0 To lScreenHeight -1
      lColor.l = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth/2) * (x-lScreenWidth/2) + (y-lScreenHeight/2) * (y-lScreenHeight/2) )) % lTextureSize
      Plot (x, y, RGB(lColor, lColor, lColor) )
    Next
  Next

StopDrawing()
   
; -------- Saving Table as Texture --------

SaveImage (0, "c:\TunnelFx_Distance.bmp")
End

; *************************************************************************************



Part3_Angle.pb
Code: [Select]
; *************************************************************************************
; *   P r o j e c t :    T u n n e l - F x   
; *************************************************************************************
; *
; *   Part3: Creating Angle Table / Texture:
; *   --------------------------------------
; *   This small example shows you, how to to create the needed angle table and how
; *   does this looks like for doing the rotations of our tunnel. Dont forget to enable
; *   inline assembler. Otherwise as you see, you will see nothing. :D
; *
; *   Source and Tutorial (c) by Thorsten Will aka va!n
; *   All rigths reserved.
; *
; *************************************************************************************

Procedure.d ATan2(y.d, x.d)
  !FLD qword[p.v_y]
  !FLD qword[p.v_x]
  !FPATAN
  ProcedureReturn
EndProcedure

; -------- Init Code --------

lTextureSize.l  = 256
lScreenWidth.l  = 640
lScreenHeight.l = 480

CreateImage (0, lScreenWidth, lScreenHeight)
 
; -------- Generating Angle Table / Texture --------

StartDrawing(ImageOutput(0))

   dParts.d = 0.5

   For x = 0 To lScreenWidth -1             
     For y = 0 To lScreenHeight -1
       dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight/2, x-lScreenWidth/2) / #PI)
       lColor = Int (256 - dAngle) & 255
       Plot (x, y, RGB(lColor, lColor, lColor) )
     Next
   Next

StopDrawing()

; -------- Saving Table as Texture --------

SaveImage (0, "c:\TunnelFx_Angle.bmp")
End

; *************************************************************************************



Part4_MergingStuff.pb
Code: [Select]
; *************************************************************************************
; *   P r o j e c t :    T u n n e l - F x
; *************************************************************************************
; *
; *   Part4: Merging routines from Part1-Part3 into two single loops:
; *   ---------------------------------------------------------------
; *   Now we are going to optimize our stuff from Part1-Part3 while merging Part2 and
; *   Part3 into just a single loop and storing the data from Part1-Part3 directly into
; *   our defined arrays. Merging Part2 with Part3 will reduce the generated ASM output
; *   and increase the speed of our table pre-generation.
; *
; *   Source and Tutorial (c) by Thorsten Will aka va!n
; *   All rights reserved.
; *
; *************************************************************************************

Procedure.d ATan2(y.d, x.d)
  !FLD qword[p.v_y]
  !FLD qword[p.v_x]
  !FPATAN
  ProcedureReturn
EndProcedure

; -------- Init Code --------

lTextureSize.l  = 256
lScreenWidth.l  = 640
lScreenHeight.l = 480

Dim aTexture  (lTextureSize, lTextureSize)
Dim aDistance (lScreenWidth, lScreenHeight)
Dim aAngle    (lScreenWidth, lScreenHeight)
 
; -------- Generating Mapping Texture --------

For x.l = 0 To lTextureSize -1
  For y.l = 0 To lTextureSize -1
    aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)               
  Next
Next

; -------- Generating Distance and Angle Table --------

dDistance.d = 32.0
dParts.d    =  0.5
         
For x = 0 To lScreenWidth -1     
  For y = 0 To lScreenHeight -1
    aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth/2) * (x-lScreenWidth/2) + (y-lScreenHeight/2) * (y-lScreenHeight/2) )) % lTextureSize
    dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight/2, x-lScreenWidth/2) / #PI)
    aAngle(x,y) = Int (256 - dAngle) & 255
  Next
Next
 
; *************************************************************************************



Part5_FirstTunnel.pb
Code: [Select]
; *************************************************************************************
; *   P r o j e c t :    T u n n e l - F x
; *************************************************************************************
; *
; *   Part5: Showing our first tunnel:
; *   --------------------------------
; *   As we learned in the first three basic tutorials, we need one texture and two
; *   table based datas (aDistance and aAngle), also two images to produce our tunnel
; *   like effect. Now we will try to merge this knowledge to produce our first tunnel
; *   like effect in real on our screen :) Dont forget to enable inline ASM.
; *
; *   Source and Tutorial (c) by Thorsten Will aka va!n
; *   All rights reserved.
; *
; *************************************************************************************

Procedure.d ATan2(y.d, x.d)
  !FLD qword[p.v_y]
  !FLD qword[p.v_x]
  !FPATAN
  ProcedureReturn
EndProcedure

; -------- Init Code --------

lTextureSize.l  = 256
lScreenWidth.l  = 640
lScreenHeight.l = 480

Dim aTexture  (lTextureSize, lTextureSize)
Dim aDistance (lScreenWidth, lScreenHeight)
Dim aAngle    (lScreenWidth, lScreenHeight)
Dim aBuffer   (lScreenWidth, lScreenHeight)

; -------- Generating Mapping Texture --------

For x.l = 0 To lTextureSize -1
  For y.l = 0 To lTextureSize -1
    aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
  Next
Next

; -------- Generating Distance and Angle Table --------

dDistance.d = 32.0
dParts.d    =  0.5
         
For x = 0 To lScreenWidth -1     
  For y = 0 To lScreenHeight -1
    aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth/2) * (x-lScreenWidth/2) + (y-lScreenHeight/2) * (y-lScreenHeight/2) )) % lTextureSize
    dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight/2, x-lScreenWidth/2) / #PI)
    aAngle(x,y) = Int (256 - dAngle) & 255
  Next
Next
 
; *************************************************************************************

InitSprite()
OpenScreen(lScreenWidth, lScreenHeight, 32, "TunnelFx Tutorial")

Repeat

  ; -------- Calculate Texture coordinates and draw Tunnel -------

  StartDrawing(ScreenOutput())
    For x = 0 To lScreenWidth -1
      For y = 0 To lScreenHeight-1
        aBuffer(x,y) = aTexture (aDistance(x,y), aAngle(x,y))
        Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
      Next
    Next
  StopDrawing()

  FlipBuffers(2)
Until GetAsyncKeyState_(#VK_ESCAPE)

; *************************************************************************************



Part6_AnimateTunnel.pb
Code: [Select]
; *************************************************************************************
; *   P r o j e c t :    T u n n e l - F x
; *************************************************************************************
; *
; *   Part6: Lets animate the tunnel:
; *   -------------------------------
; *   After turorial part5, we will try to alive the tunnel and animate it a litte bit.
; *
; *   Source and Tutorial (c) by Thorsten Will aka va!n
; *   All rights reserved.
; *
; *************************************************************************************

Procedure.d ATan2(y.d, x.d)
  !FLD qword[p.v_y]
  !FLD qword[p.v_x]
  !FPATAN
  ProcedureReturn
EndProcedure

; -------- Init Code --------

lTextureSize.l  = 256
lScreenWidth.l  = 640
lScreenHeight.l = 480

Dim aTexture  (lTextureSize, lTextureSize)
Dim aDistance (lScreenWidth, lScreenHeight)
Dim aAngle    (lScreenWidth, lScreenHeight)
Dim aBuffer   (lScreenWidth, lScreenHeight)

; -------- Generating Mapping Texture --------

For x.l = 0 To lTextureSize -1
  For y.l = 0 To lTextureSize -1
    aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
  Next
Next

; -------- Generating Distance and Angle Table --------

dDistance.d = 32.0
dParts.d    =  0.5
         
For x = 0 To lScreenWidth -1     
  For y = 0 To lScreenHeight -1
    aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth/2) * (x-lScreenWidth/2) + (y-lScreenHeight/2) * (y-lScreenHeight/2) )) % lTextureSize
    dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight/2, x-lScreenWidth/2) / #PI)
    aAngle(x,y) = Int (256 - dAngle) & 255
  Next
Next
 
; *************************************************************************************

InitSprite()
OpenScreen(lScreenWidth, lScreenHeight, 32, "TunnelFx Tutorial")

dSpeedX.d = 2.0
dSpeedY.d = 2.0

Repeat
  ; ------- Stuff for doing the animation -------
 
  dAnimation.d = dAnimation.d + 0.005                 ; timeGetTime_() / 1000
  If dAnimation.d >= 1.0 : dAnimation = 0.0 : EndIf
 
  lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d)
  lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)

  ; -------- Calculate Texture coordinates and draw Tunnel -------

  StartDrawing(ScreenOutput())
    For x = 0 To lScreenWidth -1
      For y = 0 To lScreenHeight-1
        lCoordinateX.l = (aDistance(x,y) + lShiftX) % lTextureSize     
        lCoordinateY.l = (aAngle(x,y)    + lShiftY) % lTextureSize     
        aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l)
        Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
      Next
    Next
  StopDrawing()

  FlipBuffers(1)
Until GetAsyncKeyState_(#VK_ESCAPE)

; *************************************************************************************



Part7_MovingTunnel.pb
Code: [Select]
; *************************************************************************************
; *   P r o j e c t :    T u n n e l - F x
; *************************************************************************************
; *
; *   Part7: Moving Tunnel:
; *   ---------------------
; *   This is the last turorial part, where we will try to get the tunnel fx more
; *   interesting while moving the tunnel, by using SIN().
; *
; *   Source and Tutorial (c) by Thorsten Will aka va!n
; *   All rights reserved.
; *
; *************************************************************************************

Procedure.d ATan2(y.d, x.d)
  !FLD qword[p.v_y]
  !FLD qword[p.v_x]
  !FPATAN
  ProcedureReturn
EndProcedure

; -------- Init Code --------

lTextureSize.l  = 256
lScreenWidth.l  = 640
lScreenHeight.l = 480

Dim aTexture  (lTextureSize  , lTextureSize   )
Dim aDistance (lScreenWidth*2, lScreenHeight*2)
Dim aAngle    (lScreenWidth*2, lScreenHeight*2)
Dim aBuffer   (lScreenWidth  , lScreenHeight  )

; -------- Generating Mapping Texture --------

For x.l = 0 To lTextureSize -1
  For y.l = 0 To lTextureSize -1
    aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
  Next
Next

; -------- Generating Distance and Angle Table --------

dDistance.d = 32.0
dParts.d    =  0.5
         
For x = 0 To lScreenWidth*2 -1     
  For y = 0 To lScreenHeight*2 -1
    aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth) * (x-lScreenWidth) + (y-lScreenHeight) * (y-lScreenHeight) )) % lTextureSize
    dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight, x-lScreenWidth) / #PI)
    aAngle(x,y) = Int (256 - dAngle) & 255
  Next
Next

; *************************************************************************************

InitSprite()
OpenScreen(lScreenWidth, lScreenHeight, 32, "TunnelFx Tutorial")

dSpeedX.d = 2.0
dSpeedY.d = 2.0

Repeat
  ; ------- Stuff for doing the animation -------
 
  dAnimation.d = dAnimation.d + 0.005
 
  lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d)
  lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)

  lLookX = lScreenWidth /2 + Int(lScreenWidth /2 * Sin(dAnimation * 4.0 ))
  lLookY = lScreenHeight/2 + Int(lScreenHeight/2 * Sin(dAnimation * 6.0 ))

  ; -------- Calculate Texture coordinates and draw Tunnel -------

  StartDrawing(ScreenOutput())
    For y = 0 To lScreenHeight-1
      For x = 0 To lScreenWidth -1
        lCoordinateX.l = (aDistance(x+lLookX, y+lLookY) + lShiftX) % lTextureSize     
        lCoordinateY.l = (aAngle   (x+lLookX, y+lLookY) + lShiftY) % lTextureSize     
        aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l)
        Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
      Next
    Next
  StopDrawing()

  FlipBuffers(1)
Until GetAsyncKeyState_(#VK_ESCAPE)

; *************************************************************************************



Have phun... if you have any optimisation ideas or better ways to do this, let me know...
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1398
  • Karma: 108
    • View Profile
    • http://www.secretly.de
Re: DemoCoding - Tunnel Effect
« Reply #1 on: May 28, 2007 »
Ok, here you can download a ZIP that contains all needed files (german tutorial, all sources and executable files) ^^

www.secretly.de/public/OldSkool_TunnelFX.zip   ~43 kb Zip
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: DemoCoding - Tunnel Effect
« Reply #2 on: May 28, 2007 »
Cool, thanks va!n!

Jim
Challenge Trophies Won:

Offline ninogenio

  • Pentium
  • *****
  • Posts: 1666
  • Karma: 133
    • View Profile
Re: DemoCoding - Tunnel Effect
« Reply #3 on: May 28, 2007 »
cool! an xor textured spherical tunnel!

thanks for sharing that va!n!
Challenge Trophies Won:

Offline benny!

  • Senior Member
  • DBF Aficionado
  • ********
  • Posts: 4380
  • Karma: 228
  • in this place forever!
    • View Profile
    • bennyschuetz.com - mycroBlog
Re: DemoCoding - Tunnel Effect
« Reply #4 on: May 28, 2007 »
K++ ... thanks for sharing, va!n. Good work!
[ mycroBLOG - POUET :: whatever keeps us longing - for another breath of air - is getting rare ]

Challenge Trophies Won:

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17376
  • Karma: 497
  • evil/good
    • View Profile
    • My Homepage
Re: DemoCoding - Tunnel Effect
« Reply #5 on: May 28, 2007 »
Great Xor tunnel Vain, thank you for the tutorial! It gives me the chance to brush up a little on my German too!


Always liked these texture tunnels. Nicely commented code too so that has to be worth some Karma.

Also I am changing your status on the board to "Contributing Author".

Thank you for your work.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17376
  • Karma: 497
  • evil/good
    • View Profile
    • My Homepage
Re: DemoCoding - Tunnel Effect
« Reply #6 on: May 28, 2007 »
Btw, I will format that tutorial up and include it on the front page as soon as I get chance!
Shockwave ^ Codigos
Challenge Trophies Won:

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Re: DemoCoding - Tunnel Effect
« Reply #7 on: May 28, 2007 »
Excellent effect and well done on the article it runs really smooth and the tunnel seems to go on and on forever :D an excelent addition to the tutorial section

Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1398
  • Karma: 108
    • View Profile
    • http://www.secretly.de
Re: DemoCoding - Tunnel Effect
« Reply #8 on: May 28, 2007 »
many thanks for all your nice and posetiv feedbacks! :)

@shockwave:
"Also I am changing your status on the board to "Contributing Author" <<  WOW! O.O I am speakless... many thanks! :)
Btw, if you want format the tutorial and if you plan to do an english version, i could try to create an english version and you could correct the text if you want, because my english isnt really good ^^
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: DemoCoding - Tunnel Effect
« Reply #9 on: May 28, 2007 »
I'll meet you halfway, I bet your English is a lot better than mine (and Google's) German.

Quote
Hello and cordially welcomely in the miracle world of the so-called table-based demo effects. What are table-based demo effects and why are tables used for this? Many older demo effects such as tunnel, Sphere, BumpMap etc. are often only 3D fakes and are based on pre-computed 2D data, which are stored for later use in tables (arrays). Since the data are pre-computed, we do not need to compute them later in the main loop in real time again and again again. Thereby we save some computations and can often increase the performance of the individual effect.
Today we will look at the step-by-step basics for the programming of a tunnel effect.
What do we need to know about our first tunnel effect and how it functions? The tunnel effect actually consists of three important elements. On one hand we have the Texture, which we later map on to our tunnel. For the Texture we will compute our own 256x256 - so-called XOR - Texture. Of course we could use a 256x256 “tileable� Texture also simply by drawing points, lines or circles on our Texture - or we could even use a BMP.
Now we will compute our first XOR Texture, in which we provide a 256x256 image and store it on the hard disk under "c:\TunnelFx _Texture.bmp".
Code: [Select]
Listing: Part1_Texture.pbFurthermore we need two large textures (Distance and Angle), which correspond to our screen size of 640x480. If we imagine the view is a round tunnel, then we could compare this with a tube, which consists of many rings and which rings with increasing Distance become ever smaller. We will generate now an appropriate “Distance Texture� and will likewise store these as BMP. To get an idea what it looks like, you can open the “Distance Texture� BMP in an image viewer.
Code: [Select]
Listing: Part2_Distance.pbNow we've generated the “Distance Texture�, we need the so-called “Angle Texture�. To wrap the Texture around our XOR Texture in the tunnel correctly and among other things to let our tunnel rotate. The “Distance Texture� is needed among other things, in order to make the tunnerl fly.
Code: [Select]
Listing: Part3_Angle.pbSo far we have become acquainted with the three most important elements for a tunnel effect and their respective routines, whose results we've represented on a bitmap and stored as BMP. Now we will store the computed data directly the arrays “aTexture�, “aDistance� and “aAngle� and will join together the individual routines of Part1-Part3 with a little optimisation. In the source code of Part1 we provide our 256x256 XOR Texture, with which we let the x and y loop from 0 to 255. We leave this unchanged, however because the same loops for computing the “Distance Table� and “fish Table� we put the code for them in the same loop as the XOR Texture. Therefore we can combine these two routines without problems and now it's time to work on the pre-calculation savings and smaller code.
Code: [Select]
Listing: Part4_MergingStuff.pbWe will now apply what we've learned the so far. We will open a screen and will draw the first output of our tunnel to the screen. In order to read the program code more simply, we will use the Plot() function and not direct screen access. With our “aDistanceâ€? and “aAngleâ€? arrays we can now easily draw a tunnel. Thus now together we use these two tables in the inner loop to select the appropriate X and Y coordinates of our 256x256 XOR Texture.  Once we've done that we can put the value in the aBuffer, which we still have to add to our code! We could now  make further manipulations on the output to the output before we write it to the screen using Plot().
Code: [Select]
aBuffer (x, y) = aTexture (aDistance (x, y), aAngle (x, y))
Plot (x, y, aBuffer (x, y))
The complete source code would now look as follows which will show us a fixed image of the tunnel effect .
Code: [Select]
Listing: Part5_FirstTunnel.pbWe're going to animate our tunnel now, and make it look like we're flying into it. For this we need the variables dSpeedX.d and dSpeedY.d, which are the speed for the X and Y movement around those axes. Furthermore we need the variables in the inside loop lShiftX.l and lShiftY.l, in order to compute and later pick the appropriate movements from the arrays. In our example we will take the variable dAnimation.d, which we increase per loop by 0.005 for the animation! (Note: For your own projects, work with delta timing, so the effect on each computer runs correctly!).
Code: [Select]
dAnimation.d = dAnimation.d + 0.005
If dAnimation.d >= 1.0 : dAnimation = 0.0 : EndIf
lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d)
lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)
Now we have made all important computations, so that the tunnel can be animated. In order not to just get one fixed image, we must add and/or change the following lines during the representation of the tunnel.
Code: [Select]
lCoordinateX.l = (aDistance(x,y) + lShiftX) % lTextureSize
lCoordinateY.l = (aAngle(x,y) + lShiftY) % lTextureSize
aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l)
Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
The complete source code for a completely animated tunnel, would look as follows:
Code: [Select]
Listing: Part6_AnimateTunnel.pbHere we have animated tunnel. Unfortunately the whole effect is somewhat nevertheless still boring. In order to make our current animated tunnel still more funky and more interesting, we can make a few small changes. We will make tunnel to move up and down to give the impresson of the camera moving in the tunnel ;-) Since our tunnel's only made from arrays and not from genuine 3D, some questions become now need to be asked  as one wants to convert the effect with the camera. We will use for this an absolutely simple and at the same time safe trick. As our aDistance and aAngle arrays are suitable only for a screen of 640x480, we will double now the width and height of the them, in order to represent in each case the desired section later on the screen.
Code: [Select]
Dim aDistance (lScreenWidth*2, lScreenHeight*2)
Dim aAngle (lScreenWidth*2, lScreenHeight*2)
With the computations our, we so far e.g. always counted aDistance and aAngle Tables “lScreenWidth/2â€? (divided by 2), since lScreenWidth was the size of aDistance and aAngle. However since we've now doubled the size of aDistance and aAngle, we do not need to "/ 2" (divided by 2) with the computation of these tables any longer!! Caution! In order to let our tunnel dance beautifully  now, we use simply SIN () and add the variables lLookX and lLookY. The following lines are changed:
Code: [Select]
lLookX = lScreenWidth /2 + Int(lScreenWidth /2 * Sin(dAnimation * 4.0 ))
lLookY = lScreenHeight/2 + Int(lScreenHeight/2 * Sin(dAnimation * 6.0 ))
During the drawing of the tunnel we must now change the values lLookX and lLookY to make it look natural. We change the code as follows:
Code: [Select]
lCoordinateX.l = (aDistance(x+lLookX, y+lLookY) + lShiftX) % lTextureSize
lCoordinateY.l = (aAngle (x+lLookX, y+lLookY) + lShiftY) % lTextureSize
If we haven't made any mistakes now, we should have now a beautiful texturemapped and animated tunnel, whose camera position seems to constantly change. Here now again is the complete source code:
Code: [Select]
Listing: Part7_MovingTunnel.pbI hope you and others enjoy this tutorial,
Much fun, Thorsten Will aka va! n.


Jim
Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1398
  • Karma: 108
    • View Profile
    • http://www.secretly.de
Re: DemoCoding - Tunnel Effect
« Reply #10 on: June 17, 2007 »
@Jim:
Cool.... very nice... thanks!  :goodpost:
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline energy

  • Amiga 1200
  • ****
  • Posts: 280
  • Karma: 25
    • View Profile
Re: DemoCoding - Tunnel Effect
« Reply #11 on: August 18, 2007 »
super effect!
 ;)
coding: jwasm,masm
hobby: www.scd2003.de

Offline DeXtr0

  • C= 64
  • **
  • Posts: 79
  • Karma: 4
  • Proud member of dAWN
    • View Profile
    • dAWN Creations
Re: DemoCoding - Tunnel Effect
« Reply #12 on: August 18, 2007 »
Ow yeaahhh this is awesome and a much seen effect "in the amiga days"  :D

Thanks a lot va!n. Really helpfull !

Cheers,
DeXtr0

Offline Clyde

  • A Little Fuzzy Wuzzy
  • DBF Aficionado
  • ******
  • Posts: 7271
  • Karma: 71
    • View Profile
Re: DemoCoding - Tunnel Effect
« Reply #13 on: August 20, 2007 »
Nifty Tutorial Va!n :)
Karma++
Still Putting The IT Into Gravy
If Only I Knew Then What I Know Now.

Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1398
  • Karma: 108
    • View Profile
    • http://www.secretly.de
Re: DemoCoding - Tunnel Effect
« Reply #14 on: July 27, 2009 »
maybe a bit old but what about to add this to the new tutorial section?
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17376
  • Karma: 497
  • evil/good
    • View Profile
    • My Homepage
Re: DemoCoding - Tunnel Effect
« Reply #15 on: July 27, 2009 »
I'd love to put it in the tutorials section mate, that's very generous of you. The English translation of it needs to be looked over first and edited if necessary, but once we have a more readable version I'll love to see it on the front page.

Shockwave ^ Codigos
Challenge Trophies Won:

Offline ~Ar-S~

  • C= 64
  • **
  • Posts: 44
  • Karma: 26
  • Demo RuleZ
    • View Profile
Re: DemoCoding - Tunnel Effect
« Reply #16 on: April 23, 2019 »
I almost missed that great tutorial. Thank you Mr Va!n
I know this topic is very old but the same tutorial for a dot tunnel would be great.
thank you for sharing your knowledge.

Here is just a little 5.70 compatible modification

Code: [Select]
; *************************************************************************************
; *   P r o j e c t :    T u n n e l - F x
; *************************************************************************************
; *
; *   Part7: Moving Tunnel:
; *   ---------------------
; *   This is the last turorial part, where we will try to get the tunnel fx more
; *   interesting while moving the tunnel, by using SIN().
; *
; *   Source and Tutorial (c) by Thorsten Will aka va!n
; *   All rights reserved.
; *
; *************************************************************************************


DisableDebugger

; -------- Init Code --------

lTextureSize.l  = 256
lScreenWidth.l  = 640
lScreenHeight.l = 480

Dim aTexture  (lTextureSize  , lTextureSize   )
Dim aDistance (lScreenWidth*2, lScreenHeight*2)
Dim aAngle    (lScreenWidth*2, lScreenHeight*2)
Dim aBuffer   (lScreenWidth  , lScreenHeight  )

; -------- Generating Mapping Texture --------

For x.l = 0 To lTextureSize -1
  For y.l = 0 To lTextureSize -1
    aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
  Next
Next

; -------- Generating Distance and Angle Table --------

dDistance.d = 32.0
dParts.d    =  0.5
         
For x = 0 To lScreenWidth*2 -1     
  For y = 0 To lScreenHeight*2 -1
    aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth) * (x-lScreenWidth) + (y-lScreenHeight) * (y-lScreenHeight) )) % lTextureSize
    dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight, x-lScreenWidth) / #PI)
    aAngle(x,y) = Int (256 - dAngle) & 255
  Next
Next

; *************************************************************************************

InitSprite()

OpenWindow(0,0,0,lScreenWidth,lScreenHeight,"",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,lScreenWidth, lScreenHeight,0,0,0,#PB_Screen_WaitSynchronization )

dSpeedX.d = 1.0
dSpeedY.d = 1.0

Repeat
  ; ------- Stuff for doing the animation -------
 
  dAnimation.d = dAnimation.d + 0.005
 
  lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d)
  lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)

  lLookX = lScreenWidth /2 + Int(lScreenWidth /2 * Sin(dAnimation * 4.0 ))
  lLookY = lScreenHeight/2 + Int(lScreenHeight/2 * Sin(dAnimation * 6.0 ))

  ; -------- Calculate Texture coordinates and draw Tunnel -------

  StartDrawing(ScreenOutput())
    For y = 0 To lScreenHeight-1
      For x = 0 To lScreenWidth -1
        lCoordinateX.l = (aDistance(x+lLookX, y+lLookY) + lShiftX) % lTextureSize     
        lCoordinateY.l = (aAngle   (x+lLookX, y+lLookY) + lShiftY) % lTextureSize     
        aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l)
        Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
      Next
    Next
  StopDrawing()

  FlipBuffers()
Until GetAsyncKeyState_(#VK_ESCAPE)

; *************************************************************************************
~ Ar-S ~

Offline aNdy

  • C= 64
  • **
  • Posts: 63
  • Karma: 27
    • View Profile
Re: DemoCoding - Tunnel Effect
« Reply #17 on: April 25, 2019 »
Oh wow! Thanks ~Ar-S~ for the update!   :cheers:

Offline va!n

  • Pentium
  • *****
  • Posts: 1398
  • Karma: 108
    • View Profile
    • http://www.secretly.de
Re: DemoCoding - Tunnel Effect
« Reply #18 on: April 25, 2019 »
@~Ar-S~:
Thanks for your reply to this really old topic and nice you liked the tutorial ;-)
Due fact of health and time problems, i cant do a tutorial for a dot tunnel atm and probaly for the next 12 month.
There are another two very old projects i would still like to continue from time to time.

I continue to fight and wish that someday there will be a few small steps forward in terms of my health.
Then I would like to create more tutorials.

Thanks for the PB v5.70 compatible modification
« Last Edit: April 25, 2019 by va!n »
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline aNdy

  • C= 64
  • **
  • Posts: 63
  • Karma: 27
    • View Profile
Re: DemoCoding - Tunnel Effect
« Reply #19 on: April 25, 2019 »
My apologies, of course thanks to va!n for the original code!