A játék arról szól, hogy egy cső belsejét kellene látni a monitoron. Mindenki el tudja képzelni, olyan, mintha egy alagútban lennénk. Szokták nevezni alagút vagy tunnel effektnek is. Ha valaki hole effektet hall, ne jöjjön zavarba, az is hasonló. Miután elvesztünk a nevek erdejében, lássuk a lényeget.

A dolog elmélete nagyon egyszerű. Ugye kézenfekvő megoldásnak tűnik a poligonokkal (síklapokkal) való 3D-s lemodellezése egy csőnek, és a Z koordináták folyamatos csökkentésével a közeledés látszatát kelteni. Ez igencsak lassú lenne. Arról nem is beszélve, hogy erre a modellre majd kanyarokat is kell varázsolni. Jobb megoldásnak tűnik ennek a leképezés utáni állapotát meghatározni, tehát eleve 2D-s modell előállítása. Ezzel megspóroltuk a leképezést, és kanyarogtatni is könnyebb. 

Nézzük ennek az előállítását:

Az könnyen belátható, hogy mivel a cső felszeletelhető körökre, egymásra rajzolt egyre nagyobb átmérőjű körökkel megkapjuk a cső belsejét. Az, ami valójában messzebb van, kisebb átmérőjű, ami közelebb, nagyobb. Tehát ha 3D-ben szeretnénk érteni a dolgokat, akkor a rajzolt kör mélysége arányos az átmérőjével. Annak ellenére, hogy csak 2D-s modellt állítunk elő szükségünk lesz a mélységre is, hiszen mélység szerint fogunk árnyékolni. Minél messzebb van valami, annál sötétebb a színe. Legalább is egy homályos alagútban. Arról nem is beszélve, hogy, ha a képernyő minden pixelét egy színnel rajzolnánk, elég nehéz lenne kivenni, hogy mit is kellene látnunk a monitoron. 

Na de egymásra rajzolt körökből nem lesz modell. A körök között kell helyet hagyni, és mindig ugyanannyit kell rajzolni belőlük. Ez legyen mondjuk m. Az egymás után rajzolt körök átmérője között legyen viszonylag nagyobb, mondjuk d különbség. Így minden egyes körön kiválaszthatunk n db pontot, ezeket poligonokba rendezve megkapjuk a 2D-s modellt. Van n*m db pontunk és n*(m-1) poligonunk. És persze mindegyikhez megvan a Z koordináta is, hiszen arányos az átmérővel. (ŕ Az ugyanazon körön lévő pontoknak ugyanaz a Z-je). Ez pont egy olyan adatszerkezet, amilyet egy 3D-s modell leképezése után kapnánk. Megvan minden pontra 2D-s X és Y pont képernyő koordinátái), és megvan a Z. Ez lesz a 2D-s modell. Ezt már texture mapingelni is tudjuk, tehát kirajzolható. 

Az ábrán minden körnek ugyanaz a középpontja. Ez egy egyenes cső modellje.
A fenti ábra a 2D-modellt hivatott bemutatni. A rácspontokban a vannak a pontok. A betöltött trapézok a poligonok. Pirossal pedig a poligonokat alkotó pontok vannak bekeretezve. Amint látható, mivel minden körön ugyanannyi pontot választunk, beljebb egyre kisebb poligonok lesznek. Persze ez pont jó mert, ami messzebb van, annak kisebbnek is kell lennie.

Kis kanyarral, csak pontokkal:

Ezeket a pontokat ugyanúgy kell összerendezni, mint az egyenes csőnél. 

Ha egy kis kanyart akarunk belelopni, csak más középpontokban kell a köröket számolni. Leggyorsabb külön táblázatot készíteni a középpontok X, -és Y koordinátáira. Mondjuk Sin-nel, vagy Cos-sal. A körök számolásánál szintén Sin és Cos táblázatokat kell használnunk, persze felszorozva.

Gyakorlatilag a dolog így néz ki:

Procedure Tunnel(d,xm,ym: integer); Var movoffs : integer;     circnum : integer;     Cx1,Cx2,Cy1,Cy2 : integer;     Angle,Rad1,Rad2,Angle2 : integer;     XWave,YWave : integer;begin XWave:=xm and 255; YWave:=ym and 255; Rad1:=d and 7; repeat   Rad2:=Rad1+IncRad;   Cx1:=SinMov[XWave];   Cy1:=CosMov[YWave];   Cx2:=SinMov[(XWave+XMovInc) and 255];   Cy2:=CosMov[(YWave+YMovInc) and 255];   Angle:=0;   repeat    poly.points[0].x:=160+Cx1+sar(Rad1*SinTab[Angle]);    poly.points[0].y:=100+Cy1+sar(Rad1*CosTab[Angle]);    poly.points[0].z:=(250-Rad1) div 2;    poly.points[3].x:=160+Cx2+sar(Rad2*SinTab[Angle]);    poly.points[3].y:=100+Cy2+sar(Rad2*CosTab[Angle]);    poly.points[3].z:=(250-Rad1) div 2;    Angle2:=angle+IncAng;    If Angle2>359 then Angle2:=Angle2-360;    poly.points[1].x:=160+Cx1+sar(Rad1*SinTab[Angle2]);    poly.points[1].y:=100+Cy1+sar(Rad1*CosTab[Angle2]);    poly.points[1].z:=(250-Rad2) div 2;    poly.points[2].x:=160+Cx2+sar(Rad2*SinTab[Angle2]);    poly.points[2].y:=100+Cy2+sar(Rad2*CosTab[Angle2]);    poly.points[2].z:=(250-Rad2) div 2;    tex;    Inc(Angle,IncAng);   Until Angle>359;   Inc(Rad1,IncRad);   Inc(XWave,XMovInc);   XWave:=XWave and 255;   Inc(YWave,YMovInc);   YWave:=YWave and 255; Until Rad1+IncRad>250; end;

Ez a rutin képről képre újra felépíti az alagutat, csak a mozgás fázisait kell megadni, és a mélységet.

Innen már csak Texture mapping, Shading.

A Z bufferingre is szükségünk lesz, hiszen a kanyargás miatt bizonyos részek takarásba kerülhetnek. Vagy egy jobb megoldás, ha mélységi sorrendben rakjuk ki a poligonokat. És persze sok láthatatlan síkot ki lehet szűrni a régi jó körüljárásos módszerrel is. Szóval a már ismert texture mapping rutinok nagyon jól megteszik.

Ennyi.