Primele șapte capitole ale acestui manual au acoperit grafica computerizată în timp real, adică sistemele grafice în care o imagine poate fi generată într-o fracțiune de secundă. Cazul tipic este un joc video, unde cadre noi pot fi redate de până la șaizeci de ori pe secundă. Scene foarte complexe și cu aspect realist pot fi redate în timp real, folosind tehnicile acoperite în această carte și imensa putere de procesare a GPU-urilor moderne, plus câteva trucuri și algoritmi avansați. Cu toate acestea, grafica în timp real încă nu poate egala realismul graficii computerizate de cea mai înaltă calitate, cum ar fi cea care poate fi găsită în filme. De fapt, CGI (imagini generate de computer) din filmele de astăzi este uneori imposibil de distins de realitate. Obținerea unei grafici de o astfel de calitate poate necesita ore întregi de calcul pentru a reda un singur cadru. (Conform articolului Wikipedia despre filmul de animație din 2013, Frozen, unele scene complexe din acel film au folosit 30 de ore de calcul pentru a reda fiecare cadru.)
Acest capitol este o scurtă privire asupra unor tehnici care pot fi utilizate pentru grafică de foarte înaltă calitate. Discuția va fi în termeni generali. Nu voi oferi exemple de cod sau discuții detaliate despre matematica din spatele tehnicilor, dar sper să ofer cel puțin o înțelegere conceptuală de bază.
Primul lucru pe care ar trebui să-l înțelegeți, însă, este că majoritatea celor învățate până acum se aplică în continuare. Scenele sunt încă compuse folosind primitive geometrice, transformări, materiale, texturi și surse de lumină (deși poate folosind proprietăți ale materialelor și iluminare mai avansate decât am întâlnit până acum). Designerii grafici care lucrează la CGI pentru un film pot vedea previzualizări în timp real ale lucrărilor lor, care sunt redate folosind tehnici pe care le-am acoperit. Scena finală pe care o vedeți în film este doar redată folosind tehnici diferite, mult mai intensive în calcul.
Trasarea razelor (Ray Tracing)
Trasarea razelor este probabil cea mai cunoscută tehnică pentru grafică de calitate superioară. Ideea din spatele ei nu este complicată: pentru a afla ce vedeți când priviți într-o anumită direcție, luați în considerare o rază de lumină care ajunge la locația dvs. din acea direcție și urmați acea rază de lumină înapoi pentru a vedea de unde a venit. Sau, așa cum se spune de obicei, proiectează o rază din locația ta într-o direcție dată și vezi ce lovește. Asta vezi când te uiți în acea direcție. Operația de determinare a ceea ce este lovit de o rază se numește trasarea razelor (ray tracing). Este fundamentală pentru trasarea razelor și pentru alte tehnici grafice avansate.
Proiectarea razelor (Ray Casting)
Am văzut deja radiografierea utilizată de obiecte de tip THREE.RayCaster în API-ul three.js (Subsecțiunea 5.3.2). Un Raycaster ia un punct inițial și o direcție, date ca vector. Punctul și vectorul determină o rază, adică o linie semi-infinită care se extinde de la un punct de plecare, într-o anumită direcție, până la infinit. Raycaster-ul poate găsi toate intersecțiile razei cu un set dat de obiecte într-o scenă three.js, sortate după ordinea distanței față de punctul de plecare al razelor. În acest capitol, suntem interesați de prima intersecție, cea care este cea mai apropiată de punctul de plecare.
Pentru a aplica proiectarea razelor la randare, să presupunem că avem o scenă formată din obiecte în spațiul tridimensional, folosind lumini punctuale și lumini direcționale pentru iluminare. Vrem să redăm o imagine a scenei dintr-un punct de vedere dat. Este convenabil să ne imaginăm imaginea ca un fel de fereastră dreptunghiulară prin care este vizualizată scena. Având un punct în imagine, trebuie să știm cum să colorăm acel punct. Pentru a calcula o culoare pentru punct, începem prin a proiecta o rază din poziția privitorului prin punct și în scenă. Vrem să găsim prima intersecție a acelei raze cu un obiect din scenă:
În această ilustrație, scena conține mai multe sfere roșii și două puncte luminoase. O rază este proiectată din punctul de vedere (A) printr-un punct (B) din imagine. Raza intersectează două dintre sfere, dar suntem interesați doar de punctul de intersecție (C) cel mai apropiat de punctul de vedere. Acesta este punctul vizibil în punctul B din imagine.
Trebuie să calculăm culoarea pe care privitorul o va vedea în punctul B. Pentru aceasta, la fel ca în OpenGL, avem nevoie de un vector normal în punctul C și avem nevoie de proprietățile materialului suprafeței în punctul C. Aceste date trebuie să fie calculabile din descrierea scenei. Culoarea vizibilă depinde și de lumina care luminează suprafața. Luați în considerare o sursă de lumină și fie L vectorul care indică din C în direcția luminii. Dacă unghiul dintre L și vectorul normal este mai mare de 90 de grade, atunci sursa de lumină se află în spatele suprafeței și, prin urmare, nu adaugă nicio iluminare. Altfel, putem folosi din nou proiectarea razelor: Proiectați o rază din C în direcția L. Dacă acea rază lovește un obiect înainte de a ajunge la lumină, atunci acel obiect va bloca lumina de la acea sursă să ajungă la C. Acesta este cazul Luminii 2 din ilustrație: Raza din C în direcția Luminii 2 intersectează un obiect în punctul E înainte de a ajunge la lumină. Pe de altă parte, punctul C este iluminat de Lumina 1. O rază dintr-un punct de pe o suprafață în direcția unei surse de lumină se numește rază de umbră, deoarece poate fi utilizată pentru a determina dacă punctul de la suprafață se află în umbra unui alt obiect.
Cu toate aceste informații, putem colora punctul B din imagine folosind aceeași ecuație de iluminare utilizată în OpenGL (Subsecțiunea 4.1.4). Și, ca bonus, obținem umbre, ceea ce este greu de realizat în OpenGL! (Dacă raza din punctul de vedere care trece prin B nu lovește niciun obiect din scenă, atunci lui B i se va atribui o culoare de fundal sau o culoare „cer” care variază în funcție de direcții diferite. Sau poate întreaga scenă este înconjurată de o cutie cerească, iar o rază care nu lovește niciun alt obiect va lovi cutia cerească.)
Proiectarea razelor este simplă din punct de vedere conceptual, dar detaliile de implementare pot fi complicate. Sferele sunt de fapt destul de simple. Există o formulă pentru găsirea intersecțiilor unei linii cu o sferă, iar un vector normal într-un punct de pe o sferă are aceeași direcție ca linia de la centrul sferei până la acel punct. Presupunând că sfera are un material uniform, avem toate datele de care avem nevoie.
Cu toate acestea, suprafețele sunt adesea date ca plase triunghiulare, cu proprietăți specificate doar la vârfurile triunghiurilor. Să presupunem că punctul de intersecție găsit de proiectorul nostru de raze se află într-unul dintre aceste triunghiuri. Va trebui să calculăm proprietățile acelui punct de intersecție prin interpolarea valorilor proprietăților care au fost specificate la vârfurile triunghiului.
Algoritmul de interpolare folosește de obicei ceva numit coordonate baricentrice pe triunghi: Dacă A, B și C sunt vârfurile unui triunghi, iar P este un punct din triunghi, atunci P poate fi scris în mod unic sub forma a*A + b*B + c*C, unde a, b și c sunt numere în intervalul de la zero la unu, iar a + b + c = 1. Coeficienții a, b și c se numesc coordonate baricentrice ale punctului P din triunghi. Dacă o anumită cantitate are valori V(A), V(B) și V(C) la vârfurile triunghiului, atunci putem folosi coordonatele baricentrice ale lui P pentru a obține o valoare interpolată la P:
V(P) = a*V(A) + b*V(B) + c*V(C)
Cantitatea poate fi, de exemplu, culoare difuză, coordonate de textură sau un vector normal. (Desigur, tot omit o mare parte din calculele matematice – cum să testezi dacă o linie intersectează un triunghi și cum să găsești coordonatele baricentrice ale punctului de intersecție. Există formule, dar conceptual, nu ar adăuga prea mult la discuție.)
Sursa: David J. Eck, Introduction to Computer Graphics (Eck), LibreTexts, licența CC BY-NC-SA 4.0. Traducere și adaptare Nicolae Sfetcu
Descoperă mai multe la MultiMedia
Abonează-te ca să primești ultimele articole prin email.




Lasă un răspuns