Završni rad br. 38

Robert Sajko

  • Uvod
  • Fizikalni model svjetla
  • Lokalni modeli osvjetljenja
  • Globalni modeli osvjetljenja
  • Zaklanjanje ambijenta
  • PRT
  • Implementacija
  • Zaključak
  • Literatura
  • Sažetak
  • Preuzimanje

Implementacija

Programski jezik odabran za implementaciju algoritma predizračunatog prijenosa zračenja jest C++, zbog svoje moćne objektne paradigme i efikasnosti. Grafičko programsko sučelje korišteno pri izradi aplikacije jest OpenGL, koji je odabran prvenstveno zbog jednostavnosti uporabe. Zahtjevi nad programskom potporom su sljedeći: mogućnost rada s bilo kojim virtualnim okruženjem priloženim u odgovarajućem formatu; simulacija tog virtualnog okruženja u stvarnom vremenu s naprednim osvjetljenjem, koje pokazuje (barem neke) globalne učinke osvjetljenja koji se ne mogu simulirati postojećim lokalnim modelima. Prvi zahtjev je ispunjen tako da se virtualno okuženje interpretira kao skup objekata koji su raspoređeni u prostoru na neki predodređeni način, i koji posjeduju predodređene karakteristike. U toj interpretaciji, virtualno okruženje možemo nazvati scenom, a komponente virtualnog okruženja objektima scene. S tim u vidu, za potrebe demonstracije programske potpore, konstruirani su jednostavni 3D objekti korištenjem Autodesk Maya 2008 alata, i zatim eksportirani u jednostavni i općeprihvaćeni .obj format. U svrhu povezivanja tih individualnih objekata u cjelovitu scenu, potrebna je dodatna datoteka koja služi kao opisnik scene. Kao takva, njen je format vrlo jednostavan – riječ je tek o popisu objekata koji se pojavljuju na sceni. Budući da se u Maya alatu objekti mogu već prije eksportiranja translatirati, rotirati i postaviti na scenu u odgovarajuću poziciju, format opisa scene ne treba sadržavati takve podatke. Jedino što je potrebno jest označiti željenu teksturu. Dakle, opis scene se sastoji od stavaka sljedećeg oblika:

"NazivDatotekeObjekta.obj" "NazivDatotekeTeksture.tga"

Navodnici su potrebni da se omoguće praznine u nazivu datoteka. Sljedeći i glavni zahtjev se može ispuniti korištenjem predizračunatog prijenosa zračenja, što je trenutno ponajbolji izbor za interaktivnu simulaciju globalnog osvjetljenja. Nakon definiranja svih zahtjeva i općih smjernica njihovog ispunjenja, moguće je dizajnirati arhitekturu programske potpore. Prvi korak dizajna jest razlučivanje odgovornosti, i njihovo pridjeljivanje paketima. Shodno tome, možemo razlikovati četiri glavna paketa, kako to prikazuje sljedeći dijagram:

 

Slika 22. Objektni model implementacije.

 

Temeljni paket jest System, koji je odgovoran za sve sistemske operacije poput stvaranja prozora za iscrtavanje, rukovanje ulaznim jedinicama itd. Zatim, paket SceneManager sadrži  i upravlja svim podacima koji određuju scenu. Između ostalog, razredi iz tog paketa će biti zaslužni za učitavanje .obj datoteka. Najvažniji paket jest PRT, koji sadrži svu funkcionalnost potrebnu za provođenje algoritma predizračunatog zračenja, dakle i predprocesiranje scene, i samo iscrtavanje. Na kraju, pomoćni paket VectorMath sačinjavaju razredi za rad s pravokutnim i sfernim vektorima. Sada slijedi detaljniji pregled svakog od ovih paketa, sa UML dijagramima razreda, te objašnjenjima.

 

 

System

System

Slika 23. UML dijagram razreda CSystem i CSystem::CCamera.

 

Ovaj paket se sastoji od dvaju razreda, CSystem i CSystem::CCamera. Prvi razred enkapsulira računalni sustav i njegove ulazne jedinice. Stvaranje prozora za iscrtavanje se vrši direktnim pozivima Windows API-ja, dok se inicijalizacija crtaćeg konteksta ostvaruje OpenGL naredbama. Grafička kartica, predstavljena nekim programskim sučeljem poput OpneGL-a, se također može shvatiti kao jedinica unutar sustava. Razlikuje se faza inicijalizacije (stvaranje crtaćeg konteksta), faza aktivnog rada (opetovano iscrtavanje scene, određeni broj puta u sekundi), te faza deinicijalizacije i prekida rada (otpuštanje crtaćeg konteksta, oslobađanje memorije). Iz tog razloga, kao što se vidi na gornjem dijagramu, i funkcije upravljanja iscrtavanjem su podijeljene na te faze. Komunikacija s ulaznim jedinicama se ostvaruje pomoću DirectInput tehnologije, što je dio Microsoftovog DirectX skupa tehnologija. Reaktivnost aplikacije na ulazne podražaje (pritisci tipaka, pomaci miša) je ostvarena korištenjem paradigme vođene događajima (event driven paradigm). Naime, pojedine korisničke akcije su shvaćene kao događaji, te sustav detektira i identificira različite događaje korištenjem nekog sklopovskog sučelja niže razine (konkretno, DirectInput-a). Zatim, ti se događaji propagiraju kroz sustav posredstvom raspačivača (što je ovdje CSystem) tako da se pozivaju odgovarajuće funkcije rukovoditelji (event handlers). U općenitom slučaju, bilo koji objekt u aplikaciji može registrirati svoje rukovoditelje kod nekog objekta raspačivača, no u našem slučaju jedini raspačivač jest razred CSystem, a jedini rukovoditelj CSystem::CCamera (doduše, radi brzine izvođenja, provedena je optimizacija tako da se izbjegne dvostruko indirektni poziv, pa je tehnički gledano CSystem i raspačivač, i rukovoditelj). Kako se može naslutiti, razred CSystem::CCamera jest apstrakcija koncepta virtualne kamere, i sadrži podatke o položaju očišta (točka u kojoj se kamera nalazi), gledišta (točka fokusa kamere, odnosno „smjer gledanja“), te takozvani vektor prema gore, koji kazuje koji smjer je za kameru „gore“. Dakle, pritiscima tipaka i pomacima miša, moguće je pomicati pogled bilo gdje u sceni. Osim ove osnovne interaktivnosti, dozvoljeno je pomicati i točku izvora svjetlosti, i to tako da se ona rotira oko ishodišta za bilo koja dva kuta (θ, φ), pri čemu možemo reći da (θ, φ) zapravo predstavljaju sferne koordinate izvora svjetlosti. Konkretna izvedba rotacije projicirane funkcije upadnog svjetla je objašnjena u teorijskom izlaganju algoritma predizračunatog prijenosa zračenja, a implementirana je u CPRT razredu, koji je objašnjen kasnije u ovom tekstu. U ovom trenutku valja spomenuti da aplikacija podržava i klasično osvjetljenje Blinn-Phong lokalnim modelom, sklopovski dostupnim putem OpenGL-a. Budući da je podržano više od jednog istovremenog izvora svjetla, tipkama 1-8 se bira trenutno aktivno svjetlo (dakle, ono na koje se rotacija odnosi). Radi sklopovskog ograničenja na maksimalno osam istovremenih izvora svjetla, aplikacija ne podržava više od tog broja aktivnih svjetala, iako sam broj svjetala tek neznatno utječe na performanse iscrtavanja algoritmom PRT. Također, registriraju se i neke kontrole za olakšavanje testiranja programa. Sve navedene kontrole su pregledno dane sljedećom tablicom:

 

Tablica 1. Kontrole programa.

Translacija kamere unaprijed

↑    (strelica prema gore)

Translacija kamere unazad

↓    (strelica prema dolje)

Translacija kamere ulijevo

←  (strelica ulijevo)

Translacija kamere udesno

→  (strelica udesno)

Rotacija kamere lijevo-desno

Pomicanje miša lijevo-desno

Rotacija kamere gore-dolje

Pomicanje miša gore-dolje

Odabir trenutno aktivnog svjetla

Tipke 1-8

Povećavanje/smanjivanje θ koordinate izvora

Q / A

Povećavanje/smanjivanje φ koordinate izvora

W / E

Paljenje/gašenje iscrtavanja tekstura

T

Paljenje/gašenje iscrtavanja normala

N

Paljenje/gašenje iscrtavanja vektora izvora

L

Standardno OpenGL osvjetljenje

F1

Osvjetljenje PRT algoritmom

F2

 

 

SceneManager

SceneManager

Slika 24. UML dijagram razreda CScene i CObject.

 

Sljedeći bitan skup razreda su CScene i CObject. Ova dva razreda redom predstavljaju enkapsulacije scene, te objekata scene. Iz tog razloga, aplikacija u pravilu treba instancirati samo jedan objekt tipa CScene. Konstruktor tog razreda automatski učitava zadanu ulaznu datoteku s opisom scene, te stvara potreban broj objekata, koje pohranjuje u internom spremniku. Sam postupak parsiranja .obj datoteka se delegira na novostvorene CObject objekte. Pojedini objekt scene je definiran svojim topološkim i geometrijskim podacima. Geometrijski podaci su jednostavno skup točaka koji definiraju poligone objekta, najčešće trokute, dok su topološki podaci logičke prirode. Naime, oni govore na koji način se prethodno definirane točke interpretiraju, odnosno, kojim redosljedom tvore poligone. Upravo ovakav pristup se koristi u .obj formatu, zato što omogućava da se vrhovi poligona zapišu samo jedanput, a zatim po potrebi dijele između susjednih poligona, čime se ostvaruje značajna ušteda na memoriji. Međutim, radi jednostavnosti kasnije obrade, vrhovi i poligoni se u CObject klasi ne pohranjuju odvojeno, već se točke jednostavno nižu onim redosljedom kojim tvore poligone, što znači da se većina njih ponavlja, i do nekoliko puta. Pojedini vrh je predstavljen strukturom CObject::SVertex, koja osim pozicije točke u prostoru pohranjuje i neke druge podatke vezane uz taj vrh, a to su koordinate teksture, boja, te koeficijenti projekcije funkcije prijenosa svjetlosti u sferne harmonike, u toj konkretnoj točki. Broj tih koeficijenata je limitiran na 16, budući da se pokazalo da je već i tako malen broj sasvim dovoljan za kvalitetne rezultate. Po potrebi, ovo se može i promijeniti, budući da nema nikakvog utjecaja na izvođenje samog algoritma (osim produljenja trajanja). Kako se može primijetiti, struktura za pohranu vrhova sadrži dva polja za pohranu boje. Razlog tomu je taj, što aplikacija podržava i klasično, lokalno osvjetljenje, i PRT osvjetljenje. Budući da je krajnji rezultat PRT algoritma boja pojedinog vrha, tu boju je potrebno pohraniti. No, boja utječe i na OpenGL-ov ugrađeni model osvjetljenja, pa je potrebno sačuvati bijelu boju za svaki vrh, i po potrebi alternirati između njih. Sam izvor svjetla je enkapsuliran CScene::SLight strukturom, koja pohranjuje sferne koordinate izvora, koeficijente izvorne projekcije funkcije osvjetljenja tog izvora, te rotirane koeficijente projekcije, koji su dobiveni rotacijom izvornih koeficijenata za kutove koji odgovaraju trenutnim sfernim koordinatama izvora. Izvorne koeficijente je potrebno sačuvati zato jer postupak rotacije opisan u prethodnom teorijskom izlaganju pretpostavlja apsolutnu rotaciju, a ne relativnu. Budući da je tokom izvršavanja aplikacije moguće tek dobivati relativne pomake između pojedinih iscrtavanja scene, ti relativni pomaci se moraju zbrajati. Zatim, izvorni koeficijenti projekcije se rotiraju za te zbrojene, apsolutne kutove.

 

 

PRT

PRT

Slika 25. UML dijagram razreda CPRT.

 

Jezgra cijele aplikacije jest upravo razred CPRT. Naime, ovaj razred sadrži svu funkcionalnost potrebnu za provedbu algoritma predizračunatog zračenja. Glavne funkcije, koje ujedno čine javno sučelje razreda, su sljedeće:

void computeTransferFunctions(

CScene& Scene,

fpProgressCallback ProgressCallback,

bool FastMode

)

Ulazni argumenti:

Scene

referenca na instancu CScene klase

ProgressCallback

pokazivač na funkciju povratnog poziva

FastMode

brzo predprocesiranje (true) ili sporo (false)

Ova funkcija je zaslužna za predprocesiranje scene. Iz tog razloga, potrebno je prije njenog pozivanja imati izgrađen objekt scene. Sam postupak predprocesiranja može biti vrlo dugotrajan, stoga se omogućava objavljivanje napretka. U tu svrhu, upotrijebljen je mehanizam funkcije povratnog poziva (callback function). Naime, korisnik treba napisati vlastitu funkciju odgovarajućeg prototipa, i predati pokazivač na tu funkciju kao argument funkciji computeTransferFunctions. Tokom predprocesiranja, funkcija čiji je pokazivač predan će povremeno biti pozivana, točnije, prilikom svakih 1% obavljenog posla. Iz tog razloga, ovaj mehanizam se naziva povratnim pozivom. Generalno govoreći, očekuje se da će ta povratno pozivajuća funkcija obavještavati korisnika o napretku algoritma, primjerice, osvježavanjem nekog elementa grafičkog sučelja aplikacije i/ili tekstualnim ispisom. Upravo je to slučaj u ovoj aplikaciji, kako će biti objašnjeno kasnije. Posljednji argument funkcije specificira način obrade scene. Naime, kako je spomenuto u teorijskom izlaganju, funkcija prijenosa čija se projekcija računa za svaki vrh može biti različitog oblika. Ona može uključivati samo difuznu refleksiju, bez detekcije zaklonjenosti, ili se pomoću zrake sjene može dodatno utvrditi i da li je trenutni vrh u sjeni. Ovaj drugi način je očito sporiji, pa je za potrebe testiranja scene ili same aplikacije mnogo praktičnije preskočiti taj korak i značajno ubrzati obradu scene.

 

void computeLightFunctions(

CScene& Scene

)

Ulazni argumenti:

Scene

referenca na instancu CScene klase

Ova funkcija također vrši projekciju u sferne harmonike, no ovaj put za svjetla. Budući da je za funkciju izlaznog isijavanja izvora uzeta konstanta, ovaj je postupak relativno jednostavan i brz. Geometrijske karakteristike scene nisu bitne, no podaci o svjetlima jesu, pa je potrebna referenca na objekt scene, koji sadrži podatke o svjetlima.

 

static void RotateSHCoefficients(

int numBands,

double* unrotatedCoeffs,

double* rotatedCoeffs,

double theta, double phi

)

Ulazni argumenti:

numBands

Red projekcije (broj pojaseva sfernih harmonika)

unrotatedCoeffs

Izvorni koeficijenti projekcije (prije rotacije).

theta, phi

Željene sferne koordinate izvora.

Izlazni argumenti:

rotatedCoeffs

Pokazivač na spremnik rotiranih koeficijenata.

Funkcija za rotiranje koeficijenata projekcije vrši prethodno opisan postupak rotacije. Prvo se rekurzivnim postupkom generiraju matrice za rotaciju oko Z i X osi, a zatim se one izmnože i time stvori konačna matrica rotacije. Množenjem izvornih koeficijenata s tom matricom dobiju se rotirani koeficijenti, koji se pohranjuju u spremnik čiji je pokazivač predan kao argument funkciji. Ova funkcija je deklarirana kao statička, iz razloga da se omogući njeno korištenje i bez instanciranja razreda kojemu pripada.

 

Ostali članovi razreda CPRT, koji sačinjavaju njegov privatni dio, su određene pomoćne funkcije koje nemaju svrhu same za sebe, već su potrebne za prethodne tri funkcije. U ovu skupinu spadaju metode za generiranje uniformnih uzoraka sfere, konstruiranje asociranih Legendre polinoma, evaluaciju funkcija sfernih harmonika u danoj točki, generiranje matrica rotacije oko Z i X osi, i slično. Implementacije tih metoda su direktno preuzete iz teorijskog izlaganja algoritma.

 

 

VectorMath

 

VectorMath

Slika 26. UML dijagram razreda CartesianVector i SphericVector.

Posljednji, i najmanji paket se sastoji od dvaju razreda za olakšavanje računanja s vektorima, zadanih sfernim ili kartezijevim koordinatama. Njihovo javno sučelje jest identično, i uključuje često korištene operacije poput rotacije oko proizvoljne osi, normalizacije, skaliranja, skalarnog množenja itd. Zbog česte i raširene potrebe za vektorskom matematikom, ove operacije su enkapsulirane u zasebnom paketu, kojeg koriste svi ostali paketi.

 

 

*

*  *

 

Dizajn paketa i razreda programskog rješenja predstavlja njegovu logičku arhitekturu, čiji je pregled upravo dan. Fizički dizajn uključuje raspodjelu aplikacije u izvršne module i podatke. Budući da implementirani algoritam jasno razlikuje dvije odvojene faze – predprocesiranje i samo iscrtavanje – i programska podrška je fizički dizajnirana kao dvije odvojene aplikacije. Prva aplikacija se naziva SHBuilder, i služi za obradu scene i generiranje koeficijenata projekcije funkcije prijenosa. Druga aplikacija, koja se naziva SHDemo, učitava prethodno generirane koeficijente, i na temelju njih vrši iscrtavanje scene u stvarnom vremenu. Pritom obje aplikacije koriste iste, prethodno opisane pakete razreda. Jedina je razlika u tome što SHBuilder sadrži grafičko korisničko sučelje, za lakšu interakciju s programom. Iz tog razloga, umjesto paketa System, koristi se Microsoftova biblioteka MFC, koja omogućava jednostavniju izgradnju Windows aplikacija s grafičkim korisničkim sučeljem. Sada možemo na konkretnom primjeru pokazati korisnost prethodno objašnjenog mehanizma povratnog poziva – kako predprocesiranje scene napreduje, tako se osvježava ProgressBar kontrola (horizontalni stupac, inicijalno prazan, koji progresivno postaje sve ispunjeniji), te se ispisuje očekivano vrijeme trajanja obrade scene (na temelju trajanja obrade dotad obrađenog dijela scene). Budući da vrijeme procesiranja može biti dugotrajno (na Pentium IV 2.0 GHz računalu je trajalo otprilike tri sata za demonstracijsku scenu), u prilogu ovom radu se nalazi aplikacija s demonstracijskom scenom s već predizračunatim koeficijentima. Rezultati implementacije su u skladu s očekivanjima. Iz testiranja na nekoliko računala, osvjetljenje PRT algoritmom je tek oko 15%, do najviše 40% sporije nego osvjetljenje dobiveno ugrađenim OpenGL modelom osvjetljenja (pogledati donju tablicu). Valja imati na umu da je ovdje riječ o naivnoj implementaciji, koja direktno slijedi teorijske rezultate bez ikakvih optimizacija. Prvi korak koji bi svaka ozbiljna implementacija trebala poduzeti jest prebacivanje izračuna boje pojedinog vrha na grafičku karticu. Iako je ta operacija vrlo jednostavna, i sastoji se tek od 16 množenja i zbrajanja, takve operacije grafičko sklopovlje izvršava mnogo brže nego glavni procesor. Također, budući da će sve podatke o vrhovima pohranjivati i obrađivati grafička kartica, ne gubi se vrijeme na komunikaciju glavnog procesora i grafičke kartice. Osim toga, i postupak predprocesiranja scene se može barem djelomično implementirati nekim jezikom sjenčanja, i time značajno ubrzati. Optimizirane implementacije PRT algoritma bi zapravo lako mogle biti i brže od lokalnih modela osvjetljenja, ukoliko uzmemo u obzir situacije s više od jednog svjetla na sceni. Naime, konačna boja nekog vrha jest skalarni umnožak vektora koeficijenata tog vrha, i konačnog vektora koeficijenata osvjetljenja. Taj konačni vektor osvjetljenja se dobije kao zbroj vektora koeficijenata svih izvora. Taj se zbroj može izračunati jedanput, a zatim, ukoliko dođe do rotacije pojedinog svjetla, dovoljno je izračunati razliku u odnosu na nerotirano svjetlo, i taj vektor razlike pribrojiti ukupnom zbroju. Drugim riječima, kompleksnost izračuna boje danog vrha time postaje konstantna, uopće ne oviseći o broju svjetala. S druge strane, kod lokalnih modela osvjetljenja, za svako svjetlo se cjelokupan postupak računanja mora ponoviti. Sljedeća tablica ilustrira performanse (izražene u broju iscrtanih slika u sekundi) ove neoptimizirane implementacije, i dobro pokazuje da je upravo centralni procesor usko grlo:

 

Tablica 2. Performanse implementiranog algoritma.

 

1 svjetlo

8 svjetala

Pentium IV 2.0 GHz,
GeForce4 Ti4400
(starost 6 godina)

Blinn-Phong

102

66

PRT

59

16

 

 

 

 

Intel Core Duo, 1.67 Ghz,
Radeon x1600
(starost 2 godine)

Blinn-Phong

184

163

PRT

131

72

 

 

 

 

Intel Core 2 Duo 2.6 Ghz,
Radeon HD3870
(starost mjesec dana)

Blinn-Phong

268

243

PRT

209

124

 

Promatrajući generirane slike, do izražaja dolazi činjenica da algoritam računa boju po vrhu. Naime, prilikom kreiranja konačne slike, u postupku rasterizacije se mora odrediti boja svakog pojedinog slikovnog elementa. Budući da boju specificiramo po vrhovima, slikovni elementi koji upadaju na područja između pojedinih vrhova, nakon projekcije u prostor slike, imaju nedefiniranu boju. Jednostavno rješenje problema jest linearna interpolacija boje između dva susjedna vrha. No, to znači da ukoliko imamo nedostatan broj vrhova, diskretizacija će biti očita, budući da će zamjetno velika područja slike biti obojana istom bojom. To također znači da neće biti finih prijelaza osvjetljenja, već će biti vidljive grube razine. Primjer daje slika 27, nastala isključivanjem tekstura (usporedbe radi, ta je slika nastala u istovjetnim uvjetima kao slika 21).

Slika 27. Primjer artefakata nastalih zbog interpolacije osvjetljenja između vrhova.

 

Na sjeni koju baca torus, uočavaju se dvije razine – najtamnija, središnja sjena, koja se naziva umbra, te okolna, svjetlija sjena koja se naziva penumbra. Prijelaz između umbre i penumbre bi trebao biti gladak, no lako se mogu uočiti diskretne razine osvjetljenja, budući da su pojedini vrhovi koji su unutar umbre gotovo potpuno crni, no dijelovi poligona koji bi također trebali biti unutar umbre su sivi, budući da je boja tih slikovnih elemenata dobivena linearnom interpolacijom između vrha unutar umbre, i vrha unutar penumbre. Na sjeni koju torus baca na samog sebe, takvi artefakti su mnogo teže uočljivi, budući da se torus sastoji od 10800 jedinstvenih vrhova, dok se okolne plohe sastoje od svega 2700 vrhova. Međutim, ukoliko usporedimo ovu sliku sa slikom 21, koja je ista ali s uključenim teksturama, navedeni artefakti više uopće nisu vidljivi, budući da ih tekstura čini nezamjetnima. Također, današnje aplikacije već barataju i s mnogo većim brojem vrhova, tako da ovo zasigurno više nije problem.