Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
Tallinna Reaalkool
3D MOOTORID EHK RUUMILISE GRAAFIKA KUVAMINEREAALAEGSETES ARVUTIMÄNGUDES VÕI
-SIMULATSIOONIDESuurimistöö
Marius Andra11a
Juhendaja: õp. Mart Kuurme
Tallinn 2004
SISUKORD
SISUKORD................................................................................................................................2SISSEJUHATUS .......................................................................................................................3
1.RUUMILISE GRAAFIKA REAALAEGNE KUVAMINE..............................................5
1.1. Kolmnurgad..............................................................................................................5
1.2. Erinevad API-d.........................................................................................................6
1.2.1. Direct3D............................................................................................................6 1.2.2. OpenGL.............................................................................................................7
1.3. Kokkuvõtvalt ruumilise graafika kuvamisest...........................................................8
2.RUUMIJAOTUSALGORITMID.......................................................................................9
2.1. Vaateväljapiirang.......................................................................................................9
2.2. Kaheksandpuud........................................................................................................12
2.3. Binaarsed jaotuspuud...............................................................................................16
2.4. Portaalisüsteemid.....................................................................................................19
2.5. Potentsiaalsed nähtavushulgad.................................................................................21
2.6. Adaptiivsed kahendpuud..........................................................................................22
2.7.Suuremate algoritmide osadena esinevad algoritmid................................................25
2.7.1. Kolmnurga jaotamine osadeks.........................................................................252.7.2. Vaatevälja kitsendamine..................................................................................26
2.8. Ruumijaotusalgoritmide kokkuvõte.........................................................................26
3.VALGUSTUS...................................................................................................................28
3.1. Radioossus...............................................................................................................28
3.2. Teised meetodid staatilise valgustuse leidmiseks....................................................31
3.3. Dünaamilised valgusallikad.....................................................................................31
TERMINID..............................................................................................................................34KOKKUVÕTE.........................................................................................................................38KASUTATUD MATERJALID................................................................................................40
2
SISSEJUHATUS
Viimase paarikümne aasta jooksul on reaalaegne arvutigraafika läbi elanud suuri
arenguetappe. Iidsete neljavärviliste Pac-Man2 mängude juurest oleme jõudnud ülirealistlike
kolmemõõtmeliste meistriteosteni, mille detailsus meid kõiki imestama paneb. Aga kuidas nii
tehakse? Milliste meetoditega tuuakse meieni kõik need ruumilised keskkonnad, mida
arvutimängudes nägema harjunud oleme? Ja miks nad ikkagi nii ilusad tunduvad? Kõigile
neile ning ka paljudele teistele küsimustele otsime siin uurimistöös vastust.
Üheksakümnendate algusest saadik on kolmemõõtmelised mängud jõuliselt arenema
hakanud. Koos riistvara arenguga on järjest lisandunud uusi trikke ja meetodeid erinevate
efektide saavutamiseks. Pidevalt mõeldakse välja uusi algoritme, mis oluliselt parandavad
mängude sujuvust, mängitavust, ilu või kõike kolme korraga. Uurimistöös püüan omavahel
võrrelda erinevate tulemuste saavutamiseks loodud algoritme, tuua esile nende head ja halvad
küljed ning kokkuvõtvalt teha järeldused ühe või teise algoritmi sobivusest kindlate
eesmärkide jaoks.
3D mootorite teema valisin ennekõike seetõttu, et olen ruumiliste mängude
programmeerimisega varasemalt kokku puutunud, kuid tahaks siiski oma oskusi täiendada
ning juurde õppida paljut, mis varasemast on uurimata jäänud. Teema valikuks on ka
sügavam põhjus: nimelt ei ole ma teadlik ühestki eestikeelsest dokumendist, mis käsitleks
kokkuvõtvalt seda teemade ringi. Üritan seda lünka täita.
Enamik uurimistöö valmistamiseks kasutatud materjalist on pärit Internetist, osa on ka
raamatutest. Internet on siin asendamatu infoallikas, milleta oleks kogu töö tegemine
tunduvalt keerulisem, kui mitte võimatu.
2 kõik mõisted on lahti seletatud uurimistöö lõpus
3
Siinkohal tahaks tänu avaldada mõnele inimesele, kes omal ajal motiveerisid mind
kolmemõõtmelise programmeerimisega tegelema. Ennekõike tänaks Jeff Molofee'd oma
suurepärase lehe3 eest, mis õpetas mind ruumilist graafikat läbi OpenGL-i (vt. punkt 1.2.2)
kuvama. Samuti on väärt tänu Kevin Hawkins ning Dave Astle nende suurepärase lehe4 eest,
läbi mille on nii mõnigi mu küsimus lahenduse leidnud, ning ka nende raamatu5 eest. Ja
ärgem unustagem mu ema Lyra Andra-t ning isa Andres Andra-t ja ka kõiki õpetajaid, kellel
suur roll mu hariduses ja kasvatuses olnud on. Nimeliselt mainiks neist õpetaja Mart
Kuurmed ning õpetaja Liisa-Kai Pihlakut, kes aitasid kaasa uurimustöö valmimisele.
3 http://nehe.gamedev.net/4 http://www.gamedev.net/5 “OpenGL Game Progamming”
4
1. RUUMILISE GRAAFIKA REAALAEGNE KUVAMINE
Enne kui uurimistöö põhiosani jõuame on vaja selgeks saada milliste vahenditega
arvutiekraanile üldse kujundeid joonistatakse.
1.1. Kolmnurgad
Praktiliselt kõikide kompleksete ruumiliste objektide kuvamisel lõhutakse need tükkideks
ning joonistatakse ekraanile kolmnurkade kaupa. Miks just kolmnurkade? See on nii vaid
sellel lihtsal põhjusel, et kolmnurgad on väikseimad ühetasandilised geomeetrilised kujundid,
millede kokkupanekul on iga teist primitiivi (nelinurka, viisnurka, kuusnurka jne) või
suuremat objekti (maja, autot, inimest) võimalik moodustada. Kolmnurgad on ruumilise
graafika ehituskivideks!
Kuna kolmnurgad on ruumilistes maailmades enimesinevad kujundid, on nende kiire
kuvamise nimel väga palju tööd tehtud. Tänapäeval suudavad paremini varustatud arvutid
ühes sekundis ekraanile joonistada juba mitukümmend miljonit kolmnurka.
Varem pidi kolmnurkade ekraanile saatmiseks arvutiprogramm läbi tegema suure töö. Oli
vaja iga kolmnurga koordinaate keerutada, transformeerida ning lõpuks
kahedimensioonilisteks ekraanikoordinaatideks projekteerida. Viimastest moodustati
“tahked” kolmnurgad, mis ekraanile jõudsid. Kõik need arvutused jooksid läbi arvuti
keskprotsessori, mis sai seega väga suure töö osaliseks. Nüüdseks on kõik see töö viidud
eraldiseisvate graafikaprotsessorite kätte, mis just sel eesmärgil loodud on. Vabastades
keskprotsessori suurest liigsest koormusest, võib see samal ajal teisi olulisi arvutusi teha,
näiteks arvutimängudes vastaste strateegia arvutamine, füüsikaseaduste simuleerimine vms.
Kolmnurkade kuvamiseks ei pea me enam palju vaeva nägema. Saadame vaid
graafikaprotsessorile informatsiooni nende koordinaadite kohta, ütleme mitu kraadi millise
5
telje ümber neid pöörata, millise tekstuuri/pildi neile peale panna ning nad ongi juba ekraanil
nähtavad. Raskused seisnevad aga selles, kuidas saata graafikaprotsessorile informatsiooni
vaid nende kolmnurkade kohta, mis kindlalt nähtavad on, vähendades üleliigset tööd, kuidas
kolmnurki värvida nii, et stseen näeks ehtsalt valgustatud välja, kuidas tagada realistlik
kasutaja ja maailma vaheline vastastikmõju ning kuidas teha seda kõike korraga ning
võimalikult lühikese aja jooksul. Need on vaid mõningad põhiprobleemid, mis 3D mootoreid
programmeerides esile kerkivad.
1.2. Erinevad API-d
Et otse GPU'ga keerulist dialoogi pidama ei peaks, on loodud erinevad rakendusliidesed, mis
meid abistavad. Neid võiks justkui tõlkijateks nimetada, sest nad vahendavad 3D mootori
ning graafikaprotsessori vahelist kahekõne. Me saadame läbi mõne sellise rakendusliidese
informatsiooni selle kohta, mida ekraanil näha tahame. Vastu saame ekraanile soovitud pildi.
Suurfirmade omavahelise konkurentsi tõttu on selliseid rakendusliideseid tekkinud mitmeid.
Põhilised neist on SGI poolt väljatöötatud OpenGL ning Microsoft DirectX koostisse kuuluv
Direct3D. Vaatleme lühidalt nende sarnasusi ning erinevusi.
1.2.1. Direct3D
Windows 95 algusaegadel kirjutati veel enamik mänge MS-DOS-ile, sest tol hetkel
Windows-il lihtsalt puudusid korralikud vahendid mängude loomiseks. Püüdes arendajaid
uuele platvormile üle meelitada ning seega selle populaarsust MS-DOS-i ees veelgi tõsta,
loodi rakendusliides nimega DirectX, mis sisaldas endas käsustikke heli (DirectSound), pildi
(Direct3D, varem ka 2D graafika jaoks eraldi DirectDraw), tagasiside (DirectInput) jms
haldamiseks.
Esimesed versioonid tulid üpris kehvalt välja. Need olid vigased, aeglased ning kehva
ülesehitusega, mistõttu mänguloojate heakskiitu need ei saanud. Olukord paranes alles üsna
hiljuti DirectX 5-ga, mis oli esimene tõeliseltvõetav versioon. Seitsmendast versioonist alates
on oma heakskiidu andnud ka mängude arendajad, mistõttu rakendusliidese tulevik näib
6
helge.
Uued DirectX versioonid tulevad välja keskmiselt kord aastas. Kuna Microsoft teeb lähedast
koostööd graafikakaartide tootjatega, integreeritakse uutesse versioonidesse tihti võimalusi,
mida ükski turul olev kaart veel kasutada ei suuda. Seega toetavad uued DirectX-i (täpsemalt
Direct3D) väljalasked ka kõige “vingemaid” graafikakaarte.
Kahjuks on Direct3D-l ka suuri miinuseid. Erinevalt OpenGL-ist ei ole Direct3D porditav.
See tähendab, et Direct3D jaoks võib tarkvara kirjutada vaid Microsoft Windows ning XBox
platvormidele. Samuti kipub Direct3D jaoks kirjutatud kood olema tunduvalt pikem ning
segasem sama funktsiooni täitvast OpenGL-i koodist.
(Alamjaotis põhineb materjalist nr. 2 saadud infol.)
1.2.2. OpenGL
Tulevikku silmas pidades loodi 1992. aastal Silicon Graphics-i (SGI) poolt OpenGL. Tegu on
avatud standardiga, mistõttu kannavad selle spetsifikatsioonide eest hoolt mitmed erinevad
suurfirmad, kes kokku moodustavad komitee nimega Architecural Review Board (ARB).
Üllatavalt on nende hulgas ka Microsoft.
OpenGL on oma pika eksistentsi jooksul tõestanud, et tegu on ühe hästi stabiilse
rakendusliidesega. Erinevalt Direct3D-st on OpenGL kasutatav peaaegu kõikidel
eksisteerivatel arvutiplatvormidel, mitte ainult Microsoft Windows-il. Nagu varem mainitud,
on OpenGL-is kirjutatud kood enamasti tunduvalt lühem Direct3D analoogist.
ARB töömeetodite tõttu on OpenGL võrdlemisi aeglaselt arenenud. Viimane väljalastud
versioon kannab alles versiooninumbrit 1.5. Erinevalt Direct3D-st saab OpenGL-is uutele
graafikakaartidele omaseid võimalusi kasutada läbi eriliste laiendite. Paraku on erinevate
firmade kaartide laiendid sageli erinevad ning seetõttu tuleb ühte koodi mitmeid kordi
erinevate kaartide jaoks kirjutada. Direct3D-l on siinkohal eelis Microsofti ja graafikafirmade
7
koostöö mõjul väljakujunenud standardsete lähenemisviiside tõttu.
Oma platvormidevahelisuse ning stabiilsusega on OpenGL eelistatuim rakendusliides
modelleerimise, disainimise jms 3D graafikaga töötlusega seotud programmides, mitte ainult
arvutimängudes.
Peagi on oodata uut revolutsioonilist OpenGL versiooni numbriga 2.0, millega loodetakse
taaskord 3D graafika rakendusliideste latt kõrgele tõsta, nagu seda omal ajal tegi OpenGL
1.0. Lähemalt tutvumiseks vaata OpenGL 2.0 spetsifikatsioone6.
(Alamjaotis põhineb materjalist nr. 2 saadud infol.)
1.3. Kokkuvõtvalt ruumilise graafika kuvamisest
Ruumilise graafika kuvamine on viimasel ajal tunduvalt lihtsamaks muutunud. Enam ei pea
kolmnurkade või muude tasandiliste hulknurkade ekraanile saatmiseks pikalt tarkvaraga
vaeva nägema, sest kasutada võib erinevaid rakendusliideseid, mis kogu musta töö salaja ära
teevad.
Rakendusliidestest põhilised on Direct3D ning OpenGL. Mõlemad teevad praktiliselt sama
asja, Direct3D aga vaid Microsoft Windows-i platvormil, OpenGL peaaegu igal
olemasoleval. Kumba keegi kasutada soovib, sõltub vaid tema enda eelistustest.
Platvormidevahelisuse tõttu eelistab uurimistöö autor viimati mainitut.
6 http://www.3dlabs.com/support/developer/ogl2/index.htm
8
2. RUUMIJAOTUSALGORITMID
Siin peatükis tuleb juttu algoritmidest, millega saab tunduvalt vähendada kolmnurkade arvu,
mis graafikaprotsessorile saadetakse.
2.1. Vaateväljapiirang
Lihtne vaateväljapiirang ehk frustum culling on kõige lihtsam asi, mida võib teha, et
kuvatavate kolmnurkade hulke vähendada. Algoritm töötab äärmiselt lihtsa põhimõttega: me
ümbritseme mõne kindla objekti (maja, auto, inimese vms) mõne lihtsa ruumilise
geomeetrilise primitiiviga (kera, kuup, risttahukas vms) ning enne objekti joonistamist
kontrollime, kas see primitiiv asub “kaamera” vaateväljas või mitte. Kui asub, joonistame
objekti. Kui mitte, hoidsime just kõvasti aega kokku ega pea kõiki kolmnurki
graafikaprotsessorile eraldi saatma, sest ükski neist ei oleks niikuinii nähtav.
Lähemalt vaadates töötab süsteem selliselt, et
enne iga kaadri joonistamist, kui niiöelda
“kaamera” positsioon on eelneva kaadriga
võrreldes muutunud, küsime rakendusliideselt 6
tasandit, mis kaamera vaatevälja ümbritsevad:
parem, vasak, alumine, ülemine, tagumine ning
eesmine.
Vahel võib olla vaja teada, kas mõni punkt asub vaatevälja sees või sealt väljas. Selleks
uurime punkti kaugust kõigist kuuest tasandist, mis vaatevälja ümbritsevad. Kui punkt asub
igast tasandist eespool, on see vaatevälja sees. Kui punkt asub ühestki tasandist tagapool, on
see vaateväljast väljas.
Kera vaateväljasisesuse määramine on praktiliselt sama lihtne. Kera keskpunkti kaugust
9
Joonis 1: kaamera vaateväli
ühestki tasandist väljaspoole ei tohi olla suurem kui kera raadius. Kui kaugus tasandist on
suurem kui kera raadius, asub keha täielikult väljaspool ühte tasandit ning pole seega
kaamerale nähtav.
Risttahukate kontroll on natuke keerulisem. Kõige lihtsam oleks muidugi vaadata, kas
risttahuka iga nurk asub vaatevälja sees või mitte, kuid sellise meetodiga tekib probleem: mis
juhtub, kui risttahukas täielikult ümbritseb vaatevälja? Sellisel juhul oleks iga risttahuka
punkt vaateväljast väljas ning algoritm annaks negatiivse vastuse.
Korrektsem lahendus on kontrollida, kas igast
tasandist eespool asub vähemalt üks risttahuka
nurkadest. Kui ühest tasandist on kõik risttahuka
nurgad tagapool, võime kindlalt väita, et
risttahukas on vaateväljast väljas. See meetod
võib siiski vahel väärtulemusi anda. Selliseid
juhtumeid illustreerib joonis 2.
Objekt A on selgelt vaateväljast väljas, kuid B loetakse vaateväljasiseseks, sest objekti
ümbritseva risttahuka iga nurk asub vähemalt ühest vaateväljast eespool.
Muidugi oleks võimalik teha lisateste, et risttahuka vaateväljasisesust täpselt ära määrata,
kuid enamasti ei ole sellel ajalist võitu. See tähendab, et nende mõne väärtulemuse andnud
risttahukasiseste kolmnurkade graafikaprotsessorile saatmine on enamasti kiirem kui mitu
lisatingimust iga risttahuka vaateväljasisesuse hindamisel.
Vahel on kasulik teada, kas kera või risttahukas asub täielikult vaatevälja sees, on seal
osaliselt või on täielikult vaateväljast väljas. Risttahukas on täielikult vaatevälja sees, kui
kõik tema nurgad asuvad iga tasandi ees, täielikult väljas aga, kui kõik tema nurgad asuvad
täielikult ühe tasandi taga. Risttahukas on osaliselt vaatevälja sees sel juhul, kui kumbki
ülalloetletud variantidest tõeks ei osutu.
10
Joonis 2: väärtulemus
Kera on täielikult vaatevälja sees, kui ringi keskpunkt asub kõikidest tasanditest vähemalt
raadiuse võrra vaatevälja sisemuse suunas. Kera on täielikult vaateväljast väljas, kui ta asub
mõnest tasandist kaugemal kui oma raadius ning osaliselt vaatevälja sees, kui ei kumbki
variantidest tõeks ei osutu.
Alati, kui võimalik, tuleks eelistada kerasid risttahukatele. Põhjuseid selleks on mitmeid:
• Kera test ei tagasta väärtulemusi nagu vahel risttahukatest teha võib.
• Kera test on tunduvalt kiirem risttahuka testist, vajadest kõige rohkem 6 võrdlust.
Risttahuka test vajab kõige rohkem 48 võrdlust!
• Kerade kohta informatsiooni säilitamine võtab tunduvalt vähem ruumi mälus (vaja 4
muutujat, võrdluseks risttahukate korral 6. Kuupide korral piisaks samuti neljast).
• Keerlevate/pöörlevate objektide korral kera ei muutu, risttahuka korral tuleb risttahukat
kaasa keerata, nõudes lisaarvutusteks aega.
Keradel on ka üks viga: suurte kitsate või väikeste laiade objektide korral (näiteks postid,
madalad laiad hooned vms) on neid ümbritsevates kerades palju tühja ruumi. Kui objekt ise
asub vaateväljast väljas, kuid tühi osa kerast asub sees, tuleb ikkagi kogu objekt
graafikaprotsessorile saata. Sellistel juhtudel jaotatakse objektid sageli väiksemateks osadeks,
millede peal vaateväljapiirangut eraldi rakendatakse, vähendades nii vaadeldava tühja ruumi
osa ja tehes kogu kontrolli täpsemaks.
Kuigi on võimalik kontrollida ka hulknurkade (sh ka kolmnurkade) vaateväljasisesust, võtab
vastav test rohkem aega kui hulk- või kolmnurga otsene graafikaprotsessorile saatmine. Test
ise näeks välja samasugune nagu risttahuka vaateväljasisesuse kontroll, kuid risttahuka iga
nurga asemel tehtaks sama hulknurga iga punkti kohta.
Vaateväljapiirang on väga hea algoritm, kui on vaja kiirelt välistada suur hulk kolmnurki,
kuid selle implementeerimine võib suurte majasiseste maailmade korral võrdlemisi keerukas
olla: alati ei ole üheselt mõistetav, kuidas maailmas leiduvad kolmnurgad gruppidesse jaotada
11
nii, et algoritm võimalikult efektiivselt töötaks. Selleks otstarbeks on teisi algoritme,
milledest tuleb peagi juttu.
Vaateväljapiirang on mugav, kui staatilises maailmas jookseb ringi hulk arvuti poolt juhitud
vastaseid. Kiiresti saab välistada, milliseid neist peaks kuvama, milliseid mitte. Kuid suurte
maailmade puhul oleks tunduvalt efektiivsem siduda kõik need vastased juba otse mõne teise
algoritmiga, näiteks kaheksandpuuga, millest tuleb juttu järgmisena.
(Alamjaotis põhineb materjalist nr. 3 saadud infol.)
2.2. Kaheksandpuud
Kaheksandpuid (ingl. ainsuses octree) võib kutsuda järgmiseks evolutsiooniastmeks pärast
vaateväljapiirangut. Kaheksandpuude eesmärk on jaotada maailm mitmeteks väikesteks
kuupideks ning enne maailma kuvamist vaadata, millised kuupidest parajasti vaateväljas
(nähtavad) on.
Vaatleme kõigepealt staatilisi kaheksandpuid.
Algoritmi töö alguses ümbritseme kõik maailmas
leiduvad staatilised kolmnurgad (seinad, põrandad,
majad, liikumatud postid jms) ühe suure kuubiga.
Nüüd vaatame, kas kuubi sees on rohkem kui N
kolmnurka. Kui jah, jaotame kuubi kaheksaks
väiksemaks kuubiks, säilitades igaühes vaid need
kolmnurgad, mis vastava kuubi sisse jäävad. Nüüd
vaatleme igaühte kaheksast uuest tekkinud kuubist
edasi. Kui nende sees on rohkem kui N kolmnurka, jaotame nad omakorda uuesti kaheksaks
kuubiks. Algoritm töötab, kuni kogu maailm on jaotatud väikesteks kuupideks, mille sees ei
ole rohkem kui N kolmnurka.
Kuna vahel võivad olla (pisikesed) kolmnurgad kobarasse koondunud nii, et ilma suure töö ja
12
Joonis 3: Maailm enne jaotamist,pealtvaates
vaevata (ilma suure hulga jaotusteta, mis kaine mõistuse piiridest välja ulatuks) neid pooleks
jaotada ei saa, tuleb kasutusele võtta veel üks lisatingimus: kuupi võib väiksemateks osadeks
jaotada vaid siis, kui selle külje pikkus on suurem kui X.
Tihti tuleb ette seda, et üks kolmnurk ulatub kuubi piirkonnast välja teise kuubi sisse.
Kaheksandpuu koostamise hetkel on siin kaks võimalust: kolmnurk tükkideks jaotada7 või
lisada tervena igasse kuupi, mille sees ta paikneb. Kuigi esimene variant võib tunduda
asjalikum, tekib kolmnurga sirgega poolitamisel 2-3 uut kolmnurka, mis maailma
kuvamiskiirusele oma märgi jätta võivad. Lisaks kulub kõikide uute kolmnurkade kohta
informatsiooni hoidmiseks suur hulk operatiivmälu,
mis omakorda toob kaasa mitmeid probleeme. Seega
ei ole kolmnurkade poolitamine praegu lihtsalt
praktiline.
Otstarbekam on lihtsalt lisada iga loodava kuubi
kolmnurkade nimekirja kõik kolmnurgad, mille
mingigi osa kuubi sees on. Kuidas vältida sellisel
korral aga kolmnurkade ülejoonistamist, sellest tuleb
mõne lõigu pärast juttu.
Nagu iga ruumijaotusalgoritmiga jaotatud maailma korral, algab kaheksandpuu algoritmiga
osadeks jaotatud maailma kuvamine sellest, et seame paika “kaamera” vaatesuuna. Lisaks
sellele küsime rakendusliideselt sellist infot vaatevälja kohta, mida vaateväljapiirangu
algoritmid vajada võivad.
Maailma kuvamist alustame suurest kuubist. Kontrollime kõigepealt, kas suur kuup asub
vaateväljas täielikult, osaliselt või ei asu üldse. Kui kuup on täielikult vaateväljas, kuvame
kohe kõik kolmnurgad, mis seal sees on. Kui kuup ei ole vaateväljas, jätame kõik kolmnurgad
kuvamata. Kui kuup on osaliselt vaateväljas, kontrollime ükshaaval kaheksat väiksemat
7 kolmnurga osadeks jaotamise algoritmist tuleb juttu osas 2.7.1
13
Joonis 4: Maailm peale jaotamist,pealtvaates
kuupi, mis suure kuubi sees on. Kui üks väiksem kuup on tervenisti vaateväljas, kuvame kõik
selle sees olevad kolmnurgad. Kui väiksem kuup ei ole vaateväljas, jätame selle kuvamata.
Kui väiksem kuup on aga osaliselt vaateväljas, kontrollime taaskord ükshaaval kõiki
väiksema kuubi alakuupe.
Niiviisi rekursiivselt liikudes suudame lühikese ajaga välja filtreerida need osad maailmast,
mis on kindlalt kaamera vaateväljas. Joonis 5 kujutab ühe näidismaailma kujutamist.
Tumehall osa tähistab vaatevälja, helehallid kuubid on aga need, mis saadetakse
graafikaprotsessorile.
See loomulikult ei tähenda veel, et kõik
graafikaprotsessorile saadetud kolmnurgad ka nähtavad
on. Osa neist võib vaateväljast just natukene välja
ulatuda, teistel võib aga suur sein ees olla, kattes neid
täielikult. Seega pole kaheksandpuud küll kõige
optimaalsemaks lahenduseks igas olukorras, kuid
enamike maailmade korral (ning eriti seoses tänapäeva
graafikakaartidega, millede kolmnurkade kuvamise
kiirus on metsik) ei ole see mingiks takistuseks.
Kaheksandpuud annavad häid tulemusi praktiliselt iga maailma puhul, kuid kõige paremini
töötavad need suurte ning avarate välismaailmade ning ruumikate sisemaailmade korral.
Üks käsitlemata probleem on see, mis juhtub, kui kahes nähtavas naaberkuubis on üks ja
seesama kolmnurk. Lahendus on tegelikult võrdlemisi lihtne. Kuna kiiruse ning mälu huvides
sisaldab iga kuup endas niikuinii vaid kolmnurkade järjekorranumbreid, mitte aga kõikide
kolmnurkade punktide koordinaate, on samad kolmnurgad hõlpsalt eristatavad. Enne
kolmnurga kuvamist tuleb pärida spetsiaalsest järjemassiivist, millisel kaadril kolmnurk
viimati kuvati. Kui saadud informatsioon ühtib praeguse kaadri numbriga, ei tule kolmnurka
kuvada. Kui mitte, uuendame järjemassiivi informatsiooniga, et see konkreetne kolmnurk sai
kuvatud praegusel kaadril ning kuvame kolmnurga. Niiviisi hoiame hõlpsalt ning vähese
14
Joonis 5: Kaheksandpuu kuvamine
vaevaga ära kolmnurkade ülejoonistamise, mis võiks muidu suhteliselt ebameeldivaid
tulemusi anda.
Teine variant oleks kaheksandpuu koostamisel kolmnurgad salvestada vaid vähimate
mõõtmetega kuupidesse, kuhu need täielikult ära mahuvad. Sealhulgas mitte ainult
hargnematutesse kuupidesse, vaid ka nendesse, mis omakorda veelgi väiksemateks kolmnurki
sisaldavateks kuupideks hargnevad. See hoiaks täielikult ära ülejoonistamise ning ka selle
kontrolli, mida eelmises kuvamisalgoritmis ülejoonistamise tõkestamiseks tegema pidime.
Lisaks kolmnurkade organiseerimisele virtuaalmaailmas võib kaheksandpuudega teha palju
muudki. Natuke algoritmi muutes võiks nendesse sisestada informatsiooni erinevate liikuvate
objektide paiknemisest meie virtuaalmaailmas. Seesugune kaheksandpuu algoritm peab
võimaldama kiiret objektide eemaldamist ja liitmist nende üleminekul puu ühest osast teise.
Samuti tuleb vahel kuubid väiksemateks osadeks jagada või suuremateks ühendada, kui
objektide arv kuupides teatud piiri ületab. Kuna viimane operatsioon (jooksvalt uute kuupide
loomine / vanade eemaldamine) võib tihti ajaliselt kulukas olla, on mõistlikum ka tühi
maailm juba alguses tükkideks jagada.
Dünaamilisse kaheksandpuusse lisatud liikuvaid objekte oleks kõige targem vaadata kui
kerade või risttahukatega piiratud kujusid. Selline lahendus on kasulik, kui maailmas leidub
mitmeid väikesemõõtmeilisi objekte (näiteks arvuti poolt juhitud mängijad), kes kõik ringi
liiguvad. Lihtne vaateväljapiirang iga objekti peal eraldi oleks objektide suure arvu tõttu
võrdlemisi ajamahukas. Seega leiame vaid kaheksandpuu osad, mis parajasti nähtavad on,
ning kuvame vaid nendes leiduvad objektid. Niimodi võime mitme üksiku testi asemel
kuvada või välistada mitmeid objekte korraga.
Kaheksandpuid võib kasutada mitmetes erinevates tingimustes, kõige paremini avarate
välismaailmade kuvamisel, kuid need sobivad ka sisemaailmade korral, andes samuti häid
tulemusi. Kaheksandpuudega on ka hea organiseerida maailmas ringi liikuvaid objekte,
saades väheste testidega kõrvaldada mitmeid elukaid, kes muidu ekraanile ei oleks jõudnudki.
15
Kaheksandpuudel on üks noorem vend: neljandpuud (ingl. quadtrees). Ennekõike leiavad nad
rakendust kahedimensioonilistes mängudes, kuid samas ka kolmedimensiooniliste maailmade
korral, kus enamus tegevusest toimub ühel tasandil korraga või esineb vaid väheseid
erinevusi kõrguste vahel. Nende kasutamine on sageli lihtsam ning kiirem kuna puu
kuvamisel tuleb vähem teste teha. Seega leiavad need oma praktilisuse ja kiiruse tõttu
võrdlemisi laialdast kasutust maastike ning ühetasandiliste maailmade korral.
2.3. Binaarsed jaotuspuud
Ajal, mil esimesed Doom8 mängud välja tulid, oli ühe kolmnurga ekraanile joonistamine väga
kulukas tegevus. Veelgi kulukam oli enne kolmnurga joonistamist sügavuspuhvri abil
kontrollida, kas vastavale punktile ekraanil võib üldse joonistada või asub seal osa mõnest
teisest kolmnurgast, mis asetseb vaatlejale lähemal, joonistatava kolmnurga ees.
Appi tulid binaarsed jaotuspuud (ingl. Binary Space Partitioning trees) ehk lühidalt BSP-
puud. Lisaks joonistatavate kolmnurkade hulga üleüldisele vähendamisele on BSP-puude
üheks silmapaistvaimaks omaduseks joonistada maailmu kunstniku meetodil. Selle
meetodiga joonistatakse maailmu tagant ettepoole, nii nagu kunstnik joonistab maastikku.
BSP-puude, nagu iga teise algoritmi korral tuleb kolmnurki eelnevalt töödelda ning
gruppidesse jaotada.
Algoritmi nimest võib juba välja lugeda, et jaotamine toimub kahte ossa. Kuid mille alusel?
Enne jaotamist valime sellise kolmnurga, mille tasandist ette- ning tahapoole jääb enam-
vähem võrdne arv kolmnurki. Selle tasandiga jaotame kogu maailma kaheks osaks: eesmised
ning tagumised kolmnurgad. Edasi vaatleme mõlemat tekkinud osa kui iseseisvat maailma
ning poolitame need sama skeemi järgi.
8 http://www.idsoftware.com/
16
Kolmnurgad, mille tasanditega maailmu poolitame, võime paigutada eesmiste kolmnurkade
nimekirja, tekitades sedaviisi lehelise (ingl. leaf-based / leafy) puu, milles kõik kolmnurgad
puu alumistel lülidel (lehtedel) asuvad. Puu harud sisaldaksid vaid informatsiooni tasandite
kohta.
Teine variant oleks panna kolmnurgad kohe puu harudele, jättes lehed tühjaks ning tekitades
harulise puu (ingl. node-based tree).
Poolitamise lõpetame harulise puu korral siis, kui iga kolmnurk on mõnda harusse
paigaldatud, lehelise puu korral aga siis, kui igas lehes olevad kolmnurgad moodustavad
konveksse kere (iga kolmnurga pealt näeb igat teist kolmnurka ilma, et ükski teine kolmnurk
ette sattuda võiks).
Tihti tekib poolitamisel kolmnurki, mis mõlemale poole tasandit ulatuvad. Sellistel juhtudel
tuleb need lihtsalt poolitada. Kogu protsessi lõpuks saame kena organiseeritud puu.
Kuid ega BSP-puu genereerimisest niisama kasu pole. Oluline on ka see, et kolmnurgad
ekraanile jõuaksid. Ekraanile kuvame need varem mainitud kunstniku meetodil, mis põhineb
ühel lihtsal tõel: kui maailma jaotab kaheks üks tasand ning kaamera on paigutatud ühte neist,
siis ükski teises pooles olev kolmnurk ei saa katta ühtegi esimeses pooles olevat.
Sellise lihtsa tõega tuleb vaid kogu maailm läbi käia ning esmajärjekorras joonistada need
kolmnurgad, mis asuvad kõige kaugemal.
Algoritm näeks haruliste puude korral välja umbes seesugune:
joonista_puu(kolmnurgad)
{
kui(kaamera asub eespool tasandit)
{
joonista_puu(tasandi tagumise poole haru);
17
joonista(kõik haru kolmnurgad);
joonista_puu(tasandi eesmise poole haru);
} muidu {
joonista_puu(tasandi eesmise poole haru);
joonista(kõik haru kolmnurgad);
joonista_puu(tasandi tagumise poole haru);
}
}
Alustame kõige kõrgemast maailma jaotusest. Kontrollime, kummal pool jaotustasandit asub
kaamera ning joonistame kõik kolmnurgad, mis asuvad vastastasandis. Vastastasandi
kolmnurkade joonistamisel tehakse tõenäoliselt samasugune kontroll ning joonistatakse
jällegi kõigepealt kolmnurgad, mis on kaamerast kaugemal. Lõpuks jõuame järjega nii
kaugele, et joonistame tasandi enda kolmnurga ja sealt edasi liigume kaamerale järjest
lähemale, kuni lõpuks oleme kõik kolmnurgad tagant ettepoole joonistanud.
Vastupidi on samuti võimalik teha: joonistada kõigepealt kõik kolmnurgad, mis on kaamerale
ligidal, ning edasi järjest kaugemale liikuda. Tänapäeval võib selline variant isegi kiirem olla,
sest sügavuspuhver on jõuliselt arenenud ning niiviisi jääb ära pidev kolmnurkade
ülejoonistamine.
Samas kõik see ei lahenda ühte 3D graafika põhiprobleemi: kuidas võimalikult vähe
nähtamatut ning kõik nähtav graafikaprotsessorile saata? BSP-puude puhul on variante
mitmeid, neist tuleb ka peagi juttu. Kõige lihtsam on leida mõni geomeetriline kujund (kast,
kera vms), mis iga haru kõiki kolmnurki ümbritseb ning enne kolmnurkade kuvamist
kaheksandpuudega analoogsel viisil (läbi vaateväljapiirangu) vaadata, kas on seda üldse
mõtet teha.
BSP-puud olid suurepärased oma algusaegadel, kui vaid ühe kolmnurga kuvamine kulukas
oli. Nüüd, kui maailmad koosnevad miljonitest erinevatest kolmnurkadest,
kumeratest/ümmargustest pindadest, detailsetest objektidest ja muust seesugusest, on ühe
BSP-puu genereerimine võrdlemisi ebaefektiivne ning resurssinõudev. Rääkimata veel
sellest, et BSP-puudega võib mailmas leiduvate kolmnurkade arvu kiirelt mitmekordistada,
18
mis ei ole kellelegile hea. Igasuguste trikkidega oleks küll võimalik kolmnurkade poolitamine
ära jätta, kuid sellel ei ole tihti mõtet: parem juba mõnda muud algoritmi kasutada.
BSP-puudega (täpsemalt haruliste BSP-puudega) peab enne maailma kuvamist praktiliselt iga
kolmnurka korra puudutama. Kui maailma kuvamisel võib see liiga suur vaev olla (kiirem on
saata mitu kolmnurka korraga GPU-le kui neid eraldi läbi kontrollida enne saatmist), siis
operatsioonide puhul, millal niikuinii oleks kõiki kolmnurki vaja läbi vaadata (näiteks
kokkupõrkeid otsides), on BSP-puud väga kasulikud ning kiired. Kokkupõrgetel kasutatakse
ka tavaliselt vähendatud detailsusega maailmakaarte, mistõttu puude mälus hoidmine liiga
resurssivaenulik ei olegi.
BSP puud on kasutatavad staatiliste maailmade (seinad, põrandad, laed jms objektid, mis ei
liigu) juures, dünaamiliste maailmade korral tuleks peale iga muutust puu teatud osad uuesti
genereerida ning see võtaks hästi palju aega. Dünaamiliste maailmade korral on paremad
portaalisüsteemid või ABT-puud.
(Alamjaotis põhineb materjalidest nr. 7 ja nr. 6 lk 197-206 saadud infol.)
2.4. Portaalisüsteemid
Portaalisüsteeme kasutatavates 3D mootorites jaotatakse kogu maailm üksikuteks
sektsioonideks, mida omavahel ühendavad (nähtamatud) portaalid. Üks portaal ühendab
kahte sektsiooni.
Portaale võib lasta genereerida mõnel algoritmil (näiteks BSP) või neid võib kunstnik, kes
virtuaalmaailma disainis, paigutada ise sinna, kus Tema arvates neile sobiv koht on.
Portaalidega saab paljusid “võlutrikke” teha. Üks portaal ei pea ühendama kahte kõrvuti
asetsevat sektsiooni. Portaali võib näiteks iseendasse tagasi suunata, tekitades peegli. Kas
sinna sisse astuda võib või mitte, see on juba maailma looja otsustada. Samuti võib
portaalidega luua lõputu koridori, kus koridori alguses olev portaal on ühendatud lõpus
19
olevaga. Ka võib väljast imepisikesena näiva onni ukse portaali ühendada hoopis mõne suure
lossi sisemusega, tekitades rajatise, mis pärismaailmas oleks võimatu.
Nagu näha, on portaalid väga huvitavad olevused, millega võib teha imelisi asju. Kuid kuidas
need täpsemalt töötavad?
Iga sektsioon peab olema enam-vähem konveksne. See tähendab, et sektsiooni igast nurgast
peaks olema näha sektsiooni iga nurka. Vastasel juhul tekiks maailma kuvamisega probleeme
ning süsteem ei töötaks optimaalselt. Ühes sektsioonis võivad loomulikult asuda erinevad
objektid, sambad, pisikesed seinasüvendused, relvad, kollid jt olevused, mis ruumi kuju
üldjoontes ei muuda.
Maailma kuvama hakates joonistame kõigepealt selle
sektsiooni, milles me oleme. See tehtud, vaatame,
millised (selle sektsiooni) portaalidon nähtavad
(vaateväljas). Kuna sektsioon on konveksne, siis on kõik
vaateväljas olevad portaalid samuti ekraanil nähtavad.
Leides mõne seesuguse nähtava portaali, kitsendame
vaatevälja9 just selle portaali mõõtmetele (vaata joonist –
hall ala kujutab vaatevälja) ning kuvame portaali taga
oleva sektsiooni. Leides omakorda sellest sektsioonist mõne (kitsendatud) vaateväljas oleva
portaali, kitsendame vaatevälja veelkord ning kuvame ka selle sektsiooni. Protsess jätkub
niikaua, kuni kõik portaalid on rekursiivselt läbi käidud ja kogu maailm kuvatud.
Nagu varem mainitud, võib portaalide paigutuse jätta kunstniku rõõmuks või võib seda
automaatselt teha. Protsessi on kõige lihtsam automatiseerida BSP-puude abil, kasutades
portaalidena osasid tasanditest, mis BSP-puu moodustavad. Jutt on muidugi lehelistest BSP-
puudest.
Portaalid integreeruvad hästi teiste algoritmidega. Näiteks võib maja uks või aken viia välja
9 vaata peatükk 2.7.2
20
Joonis 6: portaalisüsteemi kuvamine
maastikuni, mille kuvamiseks kasutatakse kaheksandpuid või hoopis mõnda teist algoritmi.
Variante on palju.
Ka dünaamilise geomeetriaga (liikuvad seinad, koridorid jms) saavad portaalisüsteemid väga
hästi hakkama, kunstnikul tuleb vaid maailm oskuslikult luua.
(Alamjaotis põhineb materjalist nr. 8 saadud infol.)
2.5. Potentsiaalsed nähtavushulgad
Potentsiaalsete nähtavushulkade (ingl. Potential Visibility Sets ehk lühidalt PVS) all ei
mõelda konkreetset algoritmi. Pigem mõistetakse selle all mõne algoritmi töö tulemust,
kirjeldamaks millised maailma sektsioonid millistest teistest sektsioonidest vaadatuna
nähtavad on.
Kõrvaloleval joonisel on üks sektsioonideks jaotatud näidismaailm. Tähed märgivad
erinevaid sektsioone, hallid jooned kujutavad sektsioonide lõppe. Portaalisüsteemide korral
oleksid nende koha peal portaalid. Seekord aga vaatame,
milline oleks selle maailma PVS. Seda kujutab tabel nr. 1.
Sektsioon Mida näeb
A B, C, D, E
B A, C, D, E
C A, B, D, E, F
D A, B, C, E, F, H
E A, B, C, D, F, G, H
F C, D, E, G, H
G F, E, H
H D, E, F, G
Tabel 1: Näidis PVS
Maailma kuvades teeme kindlaks, millises sektsioonis me oleme. Vastavalt sellele kuvame
21
Joonis 7: näidismaailm
kõik teised nähtavad sektsioonid.
PVS on väga hea meetod maailma hästi kiireks kuvamiseks, kuid ülimalt segmenteeritud
maailmas võib see üpris palju mälu talletamiseks nõuda.
Samas ei ole PVS-i leidmine/arvutamine üheselt mõistetav tegevus. Kõige lihtsam variant
oleks iga sektsioon jaotada äärmiselt väikesteks osadeks ning vaadata, kas ühe sektsiooni
ühest osast leidub sirge teise sektsiooni mõnda ossa. Kui jah, näevad sektsioonid teineteist.
See variant on aga väga aeganõudev.
Saab ka palju kiiremalt, kuid selle algoritmi mahukuse ning keerukuse tõttu ei ole otstarbekas
seda praegu ümber jutustada. Huvilised võivad väga detailse kirjelduse leida Seth Teller'i
150-leheküljelisest teesist10. Lühidalt öeldes, luuakse Tema meetodiga üks tahke keha, mis
kirjeldab kõiki punkte, mis sektsiooni seest vaadates nähtavad on.
On olemas (programmeerijale) üks veelgi lihtsam versioon: jätta PVS-i genereerimine
kunstniku tööks. Tuleb lasta kunstnikul (või tema abilistel) mööda maailma ringi joosta. Kõik
sektsioonid, mida PVS-is näha ei ole, värvitakse näiteks kollaseks. Seda värvi nähes saab
kohe aru, et PVS-i sees on auk, mida tuleb täita vastava sektsiooni PVS-i lisamisega.
2.6. Adaptiivsed kahendpuud
Adaptiivsed kahendpuud (ingl. Adaptive Binary Trees) ehk lühidalt ABT-puud on oma
ülesehituselt sarnased kaheksandpuudega, sisaldades ka BSP-puude elemente. ABT-puude
eesmärgiks ei ole tagastada 100% täpset nimekirja ekraanil nähtavatest kolmnurkadest, vaid
teha seda ligikaudselt, pidades silmas tänapäeva graafikakaartide kiiruseid.
ABT-puu koostamine on ülesehituselt lihtne. Alustuseks tuleb kogu maailm ümbritseda suure
risttahukaga, mis on koordinaattelgedega paralleelne. Edasi hakkame, sarnaselt
kaheksandpuudega, maailma osadeks jagama. Risttahuka jagame kaheks uueks risttahukaks,
10 http://sunsite.berkeley.edu/TechRepPages/CSD-92-708?abstract=Teller
22
mis mõlemad on koordinaattelgedega samuti paralleelsed.
Maailma jagamine toimub seni, kuni risttahuka kolmnurkade arv on teatud piirist madalam
või kindla jagamissügavuseni. Kui tingimusteni on jõutud, sisestatakse informatsioon
kolmnurkade kohta kõige viimasesse (jagamata) risttahukasse.
Seni on kõik hea ja tore, kuid mille alusel jaotada kolmnurgad kaheks? Jaotustasandi valikul
tuleb arvesse võtta nelja tegurit:
1. Eelistatult tuleks lõigata risti teljega, mis on risttahukal pikimaks mõõtmeks. Näiteks,
kui risttahukal on kolmest mõõtmest suurim kõrgus, tuleks lõigata risti Y teljega.
2. Mõlemal tekkival risttahukal peaks ruumala (V1..2) enam-vähem sama olema.
3. Mõlemas tekkivas risttahukas peaks olema enam-vähem samapalju kolmnurki (n1..2).
4. Tasand tuleb valida nii, et see lõikaks osadeks võimalikult vähe kolmnurki.
Igale tegurile antakse kindel kaal (w1..4), mis määrab selle osatähtsuse lõpliku jaotustasandi
leidmisel. Kaalude valik sõltub maailmaspetsiifilistest tingimustest ning mootorist, mis
maailma kuvab. Seega tuleks kaale otsides arvestada neid eripärasid.
Lihtne meetod algoritmi elluviimiseks on võtta igalt teljelt 9 (või rohkem) risttahukasisest
punkti (ühest äärest teiseni näiteks vastavalt 10%, 20%, 30%, ... 90% kaugusel) ning arvutada
nende korral jaotuse sobivus.
1. T1 = 1 – (saadava risttahuka teljepikkus / jagamata maailma teljepikkus)
2. T2 = |V1 – V2| / (V1 + V2)
3. T3 = |n1 – n2| / kolmnurkade koguarv
4. T4 = osadeks jaotatavate kolmnurkade arv / kolmnurkade koguarv
Vaadeldava punkti ning tasandi sobivus jaotustasandiks avaldub ülalolevate väärtuste ning
nende kaalude korrutiste summana: T = w1T1 + w2T2 + w3T3 + w4T4.
23
Leiame vaadeldavate punktide hulgast vähima T väärtuse ning kasutame sellele vastavat
punkti ja tasandit jaotustasandina.
Risttahukat jaotades näeme, et tekib päris palju kolmnurki, mida tuleb osadeks tükeldada. Et
nende hulka vähendada, tuleb kõigepealt iga risttahuka omandiks teha need kolmnurgad,
millest üle poole kuulub risttahuka sisse.
Nende hulga vähendamiseks nihutame seda külge risttahukast eemale teise risttahuka sisse,
tekitades kahele risttahukale ühise osa. Selle käigus väheneb tükeldatavate kolmnurkade arv
tunduvalt. Algoritmi efektiivsuse huvides ei ole mõtet külge viia kaugemale kui 5-10%
esialgsest külgedevahelisest kaugusest. Heal juhul peaks tükeldatavate kolmnurkade hulk
kuni 90% vähenema. Kui juhtub olema kolmnurki, mis ikka risttahuka sisse ära ei mahu,
lõikame need pooleks ja anname väljaulatuva osa teisele risttahukale.
Sarnaselt käitume ka teise risttahukaga, suurendades kokkuvõttes kahe tahuka ühisosa.
Tihti juhtub, et loodud risttahukas sisaldab äärtes palju vaba ning kasutamata ruumi.
Algoritmi efektiivsuse huvides peaks sellest lahti saama. Selleks leiame uue risttahuka
siseseid kolmnurki piirava risttahuka, mida kasutame ka järgmisel jaotumisel.
Nüüd peaks kogu puu valmis olema. Viimase optimiseerimisena tuleks puu veel korra alt-üles
läbi käia, et tagada kõige optimaalsem risttahukate struktuur. Alustame alumistest
jagunevatest risttahukatest ning seame nendesiseseid kolmnurki ümbritsevaks risttahukaks
kahe madalama astme risttahuka ühendit ümbritseva risttahuka.
Lõpuks peaksime jõudma tagasi kõige esimese risttahukani, mis ümbritseb kogu maailma.
Kui uus risttahukas, mille kogu maailmale arvutasime, ühtib vanaga, on kõik väga hea ning
ABT-puu loomine on lõppenud. Kui mitte, on kusagil koodis viga sees.
24
ABT-puude kuvamine on väga selgeltmõistetav. Vaatame, kas risttahukas asub maailmas
sees. Kui jah, kontrollime järgmise astme risttahukaid. Kui ei, jätame risttahuka kuvamata.
Väga kiire ning efektiivne.
ABT-puid võib kasutada ka dünaamiliste objektide puhul. Kui mingi objekt liigub, tuleb
kaasa liigutada tema risttahukat ning kiirelt alt-üles liikudes taasühendada ABT-puu erinevate
astmete koordinaadid. Probleeme võib tekkida siis, kui objekt liigub väga kaugele. Niiviisi
väheneb küll puu efektiivsus, kuid seda mitte niipea. Probleemi lahenduseks oleks eraldatud
puuosade automaatne taasgenereerimine..
ABT-puud sobivad ennekõike maailmade jaoks, milles on palju või väga palju kolmnurki,
sajast tuhandest miljoniteni. Neid võib kasutada nii sisemaailmades kui ka väljaspool hooneid
ning arvestades tänapäeva graafikakaartide omadusi ning fakti, et ABT-puud jagavad
maailma märksa ühtlasemalt kui seda teevad nii neljand-, kaheksand- kui ka BSP-puud, võib
ABT-puid lugeda üheks tänapäeva efektiivsemaks ruumijaotusalgoritmiks.
(Alamjaotis põhineb materjalidest nr. 4 ja nr. 5 saadud infol.)
2.7.Suuremate algoritmide osadena esinevad algoritmid
2.7.1. Kolmnurga jaotamine osadeks
Mitmes algoritmis on meil ette tulnud kohti, kus on vaja üks hulknurk (täpsemalt siis
kolmnurk) jaotada ühe tasandiga kaheks tükiks.
Algoritm selle tegemiseks on väga lihtne: tuleb hulknurga punkte järjest vaatlema hakata. Kui
üks punktidest asub tasandi ees ning teine taga, leiame punkte ühendava sirge ning tasandi
lõikepunkti. Jätame selle meelde. Edasi läheb lihtsalt: kui mõni punkt on tasandi taga, kuulub
see tagumise kolmnurga punktide hulka. Kui mõni punkt on kolmnurga ees, kuulub see
eesmise kolmnurga punktide hulka. Tasandiga lõikuvatel sirgetel tuleb leida sirge ja tasandi
lõikekoht ning see mõlema kolmnurga punktide hulka lisada.
25
Niiviisi käime läbi kõik punktid esimesest viimaseni. Algoritmi
lõpuks on meil 2 iseseisvat hulknurka. Kogu protsessi illustreerib
joonis 8.
(Alamjaotis põhineb materjalist nr. 6 lk 154-156 saadud infol.)
2.7.2. Vaatevälja kitsendamine
Vaatevälja kitsendamine hulknurgaga leiab laialdast kasutust
portaalisüsteemide juures. Et seda teha, peab kõigepealt vaatama, kas hulknurk on üldse
vaateväljas nähtav. Kuidas seda teha, sellest oli juttu vaateväljapiirangu peatükis.
Vaatevälja kitsendamiseks on vaja leida see osa hulknurgast, mis jääb vaatevälja sisse. See
toimub lihtsalt: on vaja kasutada eelmises osas (2.7.1) kirjeldatud meetodit iga tasandi korral,
millest on mõned hulknurga punktid eespool, mõned tagapool. Niiviisi leiame vaateväljas
paikneva osa sellest hulknurgast.
Vaateväli saab alati alguse ühest punktist. Samast kohast saab alguse ka uus vaateväli. Uue
vaatevälja esitasandiks on sama tasand, millel hulknurk asub, tagumine tasand jääb samaks
(näeme sama kaugele kui enne). Küljetasandite (tasandid, mille punktideks on vaatevälja
alguspunkt ning kaks punkti hulknurgalt) arv võib muutuda, kuid nende põhimõte jääb ikkagi
samaks.
Nüüdseks peaks käes olema mugav vaateväli, mida võib optimaalselt portaalisüsteemide
juures kasutada.
2.8. Ruumijaotusalgoritmide kokkuvõte
Ühte 3D mootorite põhiprobleemidest – kuidas võimalikult kiirelt kogu stseen ekraanil
kuvada – üritab lahendada päris mitu erinevat algoritmi. Alustades lihtsast
vaateväljapiirangust ning lõpetades mitmete keerulisemate algoritmidega nagu BSP-puud,
26
Joonis 8: hulknurgatükeldamine
ABT-puud, portaalid jms, igaüks oma plusside ning miinustega.
Peab tunnistama, et ei leidu ühtegi väga universaalset ja toimivat algoritmi, mis igas
tingimuses suurepäraseid tulemusi annaks. Väliste ning avarate stseenide jaoks sobivad väga
hästi neljand- ja kaheksandpuud ning ABT-puud. Portaalisüsteemid ning BSP-puud jäävad
sellise keskkonna kuvamisel hätta.
Sisemaailmades võib kasutada praktiliselt kõiki algoritme, kuid kõige optimaalsemalt
töötavad portaalisüsteemid ning erinevad PVS-i realiseerivad algoritmid (kasvõi näiteks
BSP+PVS kombinatsioon). Kaheksandpuude ning ABT-puude korral võib vahel
graafikaprotsessorile liiga palju sellist infot saata, mis niikuinii jääks seina taha varju.
Viimasel aja algoritmidest on universaalseimad ABT-puud, mis annavad igas olukorras häid
tulemusi. Uute modernsete (hästi detailsete sise- ja välis-) maailmade korral on ABT-puud
väga kasulikud.
Õige 3D mootor ei tohiks aga piirduda vaid ühe tehnikaga. Kõige parem oleks omavahel
erinevaid algoritme kombineerida ning ühendada, kasutades neid vastavalt vajadustele.
Näiteks viitaks portaalisüsteeme kasutavas majas üks aken (portaal) väliskeskkonnale, mida
kuvatakse läbi kaheksandpuude. Sarnaselt viitaks ABT-puid kasutavas välismaailmas mõne
maja uks PVS-i kasutavale sisemusele.
Seega on hea, kui igas keskkonnas kuvab kolmnurki selle keskkonna jaoks mõeldud algoritm.
Enne kindla algoritmi kasuks otsustamist tuleks läbi kaaluda kõik variandid, võibolla isegi
erinevaid teste teha, kuni selgub parim.
Kui ajalistel või muudel põhjustel see kõne alla ei tule, on ABT-puud heaks valikuks.
27
3. VALGUSTUS
Üks olulisemaid asju 3D mootorite juures on reaalne valgustus. Kahjuks on päris reaalset
valgustust võimatu simuleerida, kuid leidub palju algoritme, mis annavad väga lähedase
tulemuse.
Kuid milleks üldse valgustust vaja on? Kas niisama kolmnurkade kuvamisest ei piisagi? Ei.
Kui valgustusele tähelepanu mitte pöörata, oleks kogu maailm ühtlaselt hele. Kõik objektid,
nii kauged, lähedased, kaetud või katmata näeksid täpselt ühesugused välja. Erinevusi tooksid
sisse muidugi erinevad tekstuurid pindade peal, kuid neist üksinda ei piisa. Kogu maailm
omandaks “võltsi” maigu. Kujutage ette, kui igav oleks pärismaailm, kui kõik kohad oleksid
täiesti ühtlaselt valgustatud. Pakun, et mitte liiga ahvatlev.
3.1. Radioossus
Üks parimaid algoritme reaaluse lähedase valgustuse saamiseks on radioossus (ingl.
radiosity).
Radioossuse põhitõde on see, et iga valgus, mis mingisse punkti jõuab, peegeldub tagasi ning
valgustab teisi nähtavaid kehi. Seega tuleb kaotada piir objektide ning valgusallikate vahel:
valgusallikad on vaid väga tugeva valgusega valgustatud kehad.
See põhitõde on analoogne sellega, kuidas valgus pärismaailmas töötab. Lihtne näide sellest
on kino, kus leidub vaid üks valgusallikas: projektor, mis suunab valguse vaid ühele
vastuvõtjale – ekraanile. Ekraanilt peegeldub aga kogu valgus iga inimeseni, kes saalis istub.
Inimeste näkku ei jõua valgus mitte otse projektorist, vaid ekraanilt peegeldudes.
Radioossust ei saa veel reeglina reaalajas kogu maailma jaoks arvutada ning seega tuleb seda
eeltööna (enne maailma kuvamist) teha. Algoritmi tööks jaotame kogu maailma
28
imepisikesteks tükkideks. Kõik arvutused toimuvad vaid üksikute tükkide vahel – kolmnurki
ei kasutata. Kuna me oma maailma lõputult väikesteks osadeks kahjuks jaotada aga ei saa,
tuleb kokku leppida tükkide kindlates mõõtmetes. Oluline on meeles pidada, et mida
väiksemad tükid, seda reaalsem kõik välja näeb, kuid seda kauem kulub kõige arvutamiseks.
Radioossuse arvutus ei piirdu üksiku kiire tehtega. Seda tuleb iga tüki kohta maailmas mitu
korda läbi teha enne, kui soovitud tulemus käes on. Igal korral valime välja ühe tüki, millest
väljuv valgus (seda väärtust kutsutakse radioossuseks nagu ka kogu algoritmi) on kõige
heledam. Esimesel korral oleks selleks kindlasti mõni valgusallikas. Tükk valitud, arvutame,
kui suur osa sellest jõuab teiste tükkideni ning lisame selle teistest väljuvale valgusele.
Lõpuks tühistame vaadeldava tüki väljuva valguse (seame selle nulliks). Kui kõrgeima
energiaga tüki valgus on alla kindlat väärtust, lõpetame tegevuse. Kui mitte, leiame uuesti
kõrgeima energiaga tüki ja teeme kogu protseduuri uuesti. Tulemus on järgnev:
Jääb vaid üks küsimus: kuidas arvutada, kui palju energiat ühest tükist teise kantakse?
Üldlevinud valem selleks on järgmine:
29
Joonis 9: Cornelli kast
Fi− j=1A i∫A i
∫A j
cosicos j
r2vi− jdA jdA i
Valemis esinevaid tähiseid:
vi− j tähistab kahe tüki vahelist nähtavust: 1 kui ühest tükist näeb teist takistusteta
(sirgjooneliselt), vastasel juhul 0.dA j ,dA i lõputult väikeste tükkide i ja j osade pindala.r kaugus kahe tüki vahel.i , j nurk kahe tüki vahelise kiire ning tükkide normaalvektorite vahel.
Mõte on selles, et üritame leida lahendit lõputult palju kordi lõputult väikeste tükkide korral
ning lõpuks tulemused kokku liita, kuid ajalistel kaalutlustel see lihtsalt ei ole praktiline! Kes
see ikka viitsib igavesti oodata?
Teeme valemisse väikesed kohendused ning voilá: saame küll veidike ebatäpsemaid tulemusi,
kuid seda vaid üheainsa tehtega. Ajaline võit missugune!
Fi− j=1A i
cosicos j
r2vi− jA jA i
Fi− j=cosicos j
r2vi− jA j
Radioossust on võimalik ka teisiti, nn. poolkasti meetodil arvutada. Seejuures kasutatakse ka
graafikaprotsessori abi protsessi kiirendamiseks. Kuidas see tegevus täpselt välja näeb, seda
võib lugeda Hugo Elias-e kodulehelt11.
Radioossus on olemuselt lihtne ning võimas algoritm, millega võib maailmad väga kenasti
ära valgustada nii, et nad reaalsest praktiliselt ei erinegi12. Kahjuks töötab algoritm enamasti
piisavalt kiiresti vaid staatilise geomeetria puhul, mistõttu tuleb liikuvate objektidega reeglina
midagi muud ette võtta.
(Alamjaotis põhineb materjalist nr. 6 lk 428-439 saadud infol.)
11 http://freespace.virgin.net/hugo.elias/radiosity/radiosity.htm12 http://www.graphics.cornell.edu/online/box/compare.html
30
3.2. Teised meetodid staatilise valgustuse leidmiseks
Lisaks radioossusele on veel teisigi meetodeid suhteliselt reaalse valgustuse saamiseks.
Üks neist on footonkaardistus (ingl. photon mapping), mis simuleerib valgusallikate poolt
väljastatud footonite teed mööda maailma. Sellest on põhjalikult kirjutanud Henrik Wann
Jensen13.
Monte Carlo meetodist kirjutab Eric Veach oma teesis14. Meetodi näol on tegu veel ühe
ülirealistliku algoritmiga, mille kasutamine arvutimängudes oleks ilmselt üleliigne vaev.
Kuid siiski on algoritm mainimist väärt.
Algoritme on teisigi, kuid ülalloetletud on staatilise geomeetria ning paigalpüsivate
valgusallikate korral põhilised valgustuse arvutamise algoritmid. Kuigi kõik need algoritmid
on ülesehituselt huvitavad, leiab mängudes sellel eesmärgil kõige rohkem kasutust just
radioossus.
3.3. Dünaamilised valgusallikad
Sageli tuleb valgusallikatel liikuda. Sellistel juhtudel ei piisa enam eelnevates peatükkides
tutvustatud algoritmidest, mis valgustust vaid staatiliste valgusallikate ning liikumatu
geomeetria korral leiavad.
Kindlate muutustega (ühe toa valgus, mis lülitub sisse ja välja) on need siiski suutelised
toime tulema. Tuleb vaid iga oleku korral (lüliti sees või väljas) valguse leviku mõjuala leida
ning selles valgustus uuesti arvutada. Hiljem peab ühendama vaadeldud muutuva piirkonna
hetkelise valgustuse ülejäänud maailma omaga.
Näiteks on meil üks tuba, kus valgust saab sisse ja välja lülitada. Tuppa viib vaid üks avaus,
13 http://graphics.ucsd.edu/~henrik/papers/14 http://graphics.stanford.edu/papers/veach_thesis/
31
mis on ühenduses koridoriga, kus kunagi pime ei ole. Tuba tuleb vaadelda eraldi ning
arvutada valgustatus siis kui valgus on sisse lülitatud. Kui maailma kuvamisel leiame, et tuba
on valgustatud (lüliti on sees), lisame juba joonistatud valgusele toa valguse. Kui lüliti on
väljas, valgustab tuba siiski see vähene valgus, mis läbi avause siseneb.
Mis saab kui valgus võib ringi liikuda? Sellisel juhul varemmainitud meetoditest enam ei
piisa.
Enimlevinud rakendusliidestes on selleks implementeeritud
lihtsad matemaatilised valgustusmudelid, mis leiavad objekti
igale kolmnurgale (Lambert varjustus), iga kolmnurga igale
tipule (Gouraud varjustus) või igale ekraanile joonistatud
pikselile (Phong varjustus) selle heleduse. Heleduse arvutamise
võetakse kasutusele mitmeid tegureid. Ennekõike oleneb tulemus
valguse liigist (punktvalgusallikas või suunatud valgus), pinnast
(matt või peegeldav), valguse ja pinnanormaali vahelisest
nurgast, valguse värvist ja muust seesugusest. Sellise valgustuse kasutamiseks konsulteerige
oma rakendusliideste dokumentatsiooniga.
Kuigi need valgustusmeetodid on täiesti sobivad
lihtsamate maailmade jaoks, tuleb vahel valgustuse
veelgi täpsemaks simuleerimiseks erivõtteid kasutada.
Näiteks punktvalgusallikate korral võib punktist
väljuvat valgust simuleerida joonisel 10 näidatud
kerakujulise tekstuuri paigutamisega valgustatud
kolmnurkade peale, tekitades valguse kätte sattuvatele
kohtadele heleda laigu, nagu näha jooniselt 11.
Meetod on äärmiselt lihtne. Kujutades väljuvat valgust kindla raadiusega kerana võib iga
kolmnurga iga punkti kohta leida kas see asub selle kera sees või mitte ning kui kaugel
32
Joonis 10: Näidistekstuur, mustvärv tähistab nähtamatut osa
Joonis 11: Kahe punktvalgusallika poolttekstuuridega valgustatud kast.
raadiusest ta on. Seda informatsiooni teades leiab millise punkti tekstuurist ühendada
kolmnurga tipuga. Tulemuseks on joonisel 11 kujutatud ilus värviline laik.
33
TERMINID
3D mootor – 3D engine / tarkvara, enamasti mõne arvutimängu osana, mis vastutabkolmemõõtmelise maailma ekraanile kuvamise eest. Paljud 3D mootorid tegelevad ka lisaksfüüsikaseaduste simuleerimisega, arvuti poolt juhitud objektide tegevuse või strateegiaarvutamisega ning muu seesugusega
ABT-puud – Adaptive Binary Trees = adaptiivsed kahendpuud
adaptiivsed kahendpuud – puud, mille korral maailm jagatakse pidevalt kaheks osaks,võttes arvesse tegureid nagu osade ruumala, kolmnurkade arv osades jms
API – Application Program Interface = rakendusliides
ARB – Architecural Review Board / komitee, mis haldab OpenGL-i
arvutigraafika – meetodid ja vahendid objektide ja andmete piltkujutiste loomiseks,salvestuseks ja esituseks arvuti abil
binaarne jaotuspuu – puu, kus maailm jaotatakse ühe tasandiga kaheks osaks, võttes aluseksmõlema poole kolmnurkade arvu vähese erinevuse
BSP-puu – Binary Space Partitioning Tree = binaarne jaotuspuu
CPU – Central Processing Unit = keskprotsessor
Direct3D – DirectX komponent mis haldab ruumilst graafikat
DirectX – Microsofti arendusplatvorm mängude jõudluse tõstmiseks Windowsi keskkonnas
dünaamiline – liikuv / mitte staatiline
footonkaardistus – valgustuse leidmise meetod, kus jälgitakse üksikute footonite teedmaailmas
GPU – Graphics Processing Unit = graafikaprotsessor
graafika = arvutigraafika
34
graafikaprotsessor – graafikaoperatsioonide kiirele sooritamisele spetsialiseeritud riistvara
haruline puu – node-based tree / puu, mis hoiab andmeid oma harude peal, puu madalamadlülid, lehed, jäetakse tühjaks
kaamera – punkt, millest algab vaateväli
kaheksandpuud – puud, kus maailm jaotatakse igal astmel kaheksaks võrdsete mõõtmetegakuubiks
keskprotsessor – arvuti talitlust kõrgeimal hierarhiatasemel juhtiv protsessor
koll – dünaamiline objekt, mis maailmas ringi liigub, arvutimängudes enamasti negatiivsemõjuga
kolmnurk – kolme küljega hulknurk / väikseim ühetasandiline geomeetriline kuju / kõikisuuremaid objekte on võimalik jaotada mitmeteks väiksemateks kolmnurkadeks
konveksne hulknurk – hulknurk, mille igast punktist on võimalik tõmmata sirge igasse teisepunkti nii, et sirge ei lõika ühtegi hulknurga külge
konveksne kere/sektsioon – ruumiosa, kus iga kolmnurga igast punktist on võimaliktõmmata sirge iga teise kolmnurga igasse punkti ilma, et mõni teine kolmnurk ette jääks
kunstniku meetod – graafika kuvamise meetod, kus kuvame kaugemal asuvad asjad ennelähemal asuvaid
leheline puu – leaf-based tree / puu, kus harud kirjeldavad vaid hargnemisi, kõikinformatsioon (kolmnurgad) asuvad puu madalamatel lülidel (lehtedel)
maailm = virtuaalmaailm
Microsoft – personaalarvutite tarkvara suurimaid tootjaid
Monte Carlo meetod – meetod väga reaalsuselähedase valgustuse saavutamiseks
MS-DOS – Microsoft Disk Operating System / ühetegumiline ainukasutajaoperatsioonisüsteem eeskätt 16-bitistele personaalarvutitele
neljandpuud – puud, kus maailm jaotatakse igal astmel neljaks võrdsete mõõtmetegaruuduks
objekt – mistahes geomeetriline primitiiv või suurem kolmnurkadest koosnev moodustis
35
OpenGL – Open Graphics Library / mitmeplatvormiline 3D graafika rakendusliides
Pac-Man – kaheksakümnendate populaarseim videomäng
peegel – portaalisüsteemides portaal, mis ühendab ühte sektsiooni iseendaga
portaal – portaalisüsteemides kahte sektsiooni ühendav tasand
portaalisüsteem – süsteem, mis koosneb sektsioonidest ja neid omavahel ühendavatestportaalidest
potentsiaalne nähtavushulk – nimekiri kõikidest sektsioonidest, mida on ühest sektsioonistvõimalik näha
PVS – Potential Visibility Set = potentsiaalne nähtavushulk
radioossus – radiosity / valgustuse arvutamise meetod, kus iga valgus, mis mingisse punktijõuab, peegeldub osaliselt tagasi ning valgustab teisi kehi
rakendusliides – reeglistik, mille alusel rakendusprogramm saab operatsioonisüsteemiltsüsteemifunktsioone
riistvara – arvutisüsteemi seadmestik
ruumijaotusalgoritm – algoritm jagamaks virtuaalmaailma väiksematesks osadeks
sektsioon – kindel ruumiosa, portaalisüsteemides piireldud kolmnurkade ning portaalidega
SGI – Silicon Graphics Interactive / firma, mis pani algatuse OpenGL-ile
sisemaailm – mõne ehitise või rajatise sees paiknev virtuaalmaailm, võib sisaldada aknaid,uksi vms välismaailma
staatiline – paigalseisev / mitte dünaamiline
sügavuspuhver – depth buffer / hoiab iga ekraanipikseli kohta informatsiooni sellest,millisele kaugusel sellel pikselil kujutatud kolmnurk on, et ära hoida kolmnurkadeülejoonistamist
tarkvara – infotöötlussüsteemi programmid, protseduurid, reeglid jms
tekstuur – kolmnurga pinna ilmet iseloomustavad tunnused/pildid
vaateväli – frustum / piirkond maailmast, mis jõuab arvutiekraanile
36
vaateväljapiirang – meetod leidmaks millised objektid asuvad vaateväljas ning kas neid onvaja graafikaprotsessorile saata
valgustus – kolmnurkade osade värvuse muutmine arvestades maailma iseärasusi
välismaailm – hoonetest/rajatistest väljaspoole jääv osa virtuaalmaailmast / lageda taev allasuv virtuaalmaailm
virtuaalmaailm – kolmnurkadest koosnev keskkond
Xbox – Microsofti mängukonsool
(Peatükis kasutatud materjalist nr. 1 saadud infot.)
37
KOKKUVÕTE
Viimase paarikümne aasta jooksul on reaalaegne arvutigraafika läbi elanud suuri
arenguetappe. Oleme jõudnud hetke, millal ruumiline arvutigraafika arvutimängudes on sama
igapäevane nähtus kui näiteks püsiühendus Internetti.
Aastate jooksul on mitmete eesmärkide saavutamiseks leiutatud palju erinevaid algoritme.
Müts maha kõigi nende inimeste ees, kes nende peale tulid. Kuigi lõpptulemus on paljudel
algoritmidel enam-vähem sama, on selleni jõudmine tihti erinev ning sageli isegi
eritingimuste lahendamisele kohandatud.
Kuigi erinevate eesmärkide lahendamiseks on algoritme palju, leidub siiski mitmeid
ülesandeid, mis veel ammendavat vastust saanud pole. Alati on vaja veelgi paremaid,
kiiremaid algoritme järjest ilusamate ning realistlikumate tulemuste saavutamiseks, et
asendada olemasolevaid. Järgnevate aastate jooksul võib mitmeid uusi ja huvitavaid leiutisi
ilmuda.
Ka graafikaprotsessorid arenevad jõuliselt. Numbrid, mis täna veel imestama panevad võivad
juba mõne aasta pärast jätta ükskõikseks. Riistvara paranemisega muutuvad ka mängud
ilusamateks ning detailsemateks. Ilmselt ei lähe palju aega mööda, kui võib juba reaalajas
jooksutada stseene ruumilistest filminduslikest meistriteostest.
Uurimistöö käigus jõudsime järeldustele, et vaatevälja piiramiseks on praegu üks
universaalsemaid algoritme ABT-puud. Radiosity on jätkuvalt üks enamlevinuid valgustuse
vallas. Lähiajal ei kao kumbki neist kuhugi. Mõlemad on väga head valikud inimesele, kes
soovib oma 3D mootorit luua.
Kuigi selle uurimistööga sai tehtud esimesed sammud reaalaegse ruumilise graafika
38
eestikeelse dokumentatsiooni vallas, leidub siiski veel paljusid algoritme, mis on kirjeldamist
väärt. Seega ei ole kogu töö veel tehtud ning edasisesks arenguks on küllalt võimalusi.
Me elame huvitaval ajal. 21. sajand tuleb reaalaegse arvutigraafika jaoks huvitav. Oleme kõik
õnnelikud, et saame sellest osa võtta.
39
KASUTATUD MATERJALID
1. Hanson, V. ja Tavast, A. Arvutikasutaja sõnastik Inglise-Eesti, 2000.
2. Roy, P. Direct3D vs. OpenGL: Which API to Use When, Where, and Why,
http://www.gamedev.net/reference/articles/article1775.asp, 2002.
3. Morley, M. Frustum Culling in OpenGL,
http://web.archive.org/web/20021013181230/www.markmorley.com/opengl/frustumcullin
g.html, 2000.
4. Lombard, Y. ABT - What it is and how to build them,
http://www.gamedev.net/community/forums/topic.asp?topic_id=123169, 2002.
5. Lombard, Y. ja Campbell, A. ABT questions: construction and use,
http://www.gamedev.net/community/forums/topic.asp?topic_id=163240, 2003.
6. Walsh, P. Advanced 3-D Game Programming Using DirectX 8.0, Worldware Publishing,
Inc, 2002. Lk 197-206, 154-155, 428-439.
7. Hammersley, T. BSP Trees, http://tfpsly.planet-d.net/Docs/TomHammersley/bsp.htm.
8. Rendering With Portals, http://gamecode.tripod.com/tut/tut06.htm. Materjal hangitud
24.02.2004.
40