Kedves Olvasó DEMO rovatunk mostani száma 3 dimenziós tárgyak - testek - forgatásával foglalkozik. Már volt hasonló témájú cikkünk mely az axonometrikus forgatással foglalkozott - ez is egy módja a 3 dimenziós testek grafikai modellezésének számítógépen -, most egy sokkal látványosabb 3 dimenziós test megjelenítő - forgató módszerrel ismerkedhettek meg. A most leközölt térszámításos forgatás igényel középiskolai matematikai jártasságot (+ 1 db. függvénytáblát), egy kis fantáziát, kitartást és egy kis toleranciát is a cikkírókkal szemben, mivel ez a téma - szerintem - nehezen magyarázható. Cikkíró diáktársaim megpróbálták a lényeget kiragadni ami ahhoz kell, hogy megértsétek mi hogyan működik a forgatás során, nem akarták túlbonyolítani az amúgy is nehezen érthető képleteket - arányokat, de az alapokat mindenképen le kellett írni, s remélem többszöri próbálkozásuk eredményes lesz, => Egyszerű, számotokra is érthető cikkeket kaptok.

Először a matematikai - elméleti hátterét ismertetjük a térszámításos forgatásnak, ezt Gerebenics Andor követte el. Ezután jön a két részből álló gyakorlati megvalósítás by Kimmel Tamás. Azért áll két részből mert cikkírónk két különböző cikket adott nekem, hogy döntsem el melyik a jobban érthető. A két cikk nagyrészt hasonlít egymásra, de a leképezési eljárások különböznek ! Mivel nem tudtam, nem akartam eldönteni melyik a jobb ezért mind a kettőt megtalálhatjátok.

Kellemes, hasznos, kitartó olvasást kíván a Szerkesztő (R4s) !

(Amennyiben a cikkekben valamit nem értenétek légy szíves eMail-eljetek a cikkírónak, várják eMail-jeiteket !)

A térszámításos forgatás - elmélet

Nos, ez már a második próbálkozásom, hogy megpróbáljam közkincsé tenni egy olyan ábrázolási módszer alapjait mellyel viszonylag egyszerűen és viszonylag élethűen "modellezhetünk" térbeli testeket (a modellezés azért van zárójelben mert az itt leközölt elmélet csak arra jó, hogy térhálókat rajzoljunk a képernyőre), úgyhogy elnézést kérek azoktól akik a cikket nem értik meg első olvasásra (biztosan az én hibám).

A térbeli dolgok ilyen szinten csak abban különböznek a síkbeli ábráktól, hogy nem kettő hanem három koordináta határozza meg a pontjaikat.

Vegyünk először csak pontokat! Egy két dimenzióban ábrázolt pontot egyszerűen kirakhatunk a képernyőre (pascalban a PutPixel utasítással) mivel két koordinátával egyértelműen meghatározható a helyzete (X és Y). Ha három dimenzióban ábrázolt pontot akarunk kirakni a képernyőre akkor muszáj valamilyen leképezési eljárást alkalmaznunk mivel a képernyő egy sík.

A leképezési eljárások közül kétfélével fogunk foglalkozni, mindkettőt úgy kell elképzelni mintha a képernyő mögött lenne a test amit a képernyőn mint egy üveglapon keresztül néznénk.

Az első leképezési eljárásnál (jó neve van mi?) nehéz egyszerűbbet kitalálni ugyanis ez abból áll, hogy elhagyjuk a harmadik koordinátát mely a képernyő mögötti távolságot jelölné (Z).

Ekkor a képünk így néz ki (nem valami nagy durranás) :

A második leképezési módszer sokkal bonyolultabb de sokkal látványosabb is. Ilyenkor a program úgy dolgozik, mintha egy-iránypontos perspektívát szerkesztene. Az egy-iránypontos perspektívát a következő ábra mutatja be.:

Talán az ábrából is kitűnik, hogy minden vonal egy pont felé irányul. Ezt a pontot iránypontnak szokás nevezni; a koordinátáit jelöljük X0,Y0,Z0 betűkkel. Minden pont a Z koordinátájától függően tolódik el a középpont felé. Praktikus okokból a képernyőre merőleges irány (Z tengely) 0 pontját válasszuk a képernyő síkjának mivel így egyenes arányosság áll fenn a Z koordináta nagysága és az iránypont felé való eltolódás között. Nézzük a leképezést oldalról !

Egy pont leképezése

Egy téglalap pontjainak leképezése

A Kék keresztek a téglalap valóságos pontjai

A Zöld keresztek a leképezett pontok

Mint ahogy fentebb is utaltam rá, a pontok eltolódását aránypárral adhatjuk meg (az iránypont koordinátái X0,Y0,Z0) :
Az iránypont felé való eltolódás X,Y,Z pontra:
    függőleges eltolódás (lásd a fenti ábrákat) :

    vízszintes eltolódás logikusan következik a fentebb levezetett elméletből :

Az eltolódásokból a síkbeli koordináták számítása X,Y,Z pontra:
    síkx=eltolodasx+X
    síky=eltolodasy+Y

    Tehát :

    Vagy pascalosan :

    sikx := X + Round(z / z0 * (x - x0));
    siky := Y + Round(z / z0 * (y - y0));

No, úgy tűnik, a leképezést leírtam de mi értelme lenne ennek az egésznek, ha a testeket csak egy irányból tudnánk megnézni (minden valamire való testet körbe lehet járni). A forgatás elméleti háttere nem túl bonyolult. Három dimenzióban a pontokat síkonként lehet forgatni. Ilyenkor a forgatott pontoknak csak 2 koordinátájuk változik (tulajdonképpen úgy forgatjuk a pontokat, mintha síkban lennének. Az eredeti forgató képleteket a függvénytáblában találod meg amiket kicsit megspékelve eljuthatsz a tetszőleges középpont körüli forgatás képleteihez :
 
 
A forgásközéppontot jelöljük X1,Y1,Z1 koordinátákkal

Forgatás Z tengely körül

forgatottx:=Round((x - x1) * cos(f1) - (y - y1) * sin(f1)) + x1;
forgatotty:=Round((x - x1) * sin(f1) + (y - y1) * cos(f1)) + y1;

Forgatás X tengely körül

forgatottz:=Round((z - z1) * cos(f2) - (z - z1) * sin(f2)) + z1;
forgatotty:=Round((x - x1) * sin(f2) + (y - y1) * cos(f2)) + y1;

Forgatás Y tengely körül

forgatottx:=Round((x - x1) * cos(f3) - (y - y1) * sin(f3)) + x1;
forgatottz:=Round((z - z1) * sin(f3) + (z - z1) * cos(f3)) + z1;
 
 

Végezetül még néhány tanács :
    ·

    Az objektumoknak elég csak a sarkpontjait kiszámolni és ezeket vonalakkal összerkötni
    ·

    Célszerű minél több assembly-t használni (ez elég bonyolult de kivitelezhető)
    ·

    Ha átlapolási technikával rajzoltatod ki a vonalakat, az lényegesen meggyorsítja a programodat
    ·

    Ha lehet, számoltasd előre ki az összes állás koordinátáit.
    ·

    A valós számokat ne Real hanem Single típusúra deklaráld mert így koprocesszoros gépen jóval gyorsabb lesz a számítás
    ·

    Lehetőleg ne számoltasd ki sokszor ugyanazt

A perspektívaközéppontot célszerű úgy megválasztani, hogy mögé ne kerüljön semmi mert ami mögötte áll az a leképezés folyamán fejreáll. (ez igen zavaró ha pl. csak a kocka egyik fele áll fejre).
 

Gyakorlati megvalósítás - I

Szásztok! Ha már ilyen szépen összejöttünk, nézzünk egy kis kocka forgatást. Gondolom nem mondok újdonságot azzal, hogy a kocka egy test, így 3 dimenziós. Ahhoz, hogy egy kép három dimenziós, azaz térbeli legyen, alapfeltétel, hogy minden pontjához három koordináta tartozzon (x, y, z). A probléma ott kezdődött, mikor feltalálták, a képernyőt, ami nevéből következően is két dimenzióban tud ábrázolni. Ezért jobb híján a háromdimenziós alakzatot kell "átkonvertálni" két dimenzióba, azaz síkba leképezni. Tehát egy test egy síkra adott vetületét kell kiszámolnunk. A képernyőt képzeljük el egy síknak, és nézzük meg, hogy egy pont valahol a térben milyen vetületet vet rá:

Lásd a fenti ábrákat !

Hasonló háromszögek alapján felírható:

(y-ny)/nz=(y-y2d)/z

Tehát a leképezett pont y koordinátája: y2d=y+z*(ny-y)/ny

És ennek analógiájára a leképezett x koordináta: x2d=x+z*(nx-x)/nz

Szóval a képleteink előnye, hogy bárhol lehet a pont, és a perspektíva. Így aztán általánosan jól használhatók.

Azonban a korlátolt agyú programozónak ez a képlet túlontúl bonyolult ahhoz, hogy meg tudja jegyezni, ezért egyszerűsít: Legyen a leképezés középpontja, a test középpontja, ami az egyszerűség kedvéért egyben az origó is. Persze a leképezés középpontja nem egy az egyben a test középpont, hanem az mögött. Így aztán a következő képleteket kapja:

x2d=(m*x)/(p+z)
y2d=(m*y)/(p+z)

Ahol p a perspektíva mélysége m pedig a nagyítás.

Ezen képletek előnye, hogy gyorsabban lehet számolni, hátrányuk azonban, hogy kötött a perspektíva helye, és gőzöm sincs hogy jöttek ki.

Szóval mivel az alakzatot (jelen esetben kockát) csak a csúcsaival jellemezzük, egy esetleges eltolásnál, tükrözésnél, elforgatásnál, csak azzal a pár ponttal kell számolnunk. Akkó'forgassunk!

Ajánlom mindenkinek szíves figyelmébe a függvénytáblát, amiben a 2d-forgatásnál a következő képlet tartózkodik:

x' =x*cosa +y*sina
y' =y*cosa -x*sina

Nekünk ugyanezt 3d-ben kell eljátszanunk:

Z tengely körül:

x' =x*cosa +y*sina
y' =y*cosa -x*sina

X tengely körül:

z' =z*cosb +y*sinb
y' =y*cosb -z*sinb

Y tengely körül:

x' =x*cosg +z*sing
z' =z*cosg -x*sing

Így aztán már bármilyen tengely körül forgathatunk kedvünkre.

Azért valami bibi van ezekkel a képletekkel. Feltűnően sok bennük a szögfüggvény, ezeket pedig csak elég hosszadalmas szenvedésekkel lehet kiszámolni. De sebaj, mert erre is van egy trükk. A szögekhez tartozó sin és cos értékeket eltároljuk egy tömbben. Mivel cosa =sin(p /2+a ), nem kell külön tömb a két szögfüggvénynek. Tehát van egy 360 elemű tömbünk, ahol ezek el vannak tárolva. Igenám, de ezek az értékek -1 és +1 közé esnek, ergo lebegőpontosan kell számolnunk. Ettől meg olyan lassú lesz a program, mint egy 2 hetes zsíros kenyér. De mi mindent megoldunk! Okos emberek kitalálták, hogy 2 hatványaival úgy lehet gyorsan osztani, szorozni, hogy jobbra, ill. balra léptetjük a bájtot. Nincs más dolgunk, minthogy megszorozni az adott értéket 2 a valahanyadikonnal, majd mikor szükségünk van rá először összeszorozzuk a képletben mellette szereplő számmal, majd az eredményt visszaosztjuk 2 a valahanyadikonnal. Persze ez a módszer csak akkor működik, ha a szögfüggvény értékével szoroznunk kell. Ahogy most is.

Ami még feltűnő a képletekben az az, hogy igencsak hasonlóak. mindenhol csak a változók különböznek. Ha írnánk egy gyors rutint, ami 2d-ben forgatna, ugyanezt a rutint 3d-ben is tudnánk használni úgy, hogy egyszer x,y-t adunk meg paraméternek (Z tengely), egyszer z,y-t (X tengely), egyszer meg x,z-t (Y tengely). Íme a rutin:

procedure forgat2d(k1,k2 : integer;var ki1,ki2 : integer;szog : word);assembler; asm
jmp @cod @sin: dw 0,4,9,13,18,22,27,31,36,40,44,49,53,58 dw 62,66,71,75,79,83,88,92,96,100,104,108,112,116 dw 120,124,128,132,136,139,143,147,150,154,158,161,165,168 dw 171,175,178,181,184,187,190,193,196,199,202,204,207,210 dw 212,215,217,219,222,224,226,228,230,232,234,236,237,239 dw 241,242,243,245,246,247,248,249,250,251,252,253,254,254 dw 255,255,255,256,256,256 @cos: dw 256,256,256,256,255,255,255,254 dw 254,253,252,251,250,249,248,247,246,245,243,242,241,239 dw 237,236,234,232,230,228,226,224,222,219,217,215,212,210 dw 207,204,202,199,196,193,190,187,184,181,178,175,171,168 dw 165,161,158,154,151,147,143,139,136,132,128,124,120,116 dw 112,108,104,100,96,92,88,83,79,75,71,66,62,58 dw 53,49,45,40,36,31,27,22,18,13,9,5,0,-4 dw -9,-13,-18,-22,-27,-31,-36,-40,-44,-49,-53,-58,-62,-66 dw -71,-75,-79,-83,-87,-92,-96,-100,-104,-108,-112,-116 dw -120,-124 dw -128,-132,-136,-139,-143,-147,-150,-154,-158,-161,-164 dw -168 -171,-175 dw -178,-181,-184,-187,-190,-193,-196,-199,-202,-204,-207 dw -210,-212,-215 dw -217,-219,-222,-224,-226,-228,-230,-232,-234,-236,-237, -239,-241,-242 dw -243,-245,-246,-247,-248,-249,-250,-251,-252,-253,-253, -254,-255,-255 dw -255,-256,-256,-256,-256,-256,-256,-256,-255,-255,-255, -254, -254,-253 dw -252,-251,-250,-249,-248,-247,-246,-245,-243,-242,-241, -239,-237,-236 dw -234,-232,-230,-228,-226,-224,-222,-219,-217,-215,-212, -210,-207,-205 dw -202,-199,-196,-193,-190,-187,-184,-181,-178,-175,-171, -168,-165,-161 dw -158,-154,-151,-147,-143,-140,-136,-132,-128,-124,-120, -116,-112,-108 dw -104,-100,-96,-92,-88,-83,-79,-75,-71,-66,-62,-58,-53,-49 dw -45,-40,-36,-31,-27,-22,-18,-14,-9,-5,0 dw 4,9,13,18,22,27,31,36,40,44,49,53,58 dw 62,66,71,75,79,83,88,92,96,100,104,108,112,116 dw 120,124,128,132,136,139,143,147,150,154,158,161,165,168 dw 171,175,178,181,184,187,190,193,196,199,202,204,207,210 dw 212,215,217,219,222,224,226,228,230,232,234,236,237,239 dw 241,242,243,245,246,247,248,249,250,251,252,253,254,254 dw 255,255,255,256,256,256,256 @cod: push ds mov ax,k1 cbw mov bx,ax mov ax,k2 cbw mov cx,ax push cs pop ds mov si,szog {si=szog} shl si,1 add si,offset @cos mov ax,[si] {ax=cosalfa} imul bx {ax=xv*cosalfa} mov di,ax {di=ax} mov ax,[si-180] {ax=sinalfa} imul cx {ax=yv*sinalfa} sub di,ax {di=xv*cosalfa-yv*sinalfa} sar di,8 {visszaosztunk} mov ax,[si-180] {ax=sinalfa} imul bx {ax=xv*sinalfa} mov bx,ax {bx=ax} mov ax,[si] imul cx {ax=yv*cosalfa} add ax,bx {ax=xv*sinalfa+yv*cosalfa} sar ax,8 {viszaosztunk} lds si,ki1 mov [si],di lds si,ki2 mov [si],ax pop ds
end;

Amint láttátok (remélem), az eljárás origó (0,0) körül forgat. Ebből következik, hogy ha egy kockát akarunk forgatni, célszerű a kocka közepét venni origónak. Így majd használhatjuk a
rövidebb képleteket a leképezésnél. Tehát lesz egy tömbünk, ami valahogy így néz ki :

const oldkoords array[1..8] of type3d=((x:-50;y:-50;z:-50), (x:50;y:-50;z:-50), (x:50;y:50;z:-50), (x:-50;y:50;z:-50),(x:-50;y:-50;z:50), (x:50;y:-50;z:50), (x:50;y:50;z:50), (x:-50;y:50;z:50));

Meg még egy tömbünk, ami az elforgatott koordinátákat tartalmazza:
 

var newkoords array[1..8] of type3d;

Ez a kocka. Minden pontjával eljátszuk a kívánt forgatást, és leképezést:

procedure forgat; var i:integer; begin
for i:=1 to 8 do begin
{X tengely} forgat2d(oldkoords[i].y, oldkoords[i].z, newkoords[i].y, newkoords[i].z, alfa); {Y tengely} forgat2d(oldkoords[i].x, newkoords[i].z,newkoords[i].x, newkoords[i].z, beta); {Z tengely} forgat2d(newkoords[i].x, newkoords[i].y, newkoords[i].x, newkoords[i].y, gamma); {Mivel a leképezés egyszerű képletek alapján történik, nem bonyolítunk asm-el (persze akinek kedve van...)} newkoords[i].x:=M*newkoords[i].x div (P+newkoords[i].z)+x_deph; newkoords[i].y:=M*newkoords[i].y div (P+newkoords[i].z)+y_deph; {nem használunk külön tömböt 2d-re, beleszemetelünk a 3d-s be}
end;
end;

Ha már ennyit számoltunk, nem ártana, ha látszana is valami.

Nekiállunk vonalakat rajzolgatni. De honnan hová ? Ha ragaszkodunk az én féle tömbleíráshoz, akkor így: 1-2,2-3,3-4,4-1,1-5,2-6,3-7,4-8,5-6,6-7,7-8,8-5

(A számok a tömb elemeit jelölik)
tehát:

procedure drawbox; begin
line(newkoords[1].x,newkoords[1].y,newkoords[2].x, newkoords[2].y,2); line(newkoords[2].x,newkoords[2].y,newkoords[3].x, newkoords[3].y,2); line(newkoords[3].x,newkoords[3].y,newkoords[4].x, newkoords[4].y,2); line(newkoords[4].x,newkoords[4].y,newkoords[1].x, newkoords[1].y,2); line(newkoords[1].x,newkoords[1].y,newkoords[5].x, newkoords[5].y,2); line(newkoords[2].x,newkoords[2].y,newkoords[6].x, newkoords[6].y,2); line(newkoords[3].x,newkoords[3].y,newkoords[7].x, newkoords[7].y,2); line(newkoords[4].x,newkoords[4].y,newkoords[8].x, newkoords[8].y,2); line(newkoords[5].x,newkoords[5].y,newkoords[6].x, newkoords[6].y,2); line(newkoords[6].x,newkoords[6].y,newkoords[7].x, newkoords[7].y,2); line(newkoords[7].x,newkoords[7].y,newkoords[8].x, newkoords[8].y,2); line(newkoords[8].x,newkoords[8].y,newkoords[5].x, newkoords[5].y,2);
end;

A kocka előállt!
 

Gyakorlati megvalósítás - II

(Avagy második nekifutás: Szerk.)

Szásztok! Itt volt ám még egy bekezdés, csak kitöröltem !

Ha már ilyen szépen összejöttünk, nézzünk egy kis kocka forgatást. Gondolom nem mondok újdonságot azzal, hogy a kocka egy test, így 3 dimenziós. Ahhoz, hogy egy kép három dimenziós, azaz térbeli legyen, alapfeltétel, hogy minden pontjához három koordináta tartozzon (x, y, z). A probléma ott kezdődött, mikor feltalálták, a képernyőt, ami nevéből következően is két dimenzióban tud ábrázolni. Ezért jobb híján a háromdimenziós alakzatot kell "átkonvertálni" két dimenzióba, azaz síkba leképezni. (Jobb helyeken perspektív transzformációnak hívják) Tehát egy test egy síkra adott vetületét kell kiszámolnunk. A képernyőt képzeljük el egy síknak, és nézzük meg, hogy egy pont valahol a térben milyen vetületet vet rá:

Lásd az ábrát az Elméleti részben !

Erre a feladatra az elvetemültebb fajta programozó a következő képleteket használja:

x2d=(m*x)/(p+z)
y2d=(m*y)/(p+z)

Ahol p a perspektíva mélysége m pedig a nagyítás. Ezt a két konstanst úgy kell megválasztani, hogy valószerű képet kapjunk.

Ezen képletek előnye, hogy gyorsan lehet számolni, hátrányuk azonban, hogy kötött a perspektíva helye, és gőzöm sincs hogy jönnek ki. Ez a dolog egyszerűbb oldala. akkor jöjjön a fekete leves.

Szóval mivel az alakzatot (jelen esetben kockát) csak a csúcsaival jellemezzük, egy esetleges eltolásnál, tükrözésnél, elforgatásnál, csak azzal a pár ponttal kell számolnunk. Akkó'forgassunk!

Ajánlom mindenkinek szíves figyelmébe a függvénytáblát, amiben a 2d-forgatásnál a következő képlet tartózkodik:

x' =x*cosa +y*sina
y' =y*cosa -x*sina

Nekünk ugyanezt 3d-ben kell eljátszanunk:

Z tengely körül:

x' =x*cosa +y*sina
y' =y*cosa -x*sina

X tengely körül:

z' =z*cosb +y*sinb
y' =y*cosb -z*sinb

Y tengely körül:

x' =x*cosg +z*sing
z' =z*cosg -x*sin

Így aztán már bármilyen tengely körül forgathatunk kedvünkre. Na azért még ne ragadjunk rögtön klaviatúrát, pascalt, gondolkodjunk! Ügyi van 8 pontunk, amiket mind meg akarunk forgatni a 3 tengely körül. Lássuk, ha az előbbi képleteket használjuk, az pontonként cirka 12 szögfüggvényszámítás. Igen, egy P6-oson talán már elég élvezhető is lenne. Aztán gondolkodjunk el azon is, mi lenne, ha mondjuk nem 8, hanem 50 pontot forgatnánk. Well.. valahogy optimalizálnunk kéne a kódot. (de profi voltam) Legyen !

Ha a hat képletünket összevonjuk 3-ba (nekünk 3 koordináta kell csak, a részletek nem érdekelnek), az alábbi képletek jönnek ki:(elég sok rendezés után)

x' =x*(cosa *cosg -sina *sinb *sing )-y*(sinb *cosa *sing +cosg *sina ) + z*(sing *cosb )
y' =x*(sina *cosb )+y*(cosa *cosb )+z*(sinb )
z' =x*( sing *cosa +cosg *sinb *sina )+y*(cosg *sinb *cosa -sing *sina )-z*(cosb *cosg )

Számoljuk össze a szögfüggvényeket: Asszongyahogy kb. 29. Na ezen a ponton szokták azt modnani, hogy adtunk egy jó nagy pofont a s**r-nak. Pedig ha tudnák, milyen hasznos is lehet a számítástechnikában néhány képlet túlbonyolítása. Most például azt értük el, hogy mit is? Azt , hogy egyszer kiszámoljuk , kiszenvedjük a pontok forgatása során a zárójelben lévő kifejezéseket (egy egy rahedli sin meg cos) és utána az összes pontnál fel tudjuk használni őket:

xx=cosa *cosg -sina *sinb *sing
xy=-(sinb *cosa *sing +cosg *sina )
xz=sing *cosb
yx=sina *cosb
yy=cosa *cosb
yz=sinb
zx=sing *cosa+cosg *sinb *sina
zy=cosg *sinb *cosa -sing *sina
zz=-cosb *cosg

Ezt a kilenc értéket szokták forgatási mátrixnak nevezni, egy 3X3-as mátrixba rendezve. Ezt a kilenc értéket kell meghatároznunk forgatás előtt, és már mehet a menet. Csakhogy ha ezt lebegőpontosan, a beépített sin és cos függvényekkel csináljuk, bizonyos gépeken (<486) még mindig lassúak leszünk. Mit lehet még tenni? Kezdjük ott, hogy a szögekhez tartozó sin és cos értékeket eltároljuk egy tömbben. Mivel cosa =sin(p /2+a ) (tiszta matekóra), nem kell külön tömb a két szögfüggvénynek. Tehát van egy 360+90 elemű tömbünk, ahol ezek el vannak tárolva. Igenám, de ezek az értékek -1 és +1 közé esnek, ergo lebegőpontosan kell számolnunk. Ettől meg egyrészt lassú lesz a program, másrészt a demókban nem illik. De mi mindent megoldunk! Okos emberek kitalálták, hogy 2 hatványaival úgy lehet gyorsan osztani, szorozni, hogy jobbra, ill. balra léptetjük a bájtot. Nincs más dolgunk, minthogy megszorozni az adott értéket 2 a valahanyadikonnal, majd mikor szükségünk van rá először összeszorozzuk a képletben mellette szereplő számmal, majd az eredményt visszaosztjuk 2 a valahanyadikonnal. Persze ez a módszer csak akkor működik, ha a szögfüggvény értékével szoroznunk kell. Ahogy most is. Ja, és mellékesen az egész számítás nem árt, ha assembly. Majd, ha elkezdünk forgatni, csak a következő képletekbe kell behelyettesítgetni:

x' =x*xx+y*xy+z*xz
y' =x*yx+y*yy+z*yz
z' =x*zx+y*zy+z*zz

A forgatás, mint elmélet, ezzel remélem elég tiszta.

Na, ha egy kockát akarunk forgatni, célszerű a kocka közepét venni origónak. Annál is inkább, mert mind a forgatórutin, mind a leképezőrutin az origót veszi középpontnak. Lesz egy tömbünk, ami valahogy így néz ki:

const oldkoords array[1..8] of type3d= ((x:-50;y:-50;z:-50), (x:50;y:-50;z:-50), (x:50;y:50;z:-50), (x:-50;y:50;z:-50), (x:-50;y:-50;z:50), (x:50;y:-50;z:50), (x:50;y:50;z:50), (x:-50;y:50;z:50));

Meg még egy tömbünk, ami az elforgatott koordinátákat tartalmazza:

var newkoords array[1..8] of type3d;

Ez a kocka. Minden pontjával eljátszuk a kívánt forgatást, és leképezést:

procedure forgat; var i:integer;begin   szamit; {ez tartalmazza azt a bizonyos assembly számolást}   for i:=1 to 8 do  begin     newkoords[i].x:=(oldkoords[i].x*xx+oldkoords[i].y*xy+oldkoords[i].z*xz) div 128;     newkoords[i].y:=(oldkoords[i].x*yx+oldkoords[i].y*yy+oldkoords[i].z*yz) div 128;     newkoords[i].z:=(oldkoords[i].x*zx+oldkoords[i].y*zy+oldkoords[i].z*zz) div 128;     {128=2 a hetediken, ezzel volt felszorozva a sin tábla, és most vissza kell     osztanunk}{rutinosabbak megtehetik asm-ben is (SAR)}     {A leképezés egyszerű képletek alapján történik, nem bonyolítunk asm-el (persze akinek kedve van...)}     newkoords[i].x:=M*newkoords[i].x div (P+newkoords[i].z)+x_deph;     newkoords[i].y:=M*newkoords[i].y div (P+newkoords[i].z)+y_deph;     {nem használunk külön tömböt 2d-re, beleszemetelünk a 3d-s be}  end; end;
Ha már ennyit számoltunk, nem ártana, ha látszana is valami.

Nekiállunk vonalakat rajzolgatni. De honnan hová ? Ha ragaszkodunk az én féle tömbleíráshoz, akkor így: 1-2,2-3,3-4,4-1,1-5,2-6,3-7,4-8,5-6,6-7,7-8,8-5

(A számok a tömb elemeit jelölik)

tehát:
 

procedure drawbox; begin
line(newkoords[1].x,newkoords[1].y,newkoords[2].x, newkoords[2].y,2); line(newkoords[2].x,newkoords[2].y,newkoords[3].x, newkoords[3].y,2); line(newkoords[3].x,newkoords[3].y,newkoords[4].x, newkoords[4].y,2); line(newkoords[4].x,newkoords[4].y,newkoords[1].x, newkoords[1].y,2); line(newkoords[1].x,newkoords[1].y,newkoords[5].x, newkoords[5].y,2); line(newkoords[2].x,newkoords[2].y,newkoords[6].x, newkoords[6].y,2); line(newkoords[3].x,newkoords[3].y,newkoords[7].x, newkoords[7].y,2); line(newkoords[4].x,newkoords[4].y,newkoords[8].x, newkoords[8].y,2); line(newkoords[5].x,newkoords[5].y,newkoords[6].x, newkoords[6].y,2); line(newkoords[6].x,newkoords[6].y,newkoords[7].x, newkoords[7].y,2); line(newkoords[7].x,newkoords[7].y,newkoords[8].x, newkoords[8].y,2); line(newkoords[8].x,newkoords[8].y,newkoords[5].x, newkoords[5].y,2);
end;
 

A kocka előállt!

Most már csak animálnunk kell. Röviden: mindig arra a lapra rajzolunk ami nem látszik, majd kicseréljük a két lapot. Hogy ez pontosan hogy is történik 320x200-ban? Meg egyáltalán hogy kell kezelni így a képernyőt? Ezt a mellékelt unit végzi helyettünk.