Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
AccessAdobe photoshopAlgoritmiAutocadBaze de dateCC sharp
CalculatoareCorel drawDot netExcelFox proFrontpageHardware
HtmlInternetJavaLinuxMatlabMs dosPascal
PhpPower pointRetele calculatoareSqlTutorialsWebdesignWindows
WordXml


Monitoare - modul de functionare si redare a imaginii

calculatoare



+ Font mai mare | - Font mai mic



Monitoare - modul de functionare si redare a imaginii

Informatii generale

2.1 Vedere stereoscopica



Oamenii si multe animale au doi ochi care privesc (aproximativ) in aceeasi directie. Fiecare din ochii nostri vede lumea dintr-un alt punct de vedere, de aceea imaginile obtinute cu ambii ochi sunt usor diferite. In creier, aceste 2 imagini sunt combinate intr-o singura imagine tri-dimensionala (model mental) (vezi figura 2.1).

Figura 2.1 Vedere stereoscopica [1]

Acest tip de sistem de vedere este numit vedere binoculara (sau stereoscopica). In natura este comuna la multe animale pradatoare, dar de asemenea si printre primate care necesita sa parcurga medii tri-dimensionale complexe. Este una din metodele folosite de oameni pentru a percepe adancimea si de a estima distantele.

Un alt tip de sistem de vedere este vederea monoculara, care este comuna printre multe din animalele vanate in natura. Multe dintre ele au ochii de ambele parti ale capului pentru a avea un camp de vedere mai larg. Aceasta reduce sansa ca un pradator sa le prinda. Imaginea primita de fiecare ochi este procesata separat in creier.

2.2 Perceperea adancimii

Vederea stereoscopica este mecanismul principal de percepere a adancimii, dar nu este singurul. Exista si alte mecanisme [3]:

Paralaxa de miscare: Can iti misti capul dintr-o parte in alta, obiectele care sunt apropiate tie se misca relativ mai repede decat obiectele care sunt mai indepartate.

Interpunere: Un obiect care blocheaza un alt obiect se afla in fata acelui obiect.

Lumina si umbra: Umbrele ofera informatii despre forma tri-dimensionala a unui obiect. Daca se cunoaste pozitia sursei de lumina umbra poate de asemenea sa ofere informatii despre pozitia obiectului in sine.

Marimea relativa: Obiectele de aceeasi marime aflate la distante diferite sunt percepute de catre ochi ca avand marimi diferite. Aceasta relatie marime-distanta ofera informatii despre distanta obiectelor a caror marime este cunoscuta. Intr-o imagine plana acest effect poate fi redat prin utilizarea proiectiei de perspectiva.

Neclaritate data de distanta: Obiectele indepartate apar neclare.

Toate aceste mecanisme sunt folosite impreuna de catre creierul nostru pentru a percepe adancimea.

2.3 Monitoare 3D

Cand privesc o imagine traditionala, ambii ochi vad aceeasi imagine. Desi aceasta imagine plana poate contine mai toate indicatiile despre profunzime, ii lipseste cea mai importanta: efectul stereoscopic. Acest efect poate fi redat prin oferirea unei imagini diferite ambilor ochi. Un monitor care reuseste acest lucru se numeste monitor stereoscopic.

2.3.1 Disparitatea ecranului

Diferenta dintre cele doua imagini de pe ecran este interpretata de catre creier ca fiind adancime (vezi figura 2.2. si 2.3).

Figura 2.2. Adancimea perceputa in spatele ecranului

Figura 2.3. Adancimea perceputa in fata ecranului

Distanta dintre punctele de imagine stanga si dreapta corespunzatoare este numita disparitatea ecranului, si poate fi masurata in milimetri sau pixeli. Poate fi clasificata in trei categorii:

Disparitate pozitiva - obiectele apar in spatele ecranului (figura 2.2)

Disparitate zero - obiectele apar in planul ecranului

Disparitate negativa - obiectele apar in fata ecranului (Figura 2.3)

Disparitatea limitativa a ecranului

Disparitatea folosita la un monitor stereoscopic trebuie sa fie restrictionata doar la disparitatea orizontala. Disparitatea verticala cauzeaza incordarea ochilor [15].

Folosind valori mari (pozitive si negative) ale disparitatii la un monitor 3D cauzeaza discomfort de vedere. Aceasta are de-a face, printre altele, cu relatia acomodare/convergenta [5]. Creierul nu poate contopi cele doua imagini daca ele sunt prea diferite una de cealalta. Lucrul acesta nu va fi discutat mai departe in aceasta lucrare. Noi folosim doar rezultatele care mentioneaza ca disparitatea trebuie sa fie limitata la un anumit interval care este comfortabil vederii. Disparitatea maxima depinde de tipul de ecran 3D.

2.3.2. Adancimea perceputa

Adancimea perceputa P este in functie de distanta de vedere z, separarea ochilor e si de disparitatea ecranului d (vezi figura 2.4.)

Figura 2.4 Adancimea perceputa este data de urmatoarea funtie: [4]

(2.1)

Distanta dintre ochi este de 64 milimetri in medie pentru adulti [5]. Sa presupunem ca distanta de vedere este de 1 metru. Aceasta are ca rezultat graficul din figura 2.5. Pentru valorile lui d care tind spre zero, raportul e/d va deveni ∞, facand ca P sa devina zero. Pentru valorile lui d care sunt apropiate de e, adancimea perceputa va tinde catre infinit (care cauzeaza discomfort de vedere).

2.3.3 Separarea imaginii

Pe un monitor stereoscopic cele doua imagini necesare pentru ambii ochi sunt afisate intr-o anumita masura "simultan". Tot ceea ce este nevoie mai departe este sa se asigure ca fiecare imagine sa ajunga la ochiul corect. De obicei lucrul acesta se realizeaza oferindu-i privitorului un tip de ochelari care realizeaza separarea ambelor imagini. Lucrul acesta este necomfortabil si este unul dintre motivele pentru succesul limitat al monitoarelor stereoscopice pentru consumatori [3, 5].

Figura 2.5. Adancimea perceputa in spatele ecranului in functie de disparitatea ecranului (pentru o distanta de vedere de 1 metru si o distanta dintre ochi de 64 milimetri).

2.4 Monitoare Philips 3D

Philips Research a dezvoltat cateva monitoare autostereoscopice [9]. Aceste monitoare nu necesita ochelari speciali si pot fi privite simultan de cativa privitori. Un monitor 3D este de fapt un monitor LCD plan cu un strat de lentile cilindrice (lenticulare, vezi ficura 2.6) amplasate in fata ecranului.

Figura 2.6: Placa cu lentile (elipsa este marita) [9].

Fiecare pixel in LCD consta din trei sub-pixeli: rosu, verde si albastru. Intr-un monitor normal fara lentile, toti sub-pixelii emit lumina in toate directiile. Intr-un monitor cu lentile lumina fiecarui sub-pixel este directionata intr-o singura directie si poate fi vazuta dintr-un unghi limitat de vedere din fata monitorului.

Datorita lentilelor din fata monitorului, fiecare ochi vede un set diferit de sub-pixeli pe monitor. Acesta poate fi folosit pentru a prezenta fiecarui ochi o imagine diferita. Lucrul acesta face ca vederea stereoscopica sa ofere fiecarui ochi o imagine a aceleiasi scene dintr-un punt de vedere putin diferit.

2.4.1 Imagini multiple

Imaginea care este vizibila dintr-un anumit unghi de vedere in fata monitorului se numeste vedere. Numarul minim de vederi pe care un monitor stereoscopic trebuie sa-l ofere este doua (una pentru fiecare ochi). Monitoarele create de Philips prezinta in mod characteristic mai mult de doua vederi.

Monitorul 3D (exemplu) folosit in continuare in prezentul raport este un LCD de 20 inch cu o rezolutie nativa de 1600 x 1200 (UXGA). Este un ecran cu noua vederi, ceea ce inseamna ca poate arata noua imagini diferite din unghiuri diferite de vedere. Intervalul de adancime perceput este de aproximativ 10 cm in fata ecranului si 15 cm in spatele ecranului. Folosind disparitati mari ale ecranului pentru a crea o o profunzime mai mare face ca imaginea sa fie neclara, dar aceasta depinde de asemenea de continut (luminozitate, exactitate etc), asa deci aceste numere sunt doar o sugestie. Retineti ca toate proprietatile tehnice mentionate in prezenta lucrare (numere, etc) sunt specifice acestui tip de ecran. Exista alte ecrane cu rezolutii, numar de vederi diferite, etc.

Avand un monitor 3D cu mai mult de doua vederi prezinta cateva avantaje, si bineinteles si unele dezavantaje, dupa cum vom vedea in continuare.

Avantaje

In primul rand, privitorul are o libertatea de vedere mai mare. Cand priveste un monitor cu doar doua vederi (fara ochelari), utilizatorul trebuie sa stea cu mare precizie in pozitia corecta in fata ecranului, altfel efectul stereoscopic se va pierde. Pentru a rezolva aceasta problema se foloseste dispozitivul de urmarire a pozitiei capului, dar aceasta functioneaza doar pentru o singura persoana, si prin urmare nu este considerata o tehnologie potrivita pentru piata consumatorilor [3]. Avand vederi multiple face ca efectul 3D sa fie vizibil dintr-un unghi de vedere mai mare si astfel permite mai multor persoane sa vada ecranul simultan.

Al doilea avantaj in a avea mai multe vederi este acela ca utilizatorul poate sa experimenteze paralaxa de miscare, de exemplu "sa privesti obiectele din jur", prin miscarea orizontala a capului.

Dezavantaje

Un mare dezavantaj de a avea vederi multiple este rezolutia scazuta pentru fiecare vedere. Rezolutia originala a ecranului este divizata la numarul de observatori, de aceea un monitor 2D cu rezolutie mare este necesar pentru a crea un monitor cu imagini multiple cu rezolutie mica.

Un alt dezavantaj al primei generatii de monitoare 3D este acela ca ele pot fi folosite doar pentru a afisa un continut 3D. Un continut 2D normal arata aceptabil doar la o rezolutie mica. Aceasta problema a fost rezolvata prin dezvoltarea de lentile manevrabile astfel incat monitorul poate fi inca folosit ca un monitor 2D obisnuit. Facand lentilele manevrabile pe fiecare regiune, va fi posibil chiar sa se afiseze continutul 2D si 3D in acelasi timp.

Zone de vedere

Figura 2.7 prezinta cum cele 9 vederi sunt afisate pe ecran. Fiecare vedere este vizibila dintr-un unghi specific (in mod characteristic 4 grade) din fata ecranului. Cele 9 vederi creeaza un "evantai" de 36 de grade. Evantaiul "primar" este vizibil de la -18 pana la +18 grade (0 grade fiind perpendicular pe ecran). La stanga si la dreapta acestuia este repetat acelasi evantai de 9 vederi. Dintr-o pozitie din fata ecranului doar 1/9 din sub-pixeli sunt vizibili (pentru fiecare ochi). Datorita lentilelor sub-pixelii sunt mariti si intreg ecranul este umplut tot timpul.

Figura 2.7 Vederi multiple (se prezinta un monitor cu 7 vederi in loc de 9) [9].

Suprapunere si dublarea imaginii

Vederile adiacente nu sunt complet separate: exista o anumita acoperire intre doua vederi adiacente care se numeste suprapunere. Suprapunearea face ca fiecare ochi sa nu vada exact o vedere, dar si ceva din cele 2 vederi adiacente. Este cauzata de optica lentilelor care permite vederilor sa migreze usor de la una la cealalta. Un mare dezavantaj al suprapunerii este dublarea imaginii, care are loc atunci cand doua vederi adiacente difera prea mult una de cealalta. Este mai dificil pentru creier sa uneasca intr-o singura imagine cele doua imagini primite de catre ochi.

2.4.2 Dispunerea sub-pixelilor

Figura 2.8 arata cu exactitate cum sunt plasate lentilele pe ecran. O suprafata mica a ecranului este marita si sub-pixelii specifici sunt vizibili. Trei lentile sunt vizibile in fata ecranului. Lentilele nu sunt aliniate exact vertical, ci sunt inclinate la un unghi mic. Aceasta din doua motive majore: cauzeaza o mai buna distributie intre rezolutia orizontala si cea verticala a fiecarei vederi si reduce trasaturile Moir [7].

In functie de locatia orizontala a unui sub-pixel in spatele lentilei, lumina acelui sub-pixel este directionata intr-un anumit unghi. Acest unghi este diferit de cel al sub-pixelilor invecinati.

Numarul din fiecare sub-pixel (precum este prezentat in figura 2.8) este numarul vederii. Un sub-pixel este vizibil doar din vederea sa asociata. Daca privim ecranul dintr-un anumit unghi (cu un singur ochi) vedem de exemplu toti sub-pixelii, de exemplu, cu vederea numarul 5. Acesti sub-pixeli formeaza un gratar rugos in imaginea totala asa cum este prezentat in figura 2.9.

Pentru a prezenta o imagine in vederea 5 pe ecran toti sub-pixelii cu acest numar trebuie sa fie incarcati cu informatii despre imagine (culorile). Acest proces este descris in sectiunea urmatoare.

Sub-pixelii 160012003 pe ecran sunt distribuiti intre cele 9 vederi. Fiecare vedere consta din 160012003/9 sub-pixeli. Aceasta corespunde unei rezolutii efective de 533x400. Atat rezolutia orizontala cat si cea verticala sunt impartite la 3. Rezolutia perceputa a monitorului este cumva mai mare datorita efectului de suprapunere intre imaginile adiacente si deoarece privitorul vede doua vederi in acelasi timp (cu doi ochi).

Figura 2.8 Fiecare sub-pixel are un numar de vedere [9].

Figura 2.9. Sub-pixelii vizibili pentru vederea 5 (accentuata) formeaza un gratar.

2.4.3 Pregatirea imaginii pentru monitorul 3D

Procesul de luare a noua imagini de intrare (una pentru fiecare vedere) si combinarea lor in asa maniera incat ele pot fi prezentate pe un monitor 3D se numeste interpolare.

Datele introduse pentru procesul de interpolare sunt cele 9 imagini introduse, iar rezultatul este o imagine rezultata. Deoarece rezolutia efectiva per imagine este 533x400, imaginile introduse ar trebui sa aiba aproximativ aceasta rezolutie, sau si mai bine: o rezolutie mai mare. Aceasta face ca imaginea rezultata sa fie mai intensa. Rezolutia imaginii rezultate este intotdeauna 1600x1200.

Un algoritm de interpolare foarte simplu este urmatorul: trecerea peste imaginea rezultata si pentru fiecare sub-pixel se creeaza o mostra a imaginii introduse corespunzatoare. Procesul este vizualizat in figura 2.11 si pseudocodul este prezentat in figura 2.10. Se apeleaza la mostra din pseudocod cand este necesara o valuare de culoare din imaginea introdusa. O implementare simpla este prezentata, unde se ajusteaza h si v la numarul intreg cel mai apropiat. Aceasta produce un rezultat cu o calitate rezonabila. O versiune mai buna ar folosi luarea de noi probe si filtrarea acestora pentru a obtine o imagine rezultata de o calitate mai mare.

Interpolare (byte Introdus [9] [wIn] [hIn] [3], byte Rezultat [wOut] [hOut] [3] )

Proba (int Nr vedere, float h, float v, int s)

Figura 2.10. Pseudocod pentru interpolarea a noua imagini introduse intr-o singura imagine rezultata.

Cand procesul este complet, imaginea rezultata contine cele 9 imagini introduse intr-un format interpolat. Cand aceasta imagine este prezentata intr-un monitor 2D normal toate vederile vor putea fi vizibile in acelasi timp. Arata ca o imagine cetoasa ciudata dupa cum este prezentat in figura 2.12. Cand imaginea este afisata pe un ecran 3D fiecare ochi ajunge sa vada doar o singura imagine.

Imagini 3D

Pentru a afisa o imagine 3D pe ecran primele 9 imagini trebuie sa fie formate dintr-o scena folosind pozitii diferite ale camerei de filmat. Apoi aceste 9 imagini individuale trebuie sa fie combinate (intercalate/interpolate) intr-o singura imagine care este trimisa la monitor.

Imaginea care este afisata in fiecare vedere trebuie sa fie o imagine a scenei facuta dintr-o anumita pozitie a camerei de filmat. Vederile sunt numerotate de la 1 la 9. Vederea 1 trebuie sa contina imaginea primita de la pozitia camerei din extrema dreapta iar Vederea 9 din extrema stanga. Miscarea camerei trebuie sa fie orizontala pentru a simula deplasarea dintre ochii umani.

Cand un privitor se uita la ecran ochiul lui stang ar putea, de exemplu, sa vada vederea 3 iar cel drept sa vada vederea 4. Aceasta pereche de vederi este o stereo-pereche corecta. O problema poate aparea daca utilizatorul este la marginea dintre doua "evantaie". De exemplu cand ochiul sau stang vede vederea 9 si ochiul drept vede vederea 1. Aceasta creeaza un efect 3D incorect care poate fi incomod de privit. Utilizatorii pot invata sa se indeparteze de la o astfel de pozitie de vedere.

Figura 2.11: Informatia despre culoare pentru un pixel in imaginea rezultata vine din trei imagini introduse (trei vederi)

Figura 2.12: Exemplu de imagine rezultata interpolata. (Un peste este prezentat in fata unui fundal).

Grafica 3D pe calculator

In grafica 3D pe calculator un model tri-dimensional al unei scene este storat intr-un calculator cu scopul de a efectua calcule si de a reda imagini. In aceast model tri-dimensional o camera poate fi pozitionata si o fotografie virtuala creata. Aceasta creeaza imaginea 2D a scenei 3D. Pentru a crea o animatie sau un film cateva imagini (numite cadre) sunt create si expuse succesiv.

Un numar de librarii software sunt disponibile pentru a ajuta programatorii sa creeze aplicatii de grafica pe calculator. O astfel de librarie consta in fond din functii care efectueaza functii grafice. Functiile tipice includ specificarea componentelor scenei (puncte, linii, poligoane), aplicarea transformarii si selectarea vederilor dintr-o scena. Definitia tuturor functiilor intr-o librarie se numeste Application Programming Interface API.

OpenGL[1] si Direct3D sunt doua API-uri cunoscute de grafica pe calculator. Majoritatea cardurilor grafice ofera accelerarea hardware pentru aceste API-uri, care inlesneste redarea in timp real a scenelor 3D complexe. Implementarea librariilor grafice este efectuata partial in software si (posibil, nu neaparat) partial in hardware. Intregul sistem se numeste redarea pipeline-ului. Consta in stagii diferite care efectueaza operatii pe date. Incepe prin formele geometrice de baza generate de catre aplicatie si se termina cu desenarea pixelilor pe ecran.

2.5.1 Grafica pe calculator pentru monitoarele 3D

Aplicatiile 3D "normale" (sau jocurile) creeaza doar o singura vedere pentru fiecare cadru dintr-o secventa. Pentru a folosi o astfel de aplicatie pe un monitor 3D nu una, ci noua vederi sunt necesare pentru a fi create si combinate intr-o singura imagine care sa fie potrivita pentru monitorul 3D. O solutie ar fi implementarea suportului pentru monitorul 3D in fiecare aplicatie in sine. Aceasta ar necesita schimbarea fiecarei aplicatii individuale, care de asemenea nu este nici de dorit si nici posibila.

O abordare alternativae este implementarea suportului in grafica API. Aceasta va face posibil ca toate programele existente sa foloseasca functionalitatea monitorului 3D. A fost aleasa aceasta abordare. In prezent, doar aplicatiile OpenGL sunt suportate prin intermediul asa numitului OpenGL wrapper.

Inainte de a explica aceasta abordare, sunt necesare cateva cunostinte ale altor doua subiecte: dubla stocare (memorare) si nuantatori procedurali. Acestea sunt explicate in urmatoarele doua sectiuni. In urmatorul capitol OpenGL wrapper-ul este discutat.

2.5.2 Dubla stocare (memorare)

Momeria unui card grafic care contine pixelii care sunt expusi in prezent pe ecran se numeste framebuffer (memorie temporara de cadre). Framebuffer-ul este de fapt o colectie de buffers (zone de memorii temporare): buffer de culoare (fata si spate) z-buffer, buffer sablon, etc.

Majoritatea aplicatiilor grafice interactive folosesc o tehnica numita dubla stocare. Aceasta este o metoda in care se folosesc doua framebuffer-uri (de culoare): un front buffer de culoare vizibil si un back buffer de culoare invizil. In timp ce front buffer-ul este afisat, urmatorul cadru este redat in back buffer. Cand noul cadru este terminat, cele doua zone de memorie sunt inter-schimbate. Folosirea de dubla stocare face posibil ca privitorul sa vada o imagine perfecta tot timpul. Grafica API, inclusiv OpenGL, ofera suport pentru dubla stocare. Cand o aplicatie a redat un cadru complet, trebuie sa faca apel la functia care shimba cele doua zone de memorie. In continuarea acestui raport, vom numi aceasta functie swapbuffer.

2.5.3 Shader programabile

In trecut, componentele grafice obisnuiau sa aiba o functie fixa care sa redea pipeline-ul. Aceasta s-a schimbat recent cu aparitia Unitatilor de Procesare Grafica Programabile [3] (Graphics Processing Units - GPU). Acestea permit catorva stagii ale redarii pipeline-ului sa fie programabil. Un program care functioneaza pe un GPU se numeste shader. Toate tipurile de efecte frumoase pot fi redate cu shader iar jocurile recente le folosesc in proportii mari.

O aplicatie grafica trebuie sa activeze un program shader cand vrea sa-l foloseasca (si sa-l dezactiveze dupa aceea). Cand un program shader este activ, el inlocuieste o parte din functionalitatea fixa a pipline-ului.

Exista doua tipuri de shader-e: shader de varf (vertex shader) si pixel shader. Numele lor corespunde cu pozitia lor in pipeline (si astfel tipul de date pe care ele opereaza). Pixel shader sunt uneori numite si shaders de fragment. In restul acestui document noi vom folosi numele de pixel shader. Figura 2.13 prezinta un model de redare a pipeline-ului si locul ambelor tipuri de shaders. Sagetile reprezinta curgerea datelor.

Figura 2.13 Vertex si pixel shader-i in redarea pipeline-ului [8].

Procesoarele programabile (de varf si de pixel) in interiorul GPU lucreaza pe un curent de date. Fiecare processor citeste un element din curentul de date de intrare, executa programul shader care opereaza pe aceste data, si scrie un element in curentul de date rezultat. Un program shader este executat o data pentru fiecare element din curentul de date. Nu sunt cunostinte despre elementele precedente sau urmatoare. Aceasta asigura ca programele shader sa fie usor executate in paralel pe hardware. Shaders de varf pot personaliza geometria pipeline-ului. Shaders de pixel lucreaza mai tarziu in pipeline si pot controla cum este determinata culoarea finala a pixelului.

Shader-e de varf

Varfurile trimise de catre aplicatie sunt procesate de catre shader-ul de varf. Fiecare vertex (varf) are o coordonata (x, y, z, w) si cateva atribute. Exemple de atribute de varf sunt culoarea, vectorul normal si coordonatele de structura. Un vertex shader poate sa modifice doar pozitia atributelor unui varf, nu poate sa creeze sau sa stearga varfuri.

Rasterizer (Dispozitiv care converteste imaginea vector in format bitmap)

Rezultatul unui vertex shader ajunge la ansamblul de fond si apoi la raster. Aceste parti ale canalului de prelucrare a datelor (pipeline) nu sunt programabile. Ansamblul de fond construieste triunghiuri din varfuri. Rasterul imparte aceste triunghiuri in pixeli. In timpul acestei operatii, el de asemenea interpoleaza (in mod linear) atributele fiecarui vertex.

Pixel shader

Rezultatul rasterului (pixeli cu atributele asociate interpolate) formeaza datele de intrare pentru pixel shader. Pixel shader poate folosi aceste date de intrare pentru a determina coluarea pixelului. Rezultatul pixel shader-ului (culoarea) este apoi trimisa la unitatea de stocare test (framebuffer) pentru a actualiza (posibil) un pixel real in framebuffer.

2.5.4. Limbaje de programare pentru shader

Un program shader poate fi scris intr-un limbaj de ansamblu specific pentru un anumit tip de GPU si grafica API sau intr-un libaj de nivel inalt general. Aceste limbaje inalte includ C pentru Grafica de la Nvidia (Cg), High-Level Shading Languange de la Microsoft (HLSL) si OpenGL Shading Language (GLSL). Folosind un limbaj de nivel inalt are avantajele obisnuite de portabilitate, productivitate crescuta a programatorului, refolosire usoara a codului, etc. In softul nostru Cg este folosit, prin urmare este discutat in mai multe detalii mai jos.

Cg

Cg este dezvoltat de Nvidia dar nu este specific pentru GPU-ul lor. Este un limbaj cu scop general concentrat pe hardware. Codul Cg arata aproape ca si codul C, cu aceeasi sintaxa pentru declaratii, solicitare de functie, si majoritatea tipurilor de date. Un program Cg este portabil de la o generatie de hardware la alta, de la un sistem de operare la altul, si grafica API [11].

Deoarece capabilitatile GPU cresc rapid, exista diferente majore intre generatii diferite de grafica hardware. Cg expune aceste diferente de hardware prin intermediul profilelor de limbaj. Un profil specifica subsetul limbajului Cg complet care este suportat de un anumit procesor. Exista profile diferite pentru procesoare de vertex si de pixel, pentru clasa hardware DirectX 8 si 9, etc.

Cg are suport pentru tipuri de date scalare (precum float) si pentru tipurile vector si matrice (precum float3, float4x4). Texturile sunt prezentate cu tipul special de sampler.

Limitari

Programele shader au cateva limitari care sunt cauzate de hardware-ul pe care opereaza. Lungimea lor (numarul de instructiuni) este limitat. Indicatoarele nu sunt suportate. Exista mai multe limitari, dar acestea depind de profilul shader-ului folosit.

Tipuri de input (date introduce)

Un program shader Cg poate avea 2 tipuri de input-ui: variabile si uniforme. Primul tip de input variaza cu fiecare executie a shader-ului. Ca exemple sunt pozitia, vectorul normal si coordonatele de structura. Al doilea tip de input ramane acelasi pentru mai multe executari ale shader-ului. Aceasta valoare este setata de aplicatie si ramane aceeasi pana cand aplicatia seteaza o alta valoare. Ca exemple sunt reflectivitatea si culoarea luminii.

Capitolul 3

Redari multiple

Pentru a folosi o aplicatie grafica pe un monitor 3D sunt necesare 9 vederi de la fiecare cadru (in loc de una). Aceasta este in prezent (la inceputul acestui proiect) realizata print folosirea unui OpenGL wrapper pentru a reda fiecare cadru de noua ori si apoi sa foloseasca un pixel shader pentru a face intercalarea.

Sistemul curent este descris in acest capitol. Unele din dezavantajele sale au dus la insarcinarea mea, care este descrisa in capitolul urmator.

3.1 OpenGL wrapper

OpenGL este o librarie de functii care poate fi folosita de catre o aplicatie pentru a executa operatii de grafica. Pe o platforma Windows codul tuturor acestor functii se gaseste in interiorul unei librarii de legatura dinamica (Dynamic Link Library - DLL). O posibila modalitate de a extinde functionalitatea OpenGL-ului este de a crea un wrapper DLL. Un OpenGL DLL wrapper a fost dezvoltat de Philips Research [6].

Acest proces wrapper functioneaza dupa cum urmeaza: opengl32.dll-ul original este redenumit in wopengl32.dll. Un nou opengl32.dll ("wrapper"-ul DLL) este creat si care exporta aceeasi interfata OpenGL. Aplicatiile care folosesc in mod normal opengl32.dll-ul original folosesc acum in mod automat wrapper DLL-ul, deoarece are acelasi nume de fisier.

Comportamentul de baza al wrapper DLL-ului este sa inainteze apeluri de functie catre DLL-ul original Dar este de asemenea posibil sa execute tot felul de functii inainte sau dupa apelul la functia originala. Aceasta ne da posibilitatea sa extindem functionalitatea OpenGL-ului fara ca aplicatia sa realizeze acest lucru. In figura 3.1 in stanga o aplicatie apeleaza functiile OpenGL in opengl32.dll-ul normal. In dreapta o aplicatie apeleaza functiile OpenGL in sau "prin" wrapper.

Pe alte platforme (de exemplu Linux) sau pe alte API-uri grafice (de exemplu Direct3D) o abordare asemenatoare de librarie wrapper este posibila.

3.2 Redare in format "tile"

Wrapper-ul ofera functionalitatea care permite aplicatiilor OpenGL normale sa foloseasca monitorul 3D. Aceasta functioneaza dupa cum urmeaza:

Wrapper-ul intercepteaza toate functiile OpenGL care se transmit catre ecran. Apoi, in loc sa apeleze functia de desenare o data, aceasta este apelata de noua ori. Inainte de fiecare apelare, camera este re-pozitionata in scena. De asemenea, se seteaza un viewport intainte de fiecare apelare.

Un viewport determina OpenGL-ul sa se redea doar catre o parte specifica a ecranului, in loc de intreg ecranul. Viewport-urile sunt setate dupa cum este prezentat in figura 3.2. Numerele indica numerele de vedere. Numarul 1 este vederea din extrema stanga si numarul noua este vederea din extrema dreapta.

Figura 3.1: Wrapper-ul OpenGL DLL este un strat intre aplicatie si OpenGL-ul insusi. (Sageata "redare scena" reprezinta toate apelurile de functie OpenGL necesare pentru a reda un cadru complet al unei scenei).

exrema dreapta

centru

extrema stanga

Figura 3.2: 9 Vederi in format "tile"

Cand aplicatia termina de redat un cadru, ea apeleaza functia SwapBuffers. La momentul respectiv, back buffer-ul contine cele noua vederi redate in format tile (de placa). Fiecare vedere are o rezolutie mica (1/9). Placile sunt un pas intermediar si nu sunt afisate (datorita efectului de dubla memorare). Functia SwapBuffers in wrapper DLL este extinsa cu functionalitatea de a combina cele 9 vederi tile intr-o imagine intercalata potrivita pentru monitorul 3D. Ea foloseste un pixel shader pentru aceasta functie. Cand interpolarea este gata, este apelata functia originala de SwapBuffers astfel incat imaginea intercalata este afisata pe ecran.

3.3 Interpolare cu pixel shader

Dupa ce cele 9 vederi au fost redate in format tile, este de datoria pixel shader-ului sa le intercaleze.

Un pixel shader este executat o data pentru fiecare pixel (x, y) in imaginea de iesire si functia sa este de a calcula culoarea. Un pixel consta din trei sub-pixeli si culoarea fiecarui sub-pixel trebuie sa derive dintr-o vedere diferita (vezi figura 2.11).

Un tabel este construit in prealabil care contine pentru fiecare pozitie (x, y) din imaginea rezultata cele trei pozitii necesare din imaginea de intrare sub forma tile. Acest tabel are o marime de 22MB [5]. Tabelul este storat ca sase structuri pe cardul grafic. Toate cele sase structuri trebuie sa fie citite o data din fiecare cadru. Aceasta necesita o latime de banda de memorie de 22MB pentru fiecare cadru.

Shaderul executa sase aporturi de structura si aceasta rezulta in sase valori. Aceste sase valori reprezinta trei pozitii (x, y). Apoi imaginea celor noua vederi "tiled" este etalonata la aceste trei pozitii si cele trei colori rezultate sunt combinate pentru a forma culoarea de iesire a pixelului. Codul Cg pentru pixel shader se gaseste in apendixul A. 9.

Interpolarea trebuie sa aiba loc pe cardul grafic insusi: transferarea imaginii redate la memoria principala si executarea interpolarii pe CPU este prea inceata datorita latimii de banda[6] asimetrica a Portului de Grafica Accelerata (Accelerated Graphics Port - AGP). Primirea de date de la el este mult mai inceata decat trimiterea de date catre el. (Aceasta problema va fi redusa cand cardurile grafice cu o interfata PCI Express vor deveni obisnuite . Problema latimii de banda nu este singurul motiv pentru utilizarea graficii hardware, ea permite de asemenea folosirea de filtere de textura hardware pentru re-etalonare. Realizarea re-etalonare pe CPU va fi mult mai scumpa. Poate cel mai mare avantaj de folosire de grafica hardware este paralelismul acesteia: CPU nu poate sa faca fata acesteia.

Urmatorii pasi sunt realizati pentru a face pixel shader-ul sa opereze:

  1. Salveaza starea OpenGL curenta
  2. Copiaza continutul memoriei video intr-o textura. Lucrul acesta este necesar deoarece pixel shader-ul are nevoie de acces ca sa citeasca imaginea din memoria video, lucru care in mod normal nu este posibil.
  3. Seteaza o proiectie ortografica.
  4. Activeaza (bind) pixel shader-ul
  5. Deseneaza un dreptunghi care umple complet ecranul. Datorita proiectiei ortografice pixel shader-ul se executa o data pentru fiecare pixel din dreptunghi, care are loc o data pentru fiecare pixel din ecran.
  6. Dezactiveaza (unbind) pixel shader-ul si restoreaza starea OpenGL.

Un mare avantaj al redarii multiple este calitatea rezultatului. Nu exista artefacte care sa rezulte din descoperiri sau transparente, lucru care va deveni clar in sectiunea 5.3.

Poate ca cel mai mare dezavantaj al redarii multiple este acela ca efectul de adancime nu este usor de ajustat. Valoarea adancimii percepute poate fi controlata prin variarea distantei dintre cele 9 camere virtuale. Dar aceasta nu ofera nici un control asupra cum intervalul de adancime din scena produce adancimea perceputa pe monitor. Aceasta este intr-adevar o mare problema: de exemplu, nu este posibil sa obtinem un efect de adancime bun atat pentru obiectele foarte apropiate de camera cat si (in acelasi timp) pentru obiectele indepartate. In prezent, doar obiectele un pic indepartate de camera obtin un efect de adancime bun. Obiectele foarte apropiate de camera (de exemplu un pistol la primul tragator) are o disparitate de ecran prea mare si cauzeaza discomfort de vedere. Aceasta este "rezolvata" in prezent prin dezactivarea redarii pistolului in joc.

Un alt mare dezavantaj este performanta neproductiva. Redand totul de 9 ori este un factor mult mai incet decat redarea unei singure vederi. Timpul necesar creste liniar cu numarul de poligoane (si cu numarul de vederi). Redarea multipla creste incarcatura primelor stagii ale fluxlui de procesare (unde sunt procesate varfurile). Creste de asemenea si incarcatura pe CPU. Jocurile recente folosesc din ce in ce mai multe poligoane iar monitoarele viitoare cu vederi multiple pot sa aiba mai multe vederi. Aceste dezvoltari sunt un prospect negative pentru redarea multipla. De asemenea pixel shade-ul care face interpolarea este incet: trebuie sa citeasca o textura mare pentru fiecare cadru. O alta implementare poate folosi o latime de banda mai mica pentru fiecare cadru cu pretul a mai multor calcule.

Calitatea implementarii curente este limitata de catre rezolutia imaginii intermediare in format "tiled". Rezolutia pentru fiecare vedere este de 1/9, dar o rezolutie cu putin mai mare ar fi mai buna. Acesata se poate realiza in viitor, dar necesita o schimbare majora[8].

Implementarea curenta nu este perfecta: nu toate functiile OpenGL au fost extinse ca sa suporte redarea 9x. Mai este inca o problema nerezolvata inca: o aplicatie poate sa citeasca pixelii din memoria video. Unele aplicatii fac lucrul acesta, de exemplu sa creeze o textura dintr-o imagine care este redata in memoria video. Aceasta este o problema pentru ca memoria video contine cele 9 vederi mici sub format "tiled", iar aplicatia asteapta doar o singura vedere normala. Aceasta problema ar putea fi rezolvata in viitor, prin schimbarea comportamentului unor functii OpenGL din wrapper (vezi tabelul 7.1.).

Capitolul

Redarea RGBD

Redarea RGBD ia o imagine plus harta ei de adancime si produce una sau mai multe imagini pentru noi puncte de vedere. Redarea RGBD se bazeaza pe mutarea orizontala a pixelilor in care valoarea deplasarii depinde de adancimea pixelului.

In acest capitol teoria din spatele redarii RGBD este explicata si algoritmul existent este discutat pe scurt. Schimbarile si adaugirile necesare pentru a implementa redarea RGBD pe un card grafic vor fi discutate in capitolele urmatoare.

5.1 Teorie

5.1.1 Lucrare inrudita

O lucrare care este inrudita cu problema noastra vine din campul de redare bazata pe imagine (image based rendering IBR). Idea generala a IBR este sa foloseasca ca date de intrare una sau mai multe imagini existente pentru redarea unei noi imagini. Este o abordare a redarii cu totul alta fata de redarea obisnuita bazata pe geometrie.

Idea de baza in a folosi o imagine 2D si harta ei de adancime pentru a genera o vedere virtuala este descrisa in [1.5]. Aceasta abordare este folosita in algoritmul offline existent si este descris in acest capitol.

Aceeasi abordare va fi de asemenea folosita in algoritmul nostru de redare RGBD care va functiona pe GPU.

5.1.2 Deplasarea pixelilor in functie de adancime

Punctual de plecare este o imagine si harta ei de adancime. Harta de adancime detine, pentru fiecare pixel in parte, informatia despre distanta de la camera pana la obiectul vizibil in acel pixel. Aceasta distanta este normalizata astfel incat 0 inseamna punctul cel mai indepartat de camera si 1 inseamna punctual cel mai apropiat de camera. Aceasta ne permite sa modelam imaginea ca un set de etaloane proiectate pe un teren. Figura 5.1a prezinta o linie orizontala a imaginii modelate ca un teren. Lungimile sagetilor corespund cu informatiile de adancime ale etaloanelor.

Generarea unei alte vederi poate fi realizata prin repozitionarea camerei si apoi proiectarea etaloanelor in teren inapoi peste planul imaginii (vezi figura 5.1b). In acest fel fiecare pixel de pe linia orizontala a imaginii de intrare este mapat intr-o noua pozitie in imaginea rezultata (pe aceeasi linie). Valoarea cu care fiecare pixel este deplasat orizontal este in functie de disparitatea sa si de valoarea miscarii camerei, vezi ecuatia 5.1:

deplasare orizontala = nr vedere x (disparitate - deplasament) x factor de amplificare (5.1)

Figura 5.1 (a) Linia orizontala a imaginii modelate precum un teren cu adancime. b) Etaloane proiectate inapoi pe planul imaginii pentru o pozitie diferita a camerei.

Numerele vederilor folosite in aceasta ecuatie sunt in intervalul [-4.+4], unde 0 este vederea centrala. Disparitatea este normalizata ([0.1]). Disparitatea nu este acelasi lucru cu adancimea, dar pentru moment putem ignora diferenta dintre ele. Disparitatea poate fi calculata din adancime, ceea ce va fi explicat in capitolul urmator. Deplasamentul este un parametru care controleaza tipul de disparitate de ecran in imaginea rezultata: poate fi folosit de exemplu astfel incat imaginea rezultata sa foloseasca doar adancimea din fata ecranului, sau de exemplu 40% in fata ecranului si 60% in spatele ecranului, etc. Factorul de amplificare este un parametru care controleaza valoarea disparitatii ecranului si astfel valoarea adancimii percepute. Un factor de amplificare 0 inseamna adancime 0, si cu cat factorul de amplificare este mai mare, cu atat adancimea este mai mare. Lucrul acesta poate fi vizualizat in figura 5.1 prin considerarea factorului de amplificare ca fiind valoarea deplasarii camerei. Atat deplasamentul cat si factorul de amplificare sunt acommodate normal astfel incat imaginea 3D rezultata sa arate "bine".

5.1.3 Acoperiri si descoperiri

Pixelii de intrare se deplaseaza la o noua pozitie in imaginea rezultata. Densitatea etaloanelor rezultate in imaginea rezultata nu este uniforma. De aceea este necesara o procedura de re-etalonare. In timpul deplasarii, unii pixeli sunt micsorati sau mariti iau unii sunt chiar acoperiti de altii. Lucrul acesta se poate vedea infigura 5.2. Se prezinta o casa cu un copac in fata ei. Partea de jos a figurii arata "vederea de sus" a canalului de adancime al liniei de scanare. Partea din stanga a figurii arata imaginea originala, jumatatea dreapta prezinta imaginea asa cum este vazuta din pozitia schimbata a camerei. Pe masura ce camera este deplasata catre dreapta, atat casa cat si copacul apar sa se "deplaseze" catre stanga. Totusi, intrucat copacul este mai aproape de camera decat casa, copacul se deplaseaza mai mult decat casa. Copacul apare sa se deplaseze catre stanga fata de casa (paralax de miscare). Acoperirea are loc atunci cand copacul acopera o parte din casa care era vizibila din pozitia originala a camerei. Descoperirea are loc cand o parte din casa care nu era vizibila din pozitia originala a camerei devine vizibila.

Manipularea acoperirii

Acoperirea poate fi detectata mergand prin linia de scanarea a imaginii de intrare intr-o ordine specifica bazata pe deplasarea camerei, vezi figura 5.3. O deplasare a camerei catre dreapa dicteaza o transversare de la dreapta la stanga a pixelilor de intrare. O miscare a camerei catre stanga dicteaza o transversare de la stanga la dreapta a pixelilor de intrare. In aceasta figura camera este deplasata catre dreapta. Aceasta inseamna ca pixelii de intrare sunt procesati in ordinea a, b, c. Fiecare pixel este deplasat in noua sa pozitie in baza adancimii sale. Un spatiu variabil este introdus sa mentina valoarea-x minima (sau maxima) a pixelilor proiectati in imaginea rezultata.

Figura 5.2: Acoperiri si descoperiri

Figura 5.3: Detectarea acoperirilor prin mentinerea spatiului in domeniul de iesire. Pixelul c este acoperit in imaginea de iesire, deoarece el nu mareste spatiul.

Cand un pixel deplasat nu scade (sau creste) valoarea spatiului, el trebuie sa fie acoperit de oricare din pixelii deplasati anterior. Prin urmare acest pixel nu trebuie sa fie vizibil in imaginea rezultata. In figura, aceasta este si situatia pixelului c: el nu mareste valoarea spatiului, deci este acoperit (in acest caz de pixelul b).

Manipularea descoperirii

Descoperirile pot fi detectate prin masurarea distantei dintre doi pixeli in domeniul de iesire. Cu cat distanta aceasta este mai mare, cu atat mai mult se poate vedea dintr-un obiect ce n-a fost vizibil in imaginea originala introdusa. Ar trebui notat totusi, ca nu este posibil sa detectezi cu exactitate diferenta dintre o marire normala a unui obiect si o descoperire reala. In figura 5.2 o descoperire are loc la separarea mare dintre doua pixeluri in imaginea rezultata. Descoperirile pot fi manipulate repetand fundalul. "Fundalul" este pixelul cu valoarea adancimii cea mai mare. Repetand fundalul se obtin rezultate mai bune decat repetarea prim planului deoarece in lumea reala, privind in jurul unui obiect se obtin mai multe detalii ale fundalului din spatele obiectului.

5.2 Implementare

5.2.1 Redare RGBD avansata

Un algoritm de redare RGBD a fost deja dezvoltat de catre Philips. El foloseste doua imagini pentru fiecare cadru ca date de intrare: o imagine de culoare si una de adancime. Rezultatul este o imagine interpolata pregatita pentru monitorul cu vederi multiple. Algoritmul creeaza imediat imaginea rezultata interpolata fara sa mai treaca prin pasul intermediar al celor noua imagini sub format "tiled".

Se numeste de asemenea algoritm "avansat": el trece (in mod repetat) peste imaginea introdusa si pentru fiecare pixel introdus, sunt actualizati zero sau mai multi (sub) pixeluri rezultati, vezi figura 5.4. Bucla externa a algoritmului creeaza cumva confuzie, deoarece aceasta trece peste imaginea rezultata. Dar lucrul acesta nu schimba natura avansata a algoritmului.

pentru fiecare linie din imaginea rezultata:

pentru fiecare vedere [-4.+4]:

daca vederea < 0

pentru fiecare pixel introdus pe o linie (de la dreapta la stanga)

calculeaza noua pozitie in imaginea rezultata

daca pixelul nu este acoperit

actualizeaza sub-pixelul (pixelii) corespunzatori in imaginea rezultata

altfel

pentru fiecare pixel introdus pe o linie (de la stanga la dreapta)

calculeaza noua pozitie in imaginea rezultata

daca pixelul nu este acoperit

actualizeaza sub-pixelul (pixelii) corespunzatori in imaginea rezultata.

Figura 5.4. Pseudocod pentru redare RGBD avansata

Algoritmul produce rezultate de calitate inalta, dar nu in timp real.

5.3 Avandaje si dezavantaje

Redarea RGBD are unele avantaje si dezavantaje in comparatie cu redarea multipla. Multe din aceste diferente sunt fundamentale. Vom discuta pe scurt pe cele mai importante.

Avantajele redarii RGBD in comparatie cu redarea multipla

  • Un control mai bun al valorii adancimii

Cand se foloseste redarea multipla singura modalitate de a controla valoarea adancimii in imaginea rezultata este prin schimbarea valorii translatiei camerei (iar aceasta nu ofera control asupra distributiei adancimii in scena). Redarea RGBD face ca acest lucru sa fie complet controlabil prin procesarea hartii de adancime (vezi sectiunea 6.4.4).

  • Performanta

Cand nu exista restrictii la implementare, se asteapta ca redarea RGBD sa fie mai rapida decat redarea multipla. Timpul necesar pentru redarea RGBD este (aproape complet) independent de scena, pe cand timpul necesar redarii multiple este dependent de scena in mod considerabil.

  • Redarea RGBD are mult mai multe avantaje (pentru Philips in general), dar acestea nu sunt intr-adevar relevante pentru noi.

De exemplu redarea multipla este posibila doar cand modelul 3D al scenei este disponibil. In majoritatea cazurilor, nu se intampla acest lucru, de exemplu cu video 2D. Singura optiune atunci este crearea de harti de adancime si folosirea redarii RGBD. Hartile de adancime pot fi estimate din imagini video 2D prin algoritmi speciali.

De asemenea, rezultatul redarii multiple (imaginea interpolata) este afisata dependent. Rezultatul intermediar (imaginea in format "tiled") este de asemenea afisat dependent: numar fix de vederi, valoare fixa de translatie a camerei. Formatul RGBD, pe de alta parte, nu este afisat dependent. Lucrul acesta il face sa fie foarte potrivit continutului 3D.

O harta de adancime poate fi storata o data cu imaginea 2D la cost mic: folosind compresarea video se ia aproximativ 20% din marimea imaginii 2D. Algoritmii speciali de compresare pot sa reduca aceasta valoare chiar mai mult.

Formatul RGBD este invers compatibil cu monitoarele 2D (ignora pur si simplu adancimea). Trebuie retinut faptul ca o imagine cu 9 vederi in format "tiled" este de asemenea invers compatibila: le ignora pur si simplu pe toate, cu exceptia vederii centrale.

Dezavantajele redarii RGBD in comparatie cu redarea multipla:

  • Descoperirile sunt umplute cu un fundal "gaussed" in loc cu ceea ce este intr-adevar vizibil
  • Efectele de transparenta pot cauza probleme

Problema transparentei este faptul ca culoarea pixelului este o combinatie dintre culoarea fundalului si culoarea obiectului transparent insusi. Deci pixelul ar trebui sa aiba de fapt doua valori ale adancimii, ceea ce nu este cazul. Numai una dintre ele este disponibila in harta de adancime. In baza acestui lucru, pixelul este remapat la o noua locatie. Lucrul acesta nu este corect: in mod ideal, culoarea fundalului si culoarea obiectului transparent ar trebui sa fie mapate in doua noi locatii diferite. Acelasi lucru se aplica si cu efectele atmosferice, cum ar fi ceata.

  • Vederea efectelor dependente poate crea probleme

O ipoteza ridicata de redarea RGBD este aceea ca o suprafata arata la fel, independent de unghiul de vedere. Nu se intampla tot timpul asa. Luminarea depinde de unghiul de vedere. Acesta nu va fi redat corect in vederile virtuale folosind redarea RGBD, care va scadea calitatea.

Capitolul 6

De la z-buffer la adancimea perceputa

Vrem sa implementam redarea RGBD pe un card grafic si sa folosim informatia in z-biffer ca "informatia despre adancime" necesara in procesul de redare. In acest capitol vom discuta teoria turutor pasilor necesari de parcurs de la informatia din memoria-z la adancimea perceputa pe ecran (vezi figura 6.1). Implementarea acestor pasi este discutata in urmatorul capitol (in sectiunea 7.3).

z-buffer à . à adancime perceputa

 


Figura 6.1: De la z-buffer la adancimea perceputa

6.1 Z-buffering

Z-buffering este o metoda folosita in mod curent de indepartare a suprafetei ascunse. Foloseste un buffer 2D care storeaza "adancimea" obiectului vizibil la fiecare pixel. Cand incepe redarea unui cadru, z-buffer-ul este initializat complet pana la infinit. In timpul redarii unui obiect, culoarea unui pixel este actualizata doar daca adancimea obiectului este mai mica decat adancimea storata in z-buffer. Aceasta inseamna ca un obiect este vizibil doar daca este mai aproape de camera decat un obiect care a fost deja redat, ca si in lumea reala.

Z-buffering este practic folosita de toate jocurile 3D.

Disparitatea normalizata la adancimea perceputa

z-buffer à à disparitatea ecranului à adancimea perceputa

 
Adancimea perceputa este adancimea pe care un privitor o experimenteaza cand priveste monitorul. Este cauzata de disparitatea ecranului asa cum a fost explicat in sectiunea 2.3.2 (vezi figura 6.2).

Figura 6.2: Disparitatea ecranului cauzeaza adancimea perceputa.

Relatia dintre disparitatea ecranului si adancimea perceputa a fost trasata in figura 2.5. Asa cum se observa, aceasta functie nu este liniara pentru domeniul pentru care a fost trasata. In sectiunea 2.3.1 am discutat ca disparitatea maxima a ecranului (pozitiva sau nevativa) trebuie sa fie limitata (vezi sectiunea 2.3.1).

Pentru intervalul de disparitate a ecranului folosit de monitoarele noastre, reiese ca relatia dintre disparitatea ecranului si adancimea perceputa este in mod remarcabil liniara, asa cum poate fi vazut in figura 6.3. Aceasta este aceeasi funtie precum cea din figura 2.5, numai ca domeniul este mai mic. Valorile disparitatii ecranului din afara acestui interval mic nu sunt folosite in mod normal la monitorul nostru (pentru ca ele cauzeaza discomfort de vedere).

Figura 6.3: Adancimea perceputa in spatele ecranului in functie de disparitatea ecranului (pentru o distanta de vedere de 1 metru si o separare a ochilor de 64 milimetri).

In sectiunea 5.12 noi am discutat formula folosita de redarea RGBD pentru a calcula valoarea deplasarii orizontale a unui pixel. Formula necesita disparitatea normalizata ca date de intrare. Definitia disparitatii este data in [2]. Valoarea exacta a disparitatii nu este importanta deoarece disparitatea ecranului este limitata. Prin urmare, disparitatea poate fi normalizata. Formula deplasarii transforma disparitatea normalizata in disparitatea ecranului folosind numarul vederii, factorul de amplificare si deplasamentul (vezi figura 6.4). La randul ei, disparitatea ecranului cauzeaza disparitatea perceputa pe monitor.

à à harta disparitatii normalizate à RGBD (redarea folosind factorul de amplificare si deplasament) à disparitatea ecranului à adancime perceputa

 


Figura 6.4. Disparitatea ecranului este rezultatul redarii RGBD folosind ca date de intrare o harta a disparitatii normalizate.

6.3. De la adancime normalizata la disparitate normalizata

Disparitatea normalizata necesara pentru redarea RGBD poate fi calculata din adancime. Adancimea este definita ca distanta de la planul camerei la un obiect intr-o scena. Marimea exacta a adancimii nu este importanta deoarece intervalul de adancime al scenei trebuie sa fie ajustat oricum pentru a se incadra in intervalul adancimii percepute a monitorului. Aceasta inseamna ca harta adancimii poate sa contina adancimile normalizate astfel incat 0 reprezinta adancimea cea mai scazuta iar 1 reprezinta adancimea cea mai mare (de exemplu).

Disparitatea normalizata poate fi calculata din adancimea normalizata folosind inversul graficului prezentat in figura 6.3. Graficul trebuie sa fie normalizat (si inversat) in acest scop. Pentru intervalul de disparitate (a ecranului) folosit la monitoarele noastre functia reprezentata in aceasta figura este aproape liniara. Aceasta inseamna ca noi putem folosi harta adancimii normalizata (fara conversie) ca harta de disparitate normalizata pentru redarea RGBD (vezi figura 6.5). Adancimile din harta adancimii sunt schitate (aproape) in mod liniar la adancimile percepute pe monitor, ceea ce si dorim. Retineti totusi ca pentru monitoare cu un interval al disparitatii ecranului mare, pasul conversiei de la adancimea normalizata la disparitatea normalizata nu mai poate fi sarit.

à à harta adancimii normalizate à (redarea RGBD cu factor de amplificare si deplasament) àdisparitatea ecranului à adancime perceputa

 

Figura 6.5. O harta a adancimii normalizate poate fi folosita fara convestie ca harta a disparitatii normalizate deoarece relatia dintre adancime si disparitate este aproape liniara pentru monitorul nostru.

6.4 De la Z-buffer la adancime normalizata

6.4.1 Z-buffer

Cand un cadru este redat complet, imaginea este disponibila in framebuffer-ul color (vezi figura 6.6 pentru un exemplu de joc Quake). Un produs secundar al redarii este "z-map" (harta-z) care este disponibila in z-buffer. Ea contine valoarea-z a obiectului vizibil la fiecare pixel. Valorile storate in z-buffer-ul unui card grafic sunt rezultatul unei serii de calcule in pipeline-ul grafic ( conducta de executie grafica) (vezi figura 6.9).

Z-buffer-ul contine valorile-z ale spatiului fereastra de la capatul secventei de transformare. Noi suntem interesati in valorile-z ale spatiului ochiului. In spatial ochi camera este localizata in origine si este directionata in jos pe axa z negative. In acest spatiu coordonata z reprezinta distanta de la un punct la planul camerei (zeye = 0). Aceste coordinate zeye pot fi folosite ca harta de adancime (de vreme ce ele reprezinta distanta de la planul camerei).

Z-bufferul are de obicei o precizie de 16 sau 24 bits per pixel. Figura 6.7 prezinta cei mai importanti opt bits al hartii-z ca o imagine in scala gri. Daca s-ar folosi aceasta harta-z direct ca harta de adancime pentru redarea RGBD, atunci ar rezulta o imagine 3D unde doar obiectele foarte aproape de privitor vor obtine un efect de adancime bun iar toate celelalte obiecte vor sfarsi undeva in spate. In exemplul nostru arma ar folosi o mare parte a intervalului de adancime perceputa disponibila si toate celelalte obiectele care sunt un pic mai indepartate vor fi in ultima partea a intervalului de adacime perceputa. De aceea, harta-z nu poate fi folosita direct ca harta de adancime. O etapa de conversie este necesara pentru a transforma harta-z intr-o harta de adancime (dupa cum este prezentat in figura 6.8).

6.4.2 Calculare avansata

Trebuie sa inversam calculele facute in secventa de transformare pentru a merge de la coordinate-z spatiu fereastra inapoi la coordonate-z spatiu ochi. Dar mai intai haideti sa aruncam o privire la calculele avansate (care au loc in pipeline-ul de redare).

Matricea proiectiei

Coordonatele ochilui (xeye, yeye,zeye, weye) sunt multiplicate cu matricea de proiectie pentru a obtine coordonatele clip (xc, yc, zc, wc).

Matricea de proiectie poate fi orice, dar pentru jocuri si multe alte aplicatii, este intotdeauna matricea de proiectie de perspectiva. Cand o aplicatie OpenGL specifica o proiectie de perspectiva ea trebuie sa specifice (printre altele) valorile planurilor apropiate si departate (n si f).

Figura 6.6 Framebuffer-ul color

Figura 6.7 Z-buffer (cei mai importanti 8 bits sunt in imagine de scala de gri).

Partea din scena care este (in mod potential) vizibila este intre zeye = - n we si zeye = - fwe.

Valorile rezultate ale zc si wc sunt prin urmare definite prin ecuatiile [14]:

(6.1)

wc = - zeye (6.2)

Divizare de perspectiva

Valorile coordonatelor clip (xc, yc, zc ) sunt impartite la valoarea coordonatei clip wc, care rezulta in coordonate de aparat normalizate. Acest pas este cunoscut sub numele de divizare de perspectiva. Valoarea coordonatei clip wc reprezinta distanta de la planul camerei. Pe masura ce aceasta distanta creste valoarea 1/wc se apropie de 0. Prin urmare si xc/wc si yc/wc se apropie de 0, cauzand primitivele redate sa devina mai mici pe ecran. In acest mod pipeline-ul grafic simuleaza o vedere de perspectiva.

Valoarea coordonatei clip zc este de asemenea divizata la wc, precum xc si yc. Aceasta are acelasi rezultat ca si pentru xc si yc: cu cat zc este mai mare (cu cat este mai indepartat de camera) cu atat zndc se micsoreaza.

Figura 6.8. Harta de adancime (calculata din valorile z-buffer-ului folosind functia Z - D si storata ca imagine 8-bit de scala de gri).

Figura 6.9. Secventa de trasformare a vertex-ului [14]

Cauzeaza o precizie mai mare in jurul planului apropiat si mai putina precizie in jurul planului indepartat (acest efect se vede foarte clar in figura 6.7).

Valoarea rezultata a lui zndc este:

(6.3)

(6.4)

Coordonatele aparatului normalizate sunt in intervalul [-1.+1]. zndc = -1 corespunde planului apropiat si zndc corespunde planului indepartat.

Transformarea portului de vedere

Transformarea portului de vedere ajusteaza intervalul coordonatelur apartului normalizate la [0..1], care are ca rezultat coordonatele fereastra:

(6.5)

Coordonatele spatiului fereastra zwin sunt storate in z-buffer. Zwin = 0 corespunde planului apropiat si zwin = 1 corespunde planului departat. (hardware grafice storeaza de fapt numere intregi nesemnate de 16 sau 24 bits, dar OpenGL se sustrage de la aceasta. Deci pentru noi o valoare din z-buffer este doar un numar real in intervalul [0..1]).

6.4.3 Calcularea inversa

Sectiunea anterioara a prezentat cum pipeline-ul de redare transforma zeye (adancimea de la planul camerei) in zwin (valorile storate in z-buffer). Tot ceea ce ne trebuie noua este o formula care sa faca reversul: sa transforme zwin in zeye. Aceasta formula poate fi astfel folosita in softul nostru pentru a crea harta de adancime pentru redarea RGBD folosind infomatia din z-buffer.

Calculele prezentate in sectiunea precedenta pot fi inversate. Aceasta duce la urmatoarea ecuatie:

(6.6)

Aceasta ecuatie asuma un default de glDepthRange (interval de adacime gl) de [0..1], ceea ce este si cazul. Daca nu, este nevoie de o formula mai extinsa[9]. Functia glDepthRange afecteaza schitarea de la zndc la zwin, dar nu este folosita mai niciodata. Deoarece noi nu suntem interesati in valorile zeye exacte, rezultatul poate fi normalizat intre 0 (planul camerei) si f (indepartat):

(6.7)

Cu constantele a si b bazate pe valorile lui n si f

(6.9)

Aceasta rezulta in graficul prezentat in figura 6.10. Relatia dintre zwin si zeye normalizata este prezentata pentru doua exemple de relatie de aproape si de departe. In general, jocurile folosesc o relatie de aprope la indepartat intre aceste doua.

Valorile lui zeye reprezinta o distanta liniara de la planul camerei la un obiect vizibil si prin urmare le vom numi simplu, adancime. Ecuatia 6.7 este cunoscuta de acum incolo ca si "functia Z la D". Este functia care transforma valorile z-buffer in valori de adancime. Cand valorile-z ale spatiului fereastra de la z-buffer sunt procesate cu aceasta functie, rezulta harta de adancime prezentata in figura 6.8.

6.4.4 Alte date

In aceasta sectiune sunt discutate alte chestiuni despre conversia Z la D.

Proiectia ortografica

Cand aplicatia grafica foloseste proiectia ortografica in locul proiectiei de perspectiva, intreaga poveste despre conversia Z la D nu este necesara. Z-buffer-ul poate sa fie folosit direct ca harta de adancime de vreme ce relatia dintre zwin si zeye este liniara.

Figura 6.10 Functia Z la D trasata pentru doua rapoarte de aproape la indepartat (1:100 in graficul de sus si 1:1000 in cel de jos).

W-buffering

Cand aplicatia grafica foloseste w-buffering in loc de z-buffering intreaga poveste despre conversia Z la D este inutila. W-buffering ofera o reprezentatie liniara a distantei in bufferul de adancime. Prin urmare w-buffer-ul poate fi folosit direct ca harta de adancime de vreme ce relatia dintre zwin si zeye este liniara.

Trasarea adancimii scenei la adancimea perceputa

In general, jocurile traseaza o scena 3D foarte mare si aceasta scena mare trebuie sa fie compresata in intervalul de adancime relativ mic al monitorului. Fara a fi discutat maparile in aceasta sectiune, intregul interval de adancime al scenei este mapat liniar in intervalul de adancime al monitorului. Aceasta este cea mai corecta abordare, dar se poate sa nu ofere tot timpul rezultatele cele mai bune.

Un avantaj al redarii RGBD este acela ca noi putem controla cu exactitate cum adancimea scenei este mapata la adancimea perceputa a monitorului. Aceasta poate fi realizata ca un pas de procesare suplimentar al hartii de adancime inainte de a face redarea RGBD. Deoarece valorile in harta de adancime sunt normalizate o functie f : [0..1] --> [0..1] poate fi folosita pentru a pre-procesa harta de adancime.

à (Z in D) à harta de adancime normalizata à (mapare) à harta de adancime normalizata à

 


Figura 6.11 De la z-buffer la adancimea perceputa

Un exemplu simplu si util este functia radacina patrata, prezentata in figura 6.12. Aceasta functie are efectul ca obiectele mai apropiate de camera folosesc mai multa adancime perceputa decat obiectele indepartate de camera (in imaginea 3D rezultata pe monitor). Aceasta se poate vizualiza in figurile 6.13 si 6. 14.

Figura 6.12 Functia radacina patrata

Figura 6.13. Adancimea scenei

Figura 6.14 Adancimea perceputa

Un alt exemplu util este functia y = 1.3x transformata in intervalul [0..1]. Aceasta functie este prezentata in figura 6.15. Are efectul ca obiectele mai indepartate decat o adancime specifica primesc toate aceeasi adancime maxima perceputa. Toate celelalte obiecte care sunt mai putin indepartate primesc un efect de adancime marit. Un alt scenariu util pentru aceasta functie este cand aplicatia seteaza planul indepartat la "indepartat", astfel nemaifolosind de fapt o parte din z- buffer.

Figura 6.15: Exemplu de functie

Trebuie sa se observe faptul ca prin procesul de normalizare, intervalul de adancime al scenei este intotdeauna mapat la intervalul de adancime al monitorului, chiar daca oricare dintre functiile exemplu prezentate in aceasta sectiune sunt folosite sau nu. Adancimea scenei este intotdeauna compresata sau expandata pentru a se potrivi in intervalul de adancime al monitorului (cu exceptia cazului rar in care ele se potrivesc perfect).

Nu vom intra in mai multe detalii despre aceasta scena deoarece ea nu este specifica redarii RGBD pe GPU, dar se aplica in general tuturor tipurilor de redari RGBD. Controland cum adancimea scenei este mapata la adancimea perceputa a monitorului este discutata mai departe in [16, 17].

Capitolul 7

Redarea RGBD pe GPU

Abordarea noastra de redare RGBD este implementata pe GPU prin folosirea unui OpenGL wrapper ca si in metoda veche descrisa in capitolul 3. OpenGL wrapper-ul trebuie sa indeplineasca anumite sarcini:

  1. Sa lase aplicatia (jocul) sa redea un singur cadru. Mai intai wrapper-ul trebuie sa lase aplicatia sa redea un cadru asa cum ea ar face in mod normal fara wrapper, cu singura diferenta ca acest cadru trebuie redat la o rezolutie normala in timp ce monitorul este intr-un mod de rezolutie inalta. Lucrul acesta este necesar deoarece datele introduse pentru redarea RGBD trebuie sa fie o imagine cu o rezolutie normala si deoarece monitorul 3D merge doar cand este intr-un mod cu rezolutie inalta (rezolutia originala, vezi sectiunea 2.4.1).
  2. Sa copieze continutul framebuffer-ului in structuri. Cand aplicatia a terminat redarea cadrului ea apeleaza functia swapbuffer. Acesta este semnul pentru wrapper sa copieze frambufer-ul (atat cel color cat si Z-bufferul) in structuri.
  3. Sa efectueze calcularea Z la D. Continutul z-buffer-ului nu poate fi folosit direct ca harta de adancime pentru redarea RGBD si prin urmare un pas de conversie este necesar (dupa cum este explicat in capitolul precedent).
  4. Sa efectueze redarea RGBD. Si ultimul pas este sa efectueze redarea RGBD efectiva (pe GPU) avand ca date de intrare harta de adancime creata in pasul precedent si structura color din pasul al doilea.

Aceste patru functii vor fi discutate in mai multe detalii in urmatoarele patru sectiuni.

7.1 Redarea vederii centrale

Pentru redarea RGBD este necesar ca aplicatia sa redea vederea centrala la o rezolutie normala (de exemplu 800x600), in vreme ce monitorul insusi sa fie intr-un mod cu rezolutie inalta (de exemplu 1600x1200). Exista doua modalitati de a realiza acest lucru:

  1. Prin scalarea portului de vedere

Se lasa jocul sa ruleze la rezolutie inalta si se ajusteaza portul de vedere in wrapper astfel incat jocul se reda la rezolutie normala. Vom numi acest proces scalarea portului de vedere.

a) Jocul incepe si schimba monitorul la 1600x1200

b) In mod automat, monitorul incearca de asemenea sa redea la rezolutia 1600x1200

c) Wrapper-ul ajusteaza portul de vedere astfel incat jocul se reda la 800x600 (folosind de fapt doar coltul din stanga al monitorului).

d) Rezultatul final: monitorul la 1600x1200 iar jocul la 800x600.

  1. Fara scalarea portului de vedere

Jocul este lasat sa ruleze la rezolutie normala si se schimba rezolutia monitorului la rezolutie inalta in wrapper.

a) Wrapper-ul porneste si schimba monitorul la 800x600

b) Wrapper-ul schimba imediat monitorul inapoi la rezolutia 1600x1200. Monitorul ramane la aceasta rezolutie.

c) Jocul nu observa lucrul acesta si continua sa redea rezolutia 800x600 automat (folosind de fapt in mod automat doar coltul din stanga jos al ecranului).

d) Rezultatul final: monitor la 1600x1200 si jocul se reda la 800x600.

Desi ambele aplicatii realizeaza acelasi lucru, prima prezinta un mare dezavantaj: nu este complet transparenta pentru aplicatie. Continutul framebuffer-ului nu este ceea ce aplicatia asteapta. De exemplu aplicatia se asteapta ca framebuffer-ul sa contina o imagine cu o rezolutie de 1600x1200, dar datorita schimbarilor portului de vedere in wrapper, imaginea este doar de 800x600. Aceasta este o problema deoarece unele jocuri redau o imagine in framebuffer si o folosesc apoi ca textura. O alta problema are loc cand o aplicatie citeste direct din/scrie in frambuffer. Aceste probleme pot fi rezolvate prin schimbarea comportamentului functiilor OpenGL implicate (citirea de la si scrierea in framebuffer direct, vezi tabelul 7.1), sau folosind a doua abordare.

Exista totusi o noua problema cu prima aplicare care nu poate fi rezolvata in wrapper: problema "marimii fontului". Un exemplu poate fi vazut in jocul Quake 3: consola text in joc este intocmita astfel incat fiecare caracter sa ocupe o marime fixa (in pixeli) pe ecran. Aceasta inseamna ca atunci cand jocul este jucat la o rezolutie inalta, mai multe caractere incap intr-o linie. Aceasta cauzeaza probleme la scalarea portului de vedere: jocul crede ca ruleaza la 1600x1200 si astfel reda multe caractere pe o linie. Dar datorita scalarii portului de vedere, caracterele sunt micsorate: ele devin mici si prin urmare dificil de citit. Aceasta nu poate fi rezolvata (precum celelalte probleme) prin schimbarea comportamentului functiilor OpenGL in wrapper: jocul este cel care decide cate caractere sa redea pe o singura linie. Problema nu este limitata numai la exemplu marimii fontului: tot ceea ce aplicatia reda cu marime fixa (in pixeli pe ecran) sufera de aceasta problema.

A doua abordare nu sufera de problemele de mai sus, dar are o alta problema: schimbarea rezolutiei monitorului in timp ce jocul ruleaza nu este usor de suportat. Experienta noastra este ca merge bine pe cardurile Nvidia dar cauzeaza probleme pe cardurile ATI pe care le-am incercat.

S-au implementat ambele optiuni. S-au identificat functiile OpenGL care cauzeaza probleme cu prima abordare (vezi tabelul 7.1). Toate aceste functii logheaza un mesaj ce avertizeaza cand sunt apelate in timp ce se foloseste scalarea portului de vedere. Ambele solutii au dezavantajele lor si depinde de situatia exacta (joc, cardul grafic, etc) ce solutie sa se foloseasca. Nu exista diferente de performanta intre cele doua optiuni.

Functia

Descrierea

glBitmap

traseaza un bitmap

glCopyPixels

copieaza pixeli in framebuffer

glCopyTexImage1D, 2D si 3D

copieaza pixeli din framebuffer in imagine cu textura n-dimensionala

glCopyTexSubImage1D, 2D si 3D

copieaza o sub-imagine a unei imagini cu textura n-dimensionala din framebuffer

glDrawPixels

scrie un bloc de pixeli in framebuffer

glReadPixels

citeste un bloc de pixeli din framebuffer

Tabelul 7.1: Functiile OpenGL care pot cauza probleme la scalarea portului de vederea.

7.2 De la framebuffer la texturi

Pixel shader-ul nostru are nevoie de acces pentru citirea continutului framebuffer-ului, deoarece el contine datele care sunt introduse la redarea RGBD. Lucrul aceasta nu este posibil in mod direct. Totusi, pixel shader-ul are acces sa citeasca texturile. In acest fel, prin copierea continutului framebuffer-ului in structuri, pixel shader-ul poate avea acces la el.

Copierea din framebuffer in textura trebuie sa aiba loc pe cardul grafic insusi (si nu prin intermediul memoriei sistemului). Lucrul acesta este efectuat de functia glCopyTexSubImage2D, ea copieaza datele din framebuffer in textura. In mod normal doar continutul culorii framebuffer-ului poate fi folosit ca sursa, dar extensia ARB_depth_texture a OpenGL permite z-buffer-ului sa fie folosit ca sursa de asemenea.

7.3 Conversia de la Z la D

In sectiunea 6.4 noi am discutat teoria din spatele pasului de conversie de la Z la D. In aceasta sectiune se va discuta implementarea acesteia.

Textura de adancime intermediara



Conversia de la Z la D trebuie sa aiba loc pe cardul grafic folosid un pixel shader (precum redarea RGBD insasi). In esenta, avem doua optiuni pentru a implementa lucrul acesta:

  1. Cu structura de adancime

Conversia de la Z la D este realizata intr-o trecere separata a pixel shader-ului inainte de redarea RGBD. Rezultatul acestri treceri este o textura de adancime. Pixel shader-ul de redare RGBD foloseste aceasta textura de adancime ca input. Cand este nevoie de o valoare de adancime, poate fi luata direct din structura de adancime. Aceasta optiune este prezentata in jumatatea de jos a figurii 7.1.

  1. Fara structura de adancime

Conversia Z la D este integrata in pixel shader-ul de redare RGBD. Aceasta inseamna ca se efectueaza doar o singra trecere a pixel shaderului. Pixel shader-ul de redare RGBD foloseste structura z-bufferul ca input. Cand este nevoie de o valoare de adancime, se aduce o valoare-z de la structura z-buffer si apoi este convetita. Aceasta optiune este prezentata in jumatatea de sus a figurii 7.1.

Ambele optiuni realizeaza acelasi lucru, dar una din ele foloseste structura de adancime ca pas intermediar iar cealalta nu. Folosind aceasta structura de adancime intermediara este o idee buna din doua motive:

Figura 7.1 Doua optiuni: cu sau fara structura de adancime intermediara.

  1. Rezolutia imaginii rezultate interpolate este mai mare decat rezolutia structurii z-buffer introdusa
  2. Pixel shader-ul de redare RGBD are nevoie de mai multe valori de adancipe pentru fiecare pixel rezultat

Haideti sa explicam acest lucru printr-un exemplu: sa presupunem ca jocul reda o rezolutie de 800x600 si rezolutia rezultata (a rezultatului interpolat) este de 1600x1200. Si sa presupunem mai departe ca folosim un pixel shader de redare RGBD care necesita sa citeasca 10 valori de adancime (pentru fiecare pixel rezultat). Acum sa ne uitam la latimea de unda de memorie necesara pentru fiecare cadru pentru citirea structurii, cu sau fara textura de adancime intermediara:

  1. Cu structura de adancime intermediara

In prima trecere, se creeaza structura de adancime. Sunt cititi 800x600 Z (24 bits) si convertiti (cu o functie de textura, din 8 bits Z in D) in D si apoi scrisi intr-o structura de adancime (8 bits). Aceasta necesita 800x600x(3+2+1) = 2.8 106 bytes de latime de unda pentru fiecare cardu. In a doua trecere, se realizeaza redarea RGBD si 10 valori D (8 bits) sunt citite pentru fiecare pixel rezultat. Aceasta necesita 1600x1200x10=19.2 106 bytes de bandwidth pentru fiecare cadru. Totalul de latime de unda de memorie necesar este de 22106 bytes pentru fiecare cadru[10].

  1. Fara textura intermediara de adancime

Intr-o singura trecere sunt realizate atat conversia Z la D cat si redarea RGBD. Pentru fiecare pixel rezultat 10 valori Z (24bits) sunt citite si convertite (intr-o funtie de textura de 8 bits Z in D). Aceasta necesita 1600x1200x10x(3+2) = 96106 bytes de latime de banda pentru fiecare cadru.

In acest exemplu folosind o structura de adancime intermediara salveaza un factor de 4.4 in latimea de unda de memorie pentru fiecare cardu (de la 98MB la 22MB). Acest castig de performanta este cel mai important motiv pentru care noi folosim structura de adancime intermediara.

7.3.2 Pixel shader

Pentru a executa pixel shader-ul care urmeaza sa efectueze conversia din Z la D se traseaza un dreptunghi care are marimea hartii de adancime rezultata. Cand se rasterizeaza acest dreptunghi, se executa pixel shader-ul pentru fiecare pixel din dreptunghi (care va deveni harta de adancime rezultata). Sarcina pixel shader-ului este de a citi o valoare-z din structura z-buffer-ului, sa o converteasca in valoare de adancime, si sa o redea ca valoare de culoare rezultata. Pseudocodul pentru toate acestea este prezentata in figura 7.2.

pentru fiecare pixel in harta de adancime:

citeste valoarea-z din structura z-buffer-ului;

converteste valoare-z in valoare de adancime;

culoarea rezultata = valoare adancime; //scrie framebuffer-ului

Figura 7.2 Pseudocod pentru conversia din Z in D.

Bucla din pseudocod poate fi vazuta ca executarea repetata a unui pixel shader. Codul din interiorul buclei este echivalentul unui pixel shader. Partea cea mai interesanta a unui pixel shader este cum reuseste sa faca conversia lui Z la D, iar lucrul acesta va fi discutat in urmatoarea sectiune.

Cand se efectueaza conversia lui Z la D harta de adancime rezultata se gaseste in framebuffer (color). Aceasta deoarece rezultatul unui pixel shader este o culoare care (in mod normal) ajunge in framebuffer. O functie OpenGL se apeleaza ulterior pentru a copia continutul framebuffer-ului intr-o textura de scala gri (structura hartii de adancime). O solutie mai rapida ar fi redarea directa intr-o structura (fara a trece prin framebuffer). Extensia ARB_render_texture poate sa ofere aceasta functionalitate. Aceasta ramane de analizat in viitor.

Functia de structura

Functia "din Z la D" (vezi ecuatia 6.7) converteste valorile-z in valori de adancime. Pixel shader-ul nostru ar trebui sa foloseasca aceasta functie. Din punct de vedere al calculelor este (prea) scump sa evaluezi functia Z la D intr-un pixel shader. De aceea functia este evaluata pe CPU pentru un numar fix de input-uri si rezultatele sunt storate intr-o structura 1D (o matrice). Structura are o latime de 256 texels de exemplu si fiecare texel poate fi storat intr-o valoare de 8-bits. Pixel shader-ul care realizeaza calcularea lui Z la D foloseste valoarea-z (citita din textura z-buffer-ului) ca adresa de unde se preia structura pentru structura functie. Datorita filtrarii structurii biliniare realizata de cardurile grafice rezultatul luat din structura este interpolat in mod liniar intre doua valori cele mai apropiate. In felul acesta functia de transformare a lui Z in D este aproximata destul de exact prin valorile storate in structura.

Codul pixel shader-ului Cg este prezentat in apendicele A1. Cand se compileaza cu profilul fp30 programul Cg are 3 instructiuni (din care 2 sunt aduceri de textura). Functionarea acestuia va fi discutatata in capitolul 8.

Datele Z introduse in funtia de transformare a lui Z la D trebuie sa aiba o precizie de mai mult de 8 bits. O structura z-buffer de 8 bits nu are destul de multa precizie pentru a fi folosita pentru functia de transformare a lui Z in D. Cand se realizeaza acest lucru oricum, rezulta in artifacte de banda dupa cum este prezentat in figura 7.3. Structura z-buffer ar trebui sa aiba o precizie mai mare de 8 bits si in general, pe un card grafic aceasta inseamna 16 sau 24 bits.

Figura 7.3: Harta de adancime (calculata din valori ale z-buffer-ului de 8 bits) cu artefacte de banda.

Rezultatul functiei Z la D, harta de adancime, poate fi storata cu o precizie de 8 bits. Aceasta este de ajuns pentru exemplul nostru de monitor 3D deoarece 256 "nivele de adancime" sunt de ajuns pentru intervalul de adancime perceput.

Reducerea hartii de adancime

In timpul conversiei lui Z la D rezolutia hartii de adancime rezultata (in pixeli) poate fi mai mica decat rezolutia (in pixeli) a z-buffer-ului. Acest lucru poate fi realizat variind marimea dreptunghiului care este desenat pentru a executa pixel shader-ul. Aceasta duce la cresterea performantei si scaderea calitatii. Reducerea hartii de adancime duce la reducerea conversiilor din Z la D, copierea mai rapida din framebuffer in structura si latime de banda de memorie mai mica in timpul redarii RGBD. Reducerea hartii de adancime este o optiune a software-ului nostru care poate fi redata in fisierul de configuratie (vezi apendicele B.1).

7.3.3 Detectarea matricei de proiectie

Pentru a construi structura functiei de transformare a lui Z in D pe un CPU sunt necesare valorile pentru planele apropiate si indepartate. Aceste 2 valori determina forma precisa a functiei (vezi figura 6.10). Wrapper-ul trebuie sa detecteze aceste doua valori cand aplicatia seteaza o matrice de proiectie de perspectiva. Lucrul aceasta nu este pe atat de simplu pe cat pare.

Solutia cea mai usoara este sa se foloseasca o functie fixa, independenta de planurile apropiat si departat folosite de catre aplicatie. De exemplu: noi putem sa presupunem ca raportul apropiat:indepartat este de 1:500 si sa folosim acest raport pentru a calcula functia Z in D. Aceasta functioneaza oricum, desi rezultatele nu sunt tocmai corecte (deoarece aceasta este posibil doar cand se cunoaste raportul exact apropiat:indepartat).

Solutia corecta este sa se detecteze valorile planurilor apropiat si indepartat folosite de catre aplicatie. O abordare simpla este sa se astepte apelarea SwapBuffer-ilor si apoi sa se citeasca matricea proiectiei curente. Aceasta functie nu functioneaza in multe din cazuri: pana cand aplicatia apeleaza la functia de SwapBuffers matricea de proiectie poate fi diferita de matricea de proiectie folosita pentru a reda scena. De obicei, jocurile redau unele suprapuneri 2D peste scena redata folosind o proiectie ortografica. Cand se seteaza proiectia ortografica, ea inlocuieste matricea de proiectie de perspectiva. Cand se apeleaza functia de SwapBuffers nu se mai poate oricum sa se determine care era matricea de proiectie veche. De aceea este nevoie de o solutie mai buna.

Tot ceea ce face aplicatia OpenGL trece printr-un wrapper, de asemenea si modificarea matricei de proiectie. Aceasta ne da noua posibilitatea de a detecta schimbarile facute matricei de proiectie in momentul cand aceastea au loc. In tabelul 7.2 se prezinta o lista de functii OpenGL care pot (eventual) schimba matricea de proiectie. In wrapper aceste functii isi extind functionalitatea ceea ce le permite sa vada cand o matrice de proiectie de perspectiva este setata sau modificata. Apoi valorile de apropiere si de departare pot fi determinate din aceasta matrice de proiectie si functia exacta Z in D poate fi construita. Totusi, exista unele complicatii: matricea de proiectie se poate schimba pentru fiecare cadru, deci ea trebuie sa fie detectata din nou pentru fiecare cadru. Situatia se inrautateste si mai mult: ea se poate chiar schimba cand aplicatia reda un cadru. O aplicatie poate de exemplu sa redea o parte dintr-o scena (cu o proiectie de perspectiva), sa schimbe proiectia de perspectiva, si sa redea o parte diferita a scenei. Aceasta inseamna ca nu este necesara o singura functie Z in D care sa fie corecta pentru toata scena. Aceasta totusi, este o problema mai mult teoretica decat una practiva: wrapper-ul curent detecteaza numai prima matrice de proiectie de perspectiva folosita pentru fiecare nou cadru, si aceasta este folosita pentru a calcula functia Z la D pentru acel cadru. Acest lucru se pare ca functioneaza bine pentru moment.

Functia

Descrierea

glFrustum

glLoadIdentity

glLoadMatrix

glMultMatrix

glPopMatrix

glPushMatrix

multiplica matricea curenta printr-o matrice de perspectiva

inlocuieste matricea curenta cu matricea de identitate

inlocuieste matricea curenta cu o matrice arbitrara

multiplica matricea curenta printr-o matrice arbitrara

impinge stack-ul matricei curente

pop stack-ul matricei curente

Tabelul 7.2 Functii OpenGL care pot shimba matricea de proiectie

7.3.4 Erori Z-buffer

Daca privim imaginea 2D din figura 6.6 si harta sa de adancime in figura 6.8 se pot observa 2 lucruri:

  1. Culoarea, dar nu si potrivirea adancimii

In unele locuri, un obiect este vizibil in imaginea color, dar nu si in harta de adancime. De exemplu numerele din josul ecranului apar in imagine dar nu si in harta de adancime. Valoarea adancimii in harta de adancime este din fundalul din spatele obiectului

  1. Adancime, dar nu si potrivirea culorii

Un alte locuri, exista o valoare a adancimii in harta de adancime care nu corespunde cu un obiect din imaginea color. Aceasta are loc de exemplu la capul mic din josul ecranului. Dreptunghiul care inconjoara capul apare in harta de adancime dar nu si in imagine.

Aceste doua probleme sunt vizible in harta de adancime, dar adevarata problema este deja prezenta in z-buffer (de vreme ce harta de adancime este tocmai rezultatul unui calcul realizat in z-buffer). O valoarea incorecta a z-buffer-ului va rezulta intr-o adancime incorecta in harta de adancime.

Prima problema este rezultatul faptului ca aplicatia dezactiveaza scrierea z-buffer-ului (si testarea z-buffer-ului) cand se reda suprapunerea 2D. Aceasta are loc in special din motive de functionare (de vreme ce ea salveaza latimea de unda a framebuffer-ului). Ea cauzeaza suprapunerea 2D (majoritatea text) sa aiba valoarea-z a obiectului din spatele acestuia. In imaginea 3D rezultata se pare ca textul este lipid de fundal, ceea ce este un efect ciudat nedorit.

Cand aplicatia OpenGL incearca sa dezactiveze scrierea z-buffer-ului wrapper-ul poate sa previna acest lucru si sa-l tina activ. Aceasta rezolva una din probleme: o valoare-z ajunge sa fie scrisa in z-buffer. Dar valoarea exacta depinde de valoarea-z arbitrara la care aplicatia reda suprapunerea 2D. Noi avem nevoie de o valoare-z specifica pentru ca dorim ca suprapunearea 2D in imaginea 3D rezultata sa aiba o disparitate de ecran zero. Disparitate ecranului zero inseamna ca imaginea 3D este perceputa ca fiind intinsa in planul ecranului (vezi sectiunea 2.3.1). La aceasta adancime ecranul este foarte exact ceea ce face ca textul sa fie mult mai usor de citit. Prin urmare, suprapunerea 2D necesita sa fie redata cu o valoare-z care (atunci cand este convertita in adancime) sa creeze o imagine 3D cu disparitate de ecran 0.

Amintiti-va din ecuatia 5.1 ca o adancime cu aceeasi valoare ca parametrul deplasamentului cauzeaza o disparitate a ecranului de zero (pentru toate numerele de vedere). Sa presupunem ca parametrul de deplasare pentru redarea RGBD este 0.5, atunci adancimea necesara este tot 0.5. Folosind inversul funtiei de transformare a lui Z in D noi putem calcula valoarea-z necesara in z-buffer care sa faca suprapunerile 2D din imaginea 3D rezultata sa apara cu disparitate zero. Sa presupunem ca aceasta valoare este de 0.98. Atunci wrapper-ul are nevoie sa se asigura ca suprapunerile 2D ajung tot timpul in z-buffer cu valoarea de 0.98, indiferent de valoarea-z folosita de catre aplicatie. In prezent, aceasta se realizeaza prin folosirea functiei glDeptRange. Aceasta functie afecteaza schitarea valorilor-z de la coordonatele aparatului normalizate la coordonatele window. Este apelata atunci cand aplicatia seteaza o proiectie ortografica, deoarece suprapunerile 2D sunt de obicei trasate cu acest tip de proiectie.

Cand wrapper-ul schimba valorile-z a obiectelor redate apare o noua problema: z-testul poate acum preveni redarea unui pixel deoarece valoarea-z proprie este mai mare decat valoarea z a pixelului deja desenat. De aceea, z-testul trebuie sa fie dezactivat.

Figura 7.4: Harta de adancime cu unele din erorile de z-buffer rezolvate.

Rezultatul acestora este prezentat in figura 7.4. Textul are o adancime care il face sa aiba o disparitate de ecran zero dupa redarea RGBD. Textul este totusi redat folosind un cadran schitat cu textura semi-transparenta si intreg cadranul are o adancime, nu numai caracterele vizibile din el. Prin urmare, noi am transformat problema noastra din tipul 1 in tipul 2. A doua problema, totusi, nu este usor de rezolvat. Aceasta ramane de realizat in viitor.

Exista o noua problema care poate fi observata in figura 7.4: parul (din centrul imaginii) este de asemenea redat folosind o proiectie rectangulara. Datorita lucrarii noastre, acesta obtine o adancime in harta de adancime. Insa lucrul acesta nu este de dorit: cauzeaza un efect straniu in imaginea 3D rezultata. Wrapper-ul (in general) nu poate sa rezolve aceasta problema. Acesta nu poate sa stie cand obiectele trebuie sa aiba adancimea fundalului si care obiecte trebuie sa apara la adancimea ecranului. Cea mai buna solutie este ca jocul ofera un z-buffer care sa fie pe cat de bun posibil. Unele tehnici care pot fi folosite de creatorii de jocuri pentru a ajuta aplicatiile 3D pot fi gasite in [18].

O alta problema care are ca rezultat harti de adancime incorecte este folosirea efectelor de translarenta. Jocurile recente folosesc din ce in ce mai mult aceste efecte (apa, ceata, etc). Un exemplu poate fi vazut in figura 7.5. Este evident ca aceasta harta de adancime ofera un efect 3D straniu cand este folosita pentru redarea RGBD.

Insa o alta problema este folosirea structurilor semi-transparente. De exemplu: o ramura a unui copac poate fi trasata cu o structura patrata mare. Structura este o imagine a frunzelor de pe ramura. Este transparenta in locurile unde nu sunt frunze. Cand un joc doreste sa redea o ramura, el trebuie doar sa redea un singur patrat cu structura pe el. Aceasta tehnica (structuri semi-transparente) este folosita in mod general. Totusi, aceasta rezulta in harti de adancime incorecte: Intregul patrat ajunge in z-buffer, dar numai ramurile sunt vizibile in buffer-ul color. Lucrul acesta se poate rezolva in viitor prin a face z-buffer-ul sa scrie dependent de valoarea alfa a unui fragment.

In general ne putem astepta ca z-buffer-ul sa devina o sursa de incredere din ce in ce mai mica pentru informatia adancimii datorita a tot felul de "trucuri de redare".

Figura 7.5. Aceasta informatie din z-buffer nu este folosita intotdeauna ca harta de adancime: apa este vizibila dar in josul paginii apa apare in harta de adancime. De asemenea muntele din spate lipseste din harta de adancime.

7.5 Redarea RGBD

A patra si ultima si sarcina a wrapper-ului este se realizeze procesul de redare RGBD. Datele de intrare pentru redarea RGBD sunt textura color-buffer-ului din sectiunea 7.2 si textura adancimii din sectiunea 7.3.

7.4.1 Redarea RGBD avansata versus Redarea RBGD inversa

Algoritmul ar trebui sa ruleze pe cardul grafic insusi deoarece copierea imaginii redate in memoria principala este prea inceata (dupa cum s-a explicat in sectiunea 3.3) si deoarece CPU este prea incet pentru a efectua redarea RGBD in timp real.

Acesta are un impact mare asupra algoritmului nostru: proprietatile hardware pot impune unele constrangeri serioase. Probabil cel mai mare impact este cauzat de faptul ca pixel shader-ii sunt condusi de rezultate, in loc de datele introduse. Aceasta indica un algoritm inversat in loc de un algoritm avansat care ar fi probabil mult mai logic.

pentru fiecare pixel din imaginea rezultata interpolata:

pentru cei trei sub-pixeli:

Gaseste pixelii din imaginea introdusa care sa contribuie la

culoarea acestui sub-pixel

Figura 7.6 Pseudocodul pentru redarea RGBD inversa

Comparati pseudocodul pentru redarea RGBD avansata (din figura 5.4) cu pseudocodul pentru redarea RGBD inversa (figura 7.6). Este foarte importanta diferenta dintre redarea in functie de datele introduse versus redarea in functie de datele rezultate. Redarea RGBD avansata, in esenta, trece de 9 ori peste imaginea introdusa. Pentru fiecare pixel din imaginea introdusa sunt actualizati zero sau mai multi sub-pixeli in imaginea rezultata.

Redarea RGBD inversa este dotal diferita: ea trece o singura data peste imaginea rezultata. Culoarea pentru un sub-pixel poate veni de la oricare pixel(i) introdus(i) intr-un interval orizontal din jurul pixelului rezultat. Intervalul orizontal este limitat deoarece disparitatea maxima a ecranului este limitata. Noi numim acest interval din imaginea introdusa intervalul de cautare. Toti pixelii introdusi in intervalul de cautare sunt posibili candidati: ei pot sa contribuie la culoarea sub-pixelului curent rezultat. Daca ei intr-adevar contribuie sau nu, depinde de adancimea lor (si de vizibilitatea lor, ei nu trebuie sa fie acoperiti). De aceea, noi trebuie sa shimbam fiecare pixel introdus ca posibil candidat si sa vedem daca el contribuie sau nu. Un pixel introdus contribuie daca el se schimba in apropierea pozitie rezultate si daca nu este acoperit de catre alti subpixeli.

Distanta dintre dintre pozitia rezultata si noua pozitie a pixelului introdus determina greutataea sa. Aceasta este o simplificare, dar pentru moment este destul de buna. Greutatea totala intotdeauna se insumeaza la unu. Culoarea sub-pixelului rezultat este actualizata in functie de greutatea si culoarea pixelului introdus.

Bucla externa din figura 7.6 este in esenta executarea repetata a pixel shader-ului. Daca eliminam bucla, noul pseudocod este prezentat in figura 7.7.

Pentru cei trei sub-pixeli:

Pentru fiecare pixel introdus in intervalul de cautare:

Daca pixelul introdus nu este acoperit:

calculeaza greutatea

culoare sub-pixel + = greutate * culoare introdusa;

Figura 7.7: Pseudocodul pixel shader-ului pentru redarea RGBD inversa.

7.4.2 Implementare

Dreptunghi de marimea ecranului

Pentru a executa un pixel shader pentru fiecare pixel din imaginea rezultata trebuie redat un dreptunghi care sa umple complet ecranul, asa numitul dreptunghi de marimea ecranului. Cand acest dreptunghi este rasterizat, ar trebui ca toti pixelii ecranului sa fie acoperiti de dreptunghi. De asemenea coordonatele de textura trebuie sa fie specificate in varfurile dreptunghiului. Cand coordonatele de structura sunt interpolate de catre rasterizer rezulta in coordonate de structura la fiecare pixel. Aceste coordonate de structura trebuie sa fie corecte cu exactitate (deoarece pixel shader-ul le foloseste pentru a calcula numerele vederilor de exemplu). Cum se poate realiza acest lucru este discutat in .

Adrese de structura

Pixel shader-ul nostru de redare RGBD are trei adrese de structura ca date de intrare:

  1. Rezultat: pozitia in imaginea rezultata
  2. RGBD introdus: pozitia corespunzatoare in imaginea color introdusa
  3. D introdus: pozitia corespunzatoare in imaginea de adancime introdusa

Prima coordonata de structura este folosita de catre pixel shader pentru a determina pozitia pixelului in imaginea rezultata pentru care trebuie sa calculeze culoarea. A doua coordonata de structura specifica pozitia corespunzatoare in imaginea color introdusa. De exemplu, daca pozitia in imaginea rezultata este rezultat (x, y) = (100, 200) atunci pozitia corespunzatoare in imaginea color introdusa este input RGBD (x, y) = (50, 100), dat fiind faptul ca rezolutia culorii introduse este jumatate din cea rezultata. Acelasi lucru se aplica si pentru coordonata de structura D introdusa: ea specifica pozitia corespunzatoare in imaginea de adancime introdusa. Aceasta pozitie poate fi diferita de pozitia color introdusa deoarece harta de adancime poate fi redusa in timpul conversiei lui Z in D (vezi pagina 34).

7.4.3 Determinarea numerelor vederii

Primul pas in redarea RGBD folosind pixel shader-ul este de a determina cele trei numere de vedere ale pixelului rezultat. Numerele vederii pot fi deduse din modelul prezentat in figura 2.8 (pentru monitorul nostru luat ca exemplu). In esenta, exista doua optiuni de a determina numerele de vedere: sa le calculam sau sa le cautam intr-o structura (sau o combinatie a acestora). Un posibil calcul este prezentat in figura 7.8.

matricea V =

i = (3x + 4y) mod 9

VR = V[i]

VG = V[(i + 1) mod 9] (7.1)

VB = V[(i + 2) mod 9]

Figura 7.8 Calcularea celor 3 numere de vedere (folosind o cautare cu o matrice mica)

Calculul foloseste pozitia pixelului rezultat pe ecran (x, y) pentru a calcula cele trei numere de vedere VR, VG si VB. Pozitia pixelului (0, 0) este pixelul din partea de stanga sus pe ecran. Calculul foloseste o matrice care contine primele noua numede de vedere in coltul din stanga sus a ecranului. Matricea este atat de mica, incat ea ar incapea in codul pixel-shader-ului. Totusi, ea nu poate fi implementata intr-un pixel shader: indexii matricii (sau indicatori) nu sunt suportati in profilele de pixel shader curente. Noi putem folosi o structura pentru a stora valorile matricii dar aceasta ar costa trei cautari de structura ceea ce nu se doreste. Sau am putea adapta calculul astfel incat sa nu mai fie nevoie de matrice (calculata pe loc), dar aceasta ar creste numarul de calcule, ceea ce nu se doreste de altfel. O mai buna abordare este de a scapa de calcule si doar de a folosi cautarea de structura.

Este posibil sa se creeze o structura mare (cu aceeasi rezolutie ca si rezolutia rezultata) care sa contina pentru fiecare pixel rezultat numerele de vedere ca valoare de culoare RGB. Aceasta singura aducere de structura reda cele trei numere de vedere ca valoare de culoare RGB. Nu mai este atunci nevoie de calcule, dar in schimb este nevoie de mai mult bandwidth de memorie.

Putem reduce in mod considerabil marimea structurii folosind modelul repetarii numerelor. Patratul care se repeta are 3x9 pixeli, ceea ce inseamna ca dupa trei pixeli in directia orizontala, numerele incep sa se repete. Acelasi lucru este valabil si pentru cei noua pixeli in directia verticala.

Texturile din OpenGL au nevoie sa aiba o latime si o inaltime care sa fie multiplu de doi. De vreme ce marimea texturii numarului de vedere nu este multiplu de doi, acest lucru este probelmatic. Exista doua extensii OpenGL care sa indeparteze aceasta limitare:

l        ARB_texture_rectangle

- coordonate de structura dependente de dimensiune (ne-normalizate): interval [0..w]x[0..h]

- modul REPETA wrap nu este suportat

l        ARB_texture_non_power_of_two

- coordonate de structura dependente de dimeniune: interval [0..1]x[0..1]

- mod REPETA wrap suportat

Extensia ARB_texture_rectangle a fost folosita deoarece este suportata de mai multe carduri grafice. De vreme ce modul repeat wrap nu este suportat, diviziarea modulara a coordonatelor structurii este realizata in insusi pixel shader (vezi figura 7.9).

float2 TexCoordViewNrs;

TexCoordViewNrs.x = fmod(Input . TexCoordOutput. x, 3); // x = [0.5 .. 2.5]

TexCoordViewNrs.y = fmod(Input . TexCoordOutput. y, 9); // y = [0.5 .. 8.5]

float3 ViewNrs; ViewNrs = texRECT(ViewNrTexture, TexCoordViewNrs);

ViewNrs = ViewNrs - (5/255.0); // Vederea centrala este 0 acum

Figura 7.9 Codul pixel shader-ului Cg pentru determinarea celor trei numere de vedere.

Dupa ce numerele de vedere au fost determinate din structura, ele sunt toate pozitive. Pentru redarea RGBD nu este necesar ca vederea centrala sa fie 0. O valoare constanta este scazuta din numerele de vedere pentru a realiza acest lucru.

7.4.4 Variante de redare RGBD

Cand se cunosc numerele de vedere, urmatorul pas al pixel shader-ului este sa realizerea redarea RGBD. S-au dezvoltat trei variante de pixel shader pentru redarea RGBD. Ele difera in evaluarea informatica si in calitatea rezultatelor pe care le ofera.

  1. Redarea RGBD a adancimii rezultate
  2. Redarea RGBD a adancimii introduse prin "gasirea celui mai apropiat"
  3. Redarea RGBD a adancimii introduse

Redarea RGBD a adancimii rezultate

Redarea RGBD a adancimii rezultate este un algoritm ieftin din punct de vedere informational. El se foloseste de o aproximare pentru a realiza redarea RGBD care creste performantele dar scade calitatea rezultatului.

Redarea RGBD a adancimii rezultate ia adancimea la pozitia rezultata curenta si o foloseste pentru a determina care din pixelii introdusi se muta catre pozitia rezultata.

Pseudocodul pixel shader-ului pentru redarea RGBD a adancimii rezultate este prezentat in figura 7.10.

determina cele trei numere de vedere;

citeste (pozitia rezultata) adancimea din structura;

calculeaza trei pozitii in imaginea introdusa folosind adancimea si numerele de vedere;

realizeaza trei citiri ale structurii in structura color (culoare1 t/m 3);

culoare rezultata (rosu) = culoare 1 (doar rosu);

culoare rezultata (verde) = culoare 2 (doar verde);

culoare rezultata (albastru) = culoare 3 (doar albastru);

//culoarea rezultata este scrisa in framebuffer

Figura 7.10: Pseudocudul pixel shadeer-ului pentru redarea RGBD a adancimii rezultate

Deoarece nu se efectueaza nici o cautare in imaginea de intrare, redarea RGBD a imaginii rezultate este mult mai ieftina decat "adevarata" redare RGBD (adancime introdusa). Trebuie sa se citeasca doar o singura valoare a adancimii si sa se realizeze doar o singura calculare a mutarii. Cu redarea RGBD "adevarata" toate adancimile tuturor pixelilor introdusi in intervalul de cautare trebuie sa fie citite iar valoarea mutarii trebuie sa fie calculata.

Redarea RGBD a adancimii rezultate foloseste supozitia ca valorile adancimii nu se schimba foarte mult intr-o regiune orizontala mica. El aproximeaza adancimea unui pixel introdus prin adancimea pixelului introdus la pozitia rezultata (corespunzatoare). Deoarece distanta dintre un pixel introdus si pozitia rezultata nu este mare, aceasta aproximare functioneaza bine, ceea ce cauzeaza un artifact in imaginea rezultata dupa cum este prezentat in figura 7.11. Artefactul este mai mare pentru vederile externe (vederea centrala nu are nici un artifact).

Figura 7.11: O singura vedere externa creata prin redarea RGBD a imaginii rezultate. Artefactul din marginea din stanga lansatorului de rachete este clar vizibil. Este rezultatul unei cresteri in harta de adancime.

Codul pixel shader-ului Cg pentru redarea RGBD a imaginii rezultate este prezentat in apendicele A.2.

Cand este compilat cu profilul fp30 programul Cg are 30 instructiuni (din care 5 sunt aduceri de structura). Functionarea va fi discutata in capitolul 8.

In esenta, codul prezinta cum o singura valoare de adancime este citita (folosind pozitia rezultata) si cum aceasta valoare este folosita pentru a calcula pozitia x a celor trei pixeli introdusi. Vectorul datatype float3 este folosit pentru a calcula trei rezultate (pentru r, g,b) imediat. Hardware grafice pot efectua calcule vetorizate (cu pana la 4 componente) fara pierderi de eficienta in comparatie cu calculele scalare. Pozitiile x calculate sunt folosite ca adrese de structura pentru 3 executari de structura in culoarea introdusa.

Redarea RGBD a adancimii introduse prin "gasirea celui mai apropiat "

Varianta celui de-al doilea pixel shader care a fost dezvoltata este numita adancime introdusa gaseste-cel-mai-apropiat. Asa cum specifica si numele, ea se foloseste de adancimea din pozitia de intrare. Aceasta este abordarea corecta: un pixel introdus este mutat in functie de propria adancimea.

A doua parte a numelui este "gaseste-cel-mai-apropiat". Aceasta se refera la faptul ca algoritmul gaseste doar un singur pixel (pentru fiecare sub-pixel in rezultat) care deplaseaza pe cel mai apropiat la pozitia rezultata. Algoritmul este mai costisitor din punt de vedere informational decat varianta precedenta (adancime rezultata). Dar el totusi nu efectueaza toate operatiile necesare pentru algoritmul de redare RGBD "adevarat". Nu se efectueaza nici o tratare a acoperirii sau filtrarii.

Pseudocodul pixel shader-ului pentru redarea RGBD a adancimii introduse gaseste-cel-mai-apropiat este prezentat in figura 7.12.

determina cele trei numere de vedere;

distanta minima = infinit

pentru fiecare pixel introdus (i) in intervalul de calculare:

citeste adancimea din structura;

penru cei trei sub-pixeli (vectorizati):

calculeaza noua pozitie in functie de adancime;

calculeaza distanta dintre pozitia rezultata si noua pozitia;

daca distanta < distanta minima:

pixelul cel mai apropiat = i;

distanta minima = distanta;

pentru cei mai apropiati pixeli introdusi:

citeste culoarea din structura;

culoarea sub-pixelului rezultat = culoare; (doar r, g sau b)

// culoarea rezultata este scrisa in framebuffer

Figura 7.12 Pseudocodul pixel shader-ului pentru redarea RGBD a adancimii introduse gaseste-cel-mai-apropiat.

Algoritmul contine o mica bucla: el trece peste o regiune orizontala mica in imaginea introdusa in jurul pozitiei rezultate. Pozitia (in imaginea rezultata) a pixelului introdus curent este calculata in functie de adancimea sa. Acest lucru este realizat pentru cele trei vederi in acelasi timp (vectorizat). Apoi distanta dintre pozitia calculata si pozitia rezultata este masurata. Scopul este de a gasi pixelul cu cea mai mica distanta. De aceea algoritmul se numeste "gaseste-pe-cel-mai-apropiat". De fapt exista trei pixeli apropiati (pentru r, g, b). O data ce acesti pixeli au fost gasiti, se realizeaza trei aduceri de structura in structura de culoare introdusa pentru a obtine culorile. Doar o singura componenta de culoare din fiecare culoare este folosita. Apoi aceste trei componente sunt combinate in culoarea finala rezultata a pixel shader-ului. Acest pixel ajunge in imaginea rezultata interpolata.

Algoritmul de manipulare a acoperirilor explicat in sectiunea 5.1.3 nu este folosit. Aceasta inseamna ca pixelii care nu sunt vizibili intr-o vedere noua nu sunt indepartati, cum ar fi trebuit. Algoritmul pentru a manipula acoperirile nu este folosit deoarece aceasta ne permite noua sa facem doar o singura trecere pentru pixelii introdusi. Daca se foloseste algoritmul ar insemna ca este necesar trei treceri peste pixelii introdusi (pentru cele trei numere de vedere), ceea ce este mult mai scump. De asemenea nu se realizeaza nici o filtrare: se foloseste doar culoarea pixelului care muta pe cel mai apropiat in pozitia rezultata.

Aceasta varianta este mult mai scumpa decat cea a adancimii rezultate expusa mai sus deoarece se realizeaza o cautare in imaginea introdusa. Latimea intervalului de cautare in imaginea introdusa este ajustabila. Aceasta inseamna ca mai multe aduceri de structura sunt necesare in structura de adacime. Un interval de cautare mai mare inseamna o adancime mai mare in imaginea 3D rezultata, dar mai inseamna si mai multe aduceri de structura.

De asemena, aceasta varianta este mai scumpa pentru ca sunt necesare mai multe calculte: trebuie sa se gaseasca distanta minima. Distanta trebuie sa fie calculata pentru fiecare pixel candidat introdus in functie de adancimea sa. Cum s-a mai precizat, aceste calcule au fost vectorizate oricand a fost posibil.

Un cod pentru pixel shader-ul Cg folosit pentru redarea RGBD a adancimii introduse in baza gasirii celui mai apropiat, este prezentat in apendicele A.3. Cand este compilat cu profilul fp30, programul Cg are 120 de instructiuni (din care 13 sunt aduceri de structura). Aceste numere sunt pentru un interval de cautare de 9 pixeli introdusi. Buclele nu sunt desfasurate de compilatorul Cg.

Dupa implementarea si testarea acestui pixel shader, a devenit clar faptul ca acest algoritm nu este o imbunatatire la versiunea precedenta (adancime rezultata). Shader-ul este incet dar nu produce rezultate mai bune. Artefactele cauzate de aceasta varianta sunt mult mai notabile decat artefactele versiunii precedente, in special pentru imaginile care se misca. Artefactele pot fi observate la margini (in harta de adancime). Artefactele pot varia rapid cand imaginea introdusa se schimba doar putin, pe cand artefactele variantei precedente erau mult mai stabile.

Datorita raportului rau calitate/performanta a acestei variante, ea nu mai este folosita. De asemenea, in capitolul 8 nu se va mai realiza nico o masuratoare a performantei pentru aceasta varianta.

7.4.7 Redarea RGBD a imaginii introduse

Varianta a treia a redarii RGBD se numeste adancime introdusa. Scopul acestei variante este sa fie echivalenta cu algoritmul offline deja existent (din sectiunea 5.2.1). Prin urmare ar trebui sa produca rezultate de mare calitate, ceea ce inseamna: manipularea acoperirilor si descoperirilor si o filtrare mai eficienta.

Pseudocodul pentru pixel shader-ul de redare RGBD a adancimii introduse este prezentat in figura 7.13. Algoritmul consta din trei parti majore: mai itai se citeste (din structura) adancimea si culoarea tuturor pixelilor introdusi in intervalul de cautare si se storeaza in doua matrici. Se realizeaza acest lucru deoarece adancimea si culoarea pixelului introdus sunt necesare de mai multe ori mai tariziu. Storarea lor intr-o matrice reduce numarul de aduceri de structura necesare. Indexarea matricei este posibila in acest caz deoarece buclele nu sunt desfacute de compilatorul Cg.

A doua parte a algorimului foloseste adancimea pixelilor introdusi pentru a calcula noile lor pozitii. Pentru fiecare pixel introdus, se calculeaza trei noi pozitii (pentru cele trei numere de vedere ale sub-pixelilor RGB). Aceste calcule sunt realizate vectorizat din motive de functionalitate.

Noile pozitii ale pixelilor introdusi sunt folosite in partea a treia a algoritmului. Aici se verifica daca un pixel nu este cumva acoperit de un alt pixel. Daca nu este, se calculeaza o asa numita greutate. Greutate defineste cat de mult culoarea unui pixel introdus contribuie la culoarea sub-pixelului rezultat. Greutatea poate fi calculata prin folosirea o functie de filtrare. In functie de greutate, culoarea unui pixel introdus este adaugata la culoarea sub-pixelului rezultat. A treia parte a algoritmului nu poate fi vectorizata ca partea precedenta. Deaoarece algoritmul de detectarea a acoperirilor se bazeaza pe ordinea in care pixelul introdus este procesat. Si nu este cazul mai niciodata ca cele trei numere de vedere sa aiba nevoie de aceeasi ordine. In majoritatea cazurilor, este necesar sa procesam pixelii introdusi de la stanga la dreapta pentru un numar de vedere si apoi de la dreapta la stanga pentru un alt numar de vedere.

determina cele trei numere de vedere;

pentru fiecare pixel introdus in intervalul de cautare:

citeste culoarea din structura in matrice;

citeste adancimea din structura in matrice;

pentru fiecare pixel introdus:

calculeaza trei noi pozitii in functie de adancime (vectorizat)

pentru fiecare sub-pixel rezultat (r, g, b):

culoarea sub-pixelului = 0;

daca numarul de vedere > = 0

pentru fiecare pixel introdus in intervalul de cautare (de la stanga la dreapta)

daca pixelul nu este acoperit

calculeaza greutate;

culoare sub-pixel + = greutate * culoare introdusa;

daca nu

pentru fiecare pixel introdus in intervalul de cautare (de la dreapta la stanga)

daca pixelul nu este acoperi

calculeaza greutatea;

culoare sub-pixel+ = greutate * culoare introdusa;

// culoarea rezultata este scrisa in framebuffer

Figura 7.13. Pseudocodul pixel shder-ului pentru Redarea RGBD pentru imaginea introdusa

Pixel shader-ul nostru efectueaza redarea RGBD a adancimii introduse cu manipularea si filtrarea acoperirilor. Nu produce, totusi, aceeasi calitate ca algoritmul existent deja (offline). De exemplu algoritmul existent are grija de "schimbarea lentilelor" care ajuta la producerea unei calitati mai mare a rezulatului. Pixel shader-ul nostru nu ia aceasta in calcul. De asemenea algoritmul offline poate folosi funtiile de filtrare definite de utilizator. Pixel shader-ul nostru foloseste doar o cutie de filtrare din motive de performanta.

Implementarea tuturor acestora ar face pixel shader-ul atat de mare incat nu ar mai putea fi executat pe carduri grafice. Totusi, pixel shder-ul ofera o buna indicatie a numarului minim de instructiuni necesare pentru a realiza redarea RGBD pe un card grafic. O calitate mai mare ar insemna mai multe instructiuni. Deoarecel pixel shader-ul este foarte incet, nu este foarte folositor decat pentru masuratorile de performanta.

Codul pixel shder-ului pentru redarea RGBD a adancimii introduse este prezentat in apendicele A.4. Cand este compilat cu profilul fp30 programul Cg are 708 instructiuni (dinc are 25 sunt aduceri de structura). Aceste numere sunt pentru un interval de cautare de 11 pixeli introdusi. Buclele nu sunt desfacute de catre compilatorul Cg. Performantele vor fi discutate in capitolul 8.

7.5 Rezultatul YUVD

In loc de a efectua redarea RGBD pe un card grafic, noi putem de asemenea sa realizam redarea RGBD extern. Cardul grafic va fi folosit atunci doar pentru a trimite imaginea 2D impreuna cu harta sa de adancime la exterior (vezi figura 7.14). Philips a dezvoltat o placa externa de redare RGBD. Wrapper-ul nostru a fost extins cu suport pentru a putea crea rezultatul necesar pentru placa externa de redare RGBD.

Figura 7.14. Cand redarea RGBD se face extern, cardul grafic trimite o imagine 2D impreuna cu harta sa de adancime la exterior.

Placa hardware

Placa hardware de redare RGBD dezvoltata de Philips are o imagine 2D impreuna cu harta sa de adancime ca date de intrare si produce o imagine interpolata ca rezultat. Placa are doua porturi DVI: unul pentru intrare si unul pentru iesire. Portul de intrare este conectat la portul de iesire al placii grafice. Portul de iesire este conectat la un monitor 3D (portul de intrare). Aceasta placa hardware dedicata poate efectua o redare RGBD de calitate inalta la un framerate inalt. Datele trebuie introduse in placa la o rezolutie fixa si o rata reinnoita (de exemplu: 729x540 la 60Hz), altfel nu va functiona.

Formatul YUVD

Rezultatul (DVI) a unui card grafic poate sa redea doar trei canale de culoare (RGB). Noi vom dori sa folosim aceaste canale de culoare nu numai pentru culoare, dar si pentru adancime. YUVD este o metoda de impachetare a culorii si a adancimii in aceste canale RGB. Functioneaza daca se folosesc canalele rosu si verde pentru culori si cel albastru pentru adancime. Culorile RGB ale imaginii sunt mai intai convertite in spatii de culoare YUV. Canalul rosu este folosit pentru a stora Y, canalul verde este folosit alternativ pentru a stora U sau V, si canalul albastru este folosit pentru a stora D (adancimea). (vezi figura 7.15). Componentele U si V au doar jumatate din rezolutia verticala a componentei Y, dar aceasta nu reprezinta o problema deoarece ochiul uman este mult mai bun la vederea diferentelor in luminozitate decat in culoare.

Figura 7.15 Informatie despre culoare si adancime storate in canalele RGB prin folosirea formatului YUVD.

Pixel shder

Wrapper-ul OpenGL creat original pentru a reda RGBD a fost extins cu suport pentru rezultatul YUVD. Aceasta face ca jocurile sa poate sa fie jucate in timp real cu calitate ridicata la monitorul 3D (cu ajutorul placii hardware de redare).

Redarea RGBD a fost implementata ca un algoritm pixel shader cu doua treceri (vezi figura 7.1) din motivele discutate in sectiunea 7.3.1. Pentru rezultatul YUVD, totusi, aceste motice nu mai sunt valabile:

  1. Rezolutia rezultatului YUVD este (in majoritate cazurilor) la fel ca si rezolutia RGB (si Z) introdus
  2. Conversia la YUVD necesita doar o singura valoare Z de intrare pentru fiecare valoare D rezultata.

Figura 7.16. Rezultatul YUVD este realizat cu o singura trecere a pixel shder-ului: nu se foloseste structura de adancime intermediara.

Aceasta inseamna ca rezultatul YUVD poate fi implementat ca algoritm de pixel shader pentru o singura trecere, fara pasul intermediar de structura de adancime. Conversia din Z in D poate fi integrata in pixel shader-ul YUVD si aceasta nu creste numarul de calcule pentru conversia Z in D.

citeste culoare din structura;

converteste Z in D (folosind functia de structura);

culoarea rezultata (rosu) = Y;

daca pixelul rezultat este intr-o pozitie egala:

culoarea rezultata (verde) = U;

altfel

culoarea rezultata (verde) = V;

culoarea rezultata (albastru) = D;

Figura 7.17: Pseudocodul pixel shader-ului pentru rezultatul YUVD.

Pseudocodul pixel shader-ului pentru rezultatul YUVD este prezentat in figura 7.17. Codul pixel shader-ului Cg pentru rezultatul YUVD este prezentat in apedicele A.5. Cand este compilat cu profilul fp30, programul Cg are 13 instructiuni (din care 3 sunt aduceri de structura). Performantele for fi discutate in capitolul 8.

Corectie gama in hardware

Toate placile grafice curente suporta corectia gama in hardware. Aceasta inseamna ca RAMDAC al cardului grafic poate efectua corectia gama in hardware astfel incat aplicatia grafica nu mai este nevoita sa faca acest lucru in software. Aceasta nu poate fi aplicata, dar poate interfera cu rezultatul YUVD. Este foarte important ca continutul YUVD din framebuffer sa fie trimis exact la placa hardware fara interferenta corectiei gama in hardware. Aceasta inseamna ca trebuie oprita. Unele jocuri pot fi configurate sa isi foloseasca propriul software de corectie gama in locul celei realizate de hardware. Aceasta este o solutie mai timpurie. Daca jocul nu poate fi configurat sa nu foloseasca corectia gama in hardware, atunci este nevoie de o alta solutie. O solutie posibila este sa determini wrapper-ul sa dezactiveze corectia gama in hardware. Atunci inseamna ca corectia gama trebuie sa fie realizata in alta parte, fie in pixel shader-ul YUVD sa in placa hardware. Niciuna din aceste optiuni nu a fost implementata in prezent.

Filtrare morfologica

Cu redarea RGBD noi vrem sa repetam fundalul (si nu prim-planul) sa umple descoperirile, asa cum a fost explicat in sectiunea 5.1.3. Aceasta este o problema cu continutul care a fost anti-aliased. Efectul de anti-aliasing este acela ca culoarea unui pixel pe o margine a unui obiect este o combinatie de culoare a obiectului (prim planul) si obiectul din spatele lui (fundalul). Valoarea adancimii in harta de adancime are doar o singura valoare: prim plan sau fundal. Pentru a fi sigure ca algoritmul de redare RGBD repeta culoarea de fundal corecta cand are loc o descoperire , harta de adancime poate fi pre-procesata cu un filtru morfologic. Filterul este ales astfel incat sa "creasca" obiectele din prim plan. O implementare simpla (si scumpa) este de a inlocui fiecare valoare de adancime in harta de adancime prin minim 8 valori de adancime invecinate (si valoarea adancimii insasi, astfel sunt 9 in total). Aceasta implementare se numeste morth 3x3. S-au dezvoltat alte 2 variante, numite morph 3x1, morph 5. Ele sunt mai putin scumpe deoarece ele calculeaza minimul prin folosirea valorilor de adancime mai putin invecinate.

Filtrarea morfologica nu este folosita de pixel shader-ii de redare RGBD ai nostri pentru ca ei alte artefacte mult mai severe, dar are sens pentru algoritmul de redare RGBD offline. Dupa ce au fost comparate calitatea si performanta, s-a decis ca varianta morph 3x1 are cel mai bun raport calitate/performanta. Folosind o varianta mult mai scumpa, are un efect aditional foarte mic asupra calitatii.

Codul Cg pentru pixel shader-ul YUVD rezultat cu filtrarea morfologica integrata este prezentat in apendicii A.6, A.7 si A.8.

Capitolul 8

Masuratori si analize de performanta

De vreme ce sofware-ul nostru va fi folosit pentru a juca jocuri interactive, performanta este un aspect important.

Noi am masurat si analizat performanta atat a sofware-ului nostru cat si a aceluia deja existent de "redare multipla". Rezultatele sunt prezentate in acest capitol.

Se va masura mai intai performanta totala (framerate-ul obtinut) in doua jocuri. Folosind aceste masuratori noi vom trage cateva concluzii. Apoi vom arunca o privire mai atenta la diverse aspecte detaliate care determina aceasta performanta generala.

Se va masura doar performanta sofware-ului nostru, si nu si calitatea. Masurarea calitatii este o sarcina dificila si (partial) subiectiva, care nu este considerata utila in prezent. Calitatea diferitelor redari RGBD a fost deja descrisa in sectiunea 7.4.4.

8.1 Sisteme

Pentru masuratorile de performanta s-au folosit doua PC-uri:

l      Sistem '5950': Pentium 4 (2.4 Ghz), Nvidia Geforce FX 5950 ultra (AGP 8x)

l      Sistem '6800': Pentium 4 (2.4 Ghz), Nvidia Geforce FX 6800 ultra (AGP 8x)

Sistemul "6800' are un card grafic de cea mai noua generatie, cardul grafic din sistemul '5950' este cu o generatie in urma. Ambele carduri sunt versiunea cea mai rapida a generatiei lor. Conducand masuratorile pe doua sisteme, ne permite sa analizam cum scaleaza softare-ul in ceea ce priveste noile carduri grafice.

Ambele sisteme au hard- si sofware aproape identice, cu exceptia marimii memoriei, dar aceasta nu ne va afecta masuratorile. Software-ul instalat pe ambele sisteme include urmatoarele:

l      Windows XP

l      Drivere 66.93 Nvidia ForceWare

l      Nvidia Cg Compiler Release 1.3 Beta 2

8.2 Performanta generala

Performanta generala a unei aplicatii grafice poate fi masurata in cadre/secunda (frames/seconds - fps). Un joc poate fi jucat in timp real daca numarul de cadre pe secunda ramane mai mare de o anumita valoare minima. In general, 30-40 de cadre pe secunda este considerat pentru a juca jocurile in timp real.

8.2.1 Masuratori

O serie de teste au fost realizate pentru a determina performanta generala in doua jocuri: Quake 3 si Doom 3. Quake 3 este un joc vechi (lansat in 1999) in timp ce Doom 3 este un joc destul de recent (lansat in 2004). In fiecare joc s-a inregistrat un demo care mai tarziu a fost redat, in timp ce se foloseau urmatorii wrapper/pixel shader:

fara wrapper: Jocul foloseste fisierul opengl32.dll directl. Rezolutia mentionata in table este rezolutia la care este redat jocul

wrapper gol: Jocul foloseste un empty wrapper DLL. Acest wrapper DLL doar     trimite functii de apelare la DLL original, fara a face nimic altceva. Rezolutia mentionata in table este rezolutia la care este redat jocul

redarea a 9 vederi: jocul foloseste wraper DLL-ul de "redari multiple", asa cum a fost explicat in capitolul 3. Jocul este redat la 533x400 si rezolutia imaginii interpolate rezultate este de 1600x1200

RGBD de adancime rezultata: jocul foloseste DLL wrapper-ul nostru cu pixel shader-ul de redare RGBD a adancimii rezultate (vezi sectiunea 7.5.4). Jocul este redat la 800x600 si rezolutia imaginii interpolate rezultate este de 1600x1200. Structura de adancime intermediara nu este redusa: ea este de asemenea: 800x600.

RGBD de adancime introdusa: Jocul foloseste wrapper DLL-ul cu pixel shader-ul de redare RGBD a adancimii introduse (vezi sectiunea 7.4.7). Pixel shader-ul foloseste un interval de cautare de 11 pixeli in imaginea introdusa. (Efectul intervalului de cautare asupra performantei este masurat in sectiunea 8.3). Jocul este redat la 800x600 si rezolutia imaginii rezultate interpolate este de 1600x1200. Structura intermediara de adancime nu este redusa: ea este de asemenea: 800x600.

Rezultat YUVD: Jocul foloseste wrapper-DLL-ul nostru cu pixel shader-ul rezultatului YUVD (vezi sectiunea 7.5). Jocul este redat la 720x540 si rezolutia rezultatului YUVD este de asemenea 720x540.

Rezultatele masuratoriloe sunt prezentate in tabelul 8.1 si 8.2. Varianta de redare RGBD a adancimii introduse gaseste-cel-mai-apropiatnu a fost inclusa in masuratori deoarece este mai inceata decat varianta adancime rezultata, dar produce rezultate mai bune (vezi sectiunea 7.4.6).

In tabele sunt prezentate doua numere: cadre/secunda (fps) si timp pe cadru (ms/cadru). Timpul pe cadru este pur si simplu reciproca framerate-ului (ratei cadrului).

8.2.2 Analize

Ce se poate concluziona din masuratorile de performanta generala?

l        Jucarea de jocuri recente pe monitorul 3D este posibil doar cu un wrapper de redare a adancimii rezultate (33.4 fps) sau cu wrapper-ul de YUVD rezultat in combinatie cu redarea hardware (52.7 fps). Framerate-urile mentionate sunt pentru un card 6800.

test

Geforce 5950

Geforce 6800

fps

ms/cadru

fps

ms/cadru

fara wrapper (800x600)

fara wrapper (1600x1200)

wrapper gol (1600x1200)

redare de 9 vederi

RGBD a adancimii rezultate

RGBD a adancimii introduse

YUVD rezultat (720x540)

Tabelul 8.1: Masuratorile performantei generale pentru jocul Quake 3

test

Geforce 5950

Geforce 6800

fps

ms/cadru

fps

ms/cadru

fara wrapper (800x600)

fara wrapper (1600x1200)

wrapper gol (1600x1200)

redare de 9 vederi

RGBD a adancimii rezultate

RGBD a adancimii introduse

YUVD rezultat (720x540)

Tabelul 8.2: Masuratorile performantei generala pentru jocul Doom 3

l        Shader-ul RGBD al adancimii itroduse este foarte incet, chiar si pe un card 6800 (2.5fps). Un card grafic ar trebui sa fie de cel putin 12 ori mai rapid pentru a permite acestui shader sa ruleze la o viteza acceptabila (30 fps). Pentru masuratorile noastre de performanta noi am folosit un interval de cautare mic de 11 pixeli introdusi. Aceasta limiteaza efecturl 3D. Pentru a produce un output de aceeasi calitate ca cea a algoritmului de redare offline, nivelul de cautare trebuie sa fie marit. De asemenea pixel shader-ul trebuie sa fie imbunatatit (sa se ocupe de miscarea lentilei, sa aiba o filtrare mai buna, etc). Acestea doua combinate ar face pixel shader-ul mult mai incet. De aceea, noi putem fi siguri ca redarea RGBD a adancimii introduse pe cardul grafic nu va fi o optiune viabila in viitorul apropiat (presupunand ca modelul de programare nu se schimba).

l        Shader-ul RGBD al adancimii introduse ruleaza de 15 ori mai repede (in medie) pe un card grafic Geforce6800 decat pe o Geforce 5950. Aceasta poate fi explicata (partial) prin faptul ca 6800 are unitati de pixel shader mai multe si mai rapide. Nu suntem siguri ca aceasta caracteristica va continua in acelasi raport in viitorul apropiat.

l        Wrapper-ul YUVD rezultat are o transmitere de informatie mica (media 4.15 ms/cadru pe un Geforce 5950 si de 1.25ms/cadru pentru un Geforce6800) in comparatie cu 'fara wrapper 800x600'.

8.3 Performanta detaliata

In plus fata de masurarea framerate-ului general obtinut, noi dorim sa stim cat de mult timp ia sarcinilor individuale sa fie realizate. Daca ne uitam la munca realizata pentru un cadru, o putem imparti in doua parti majore: timpul necesar aplicarii sa redea vederea centrala si timpul suplimentar necesar wrapper-ului sa isi execute sarcina. Munca wrapper-ului poate fi divizata mai departe in doua parti mai mici:

  1. Timpul de redare al aplicatiei
  2. Timpul de transmitede de informatie a wrapper-ului

(a) Salveaza & seteaza statusul

(b) Actualizeaza structurile

(c) Conversia lui Z la D

(d) Redare RGBD

(e) Restoreaza statusul

Pentru YUVD rezultat, impartirea este cumva diferita: nu exista un pas separat de conversie Z in D de vreme ce aceasta este introdusa in pasul YUVD rezultat

  1. Timpul de redare al aplicatiei
  2. Timpul de transmitede de informatie a wrapper-ului

(a) Salveaza & seteaza statusul

(b) Actualizeaza structurile

(c) Rezultat YUVD

(d) Restoreaza statusul

8.3.1 Formula framterate-ului

Framerate-ul obtinut f (in cadre/secunda) a aplicatiei grafice in combinatie cu wrapper-ul nostru este determinat de urmatoarea formula:

(8.1)

unde a este timpul (in secunde) necesar pentru aplicatie de a reda un cadru iar w este timpul de transmitere de date (in secunde) necesar pentru wrapper sa-si faca treaba. Sa presupunem ca o aplicatie (fare wrapper) obtine un framerate de 50 cadre/secunda. Aceasta inseamna ca a este 0.02secunde (20ms). Daca folosim aceasta aplicatie in combinatie cu un wrapper care necesita 10ms pentru a-si realiza sarcinile, atunci framerate-ul va scadea la 33.3 fps.

Formula 8.1 este o simplificare a situatie reale. Folosind DLL wrapper-ul aceasta nu afecteaza numai timpul w ci si timpul a necesar de aplicatie pentru a reda un cadru. Aceasta deoarece transmiterea apelurilor de functie la DLL original dureaza ceva timp. Noi vom ignora acest efect in calculele noastre, dar acest efect este vizibil in tabelul 8.1. Exista o diferenta in framerate-ul dintre 'fara wrapper (1600x1200)' si "wrapper gol" (1600x1200)'.

Noi vrem sa aflam cat de mare este timpul de transmitere de date w pentru diferite programe wrapper/pixel shader. Aceasta ne va da posibilitatea de a calcula noul framerate al unei aplicatii grafice dat fiind un framerate original (fara wrapper).

De asemenea, software-ul nostru are multi parametri (rezolutii diferite, intervale de cautare, etc). Noi dorim sa stim cum afecteaza acesti paramentri performanta pasilor individuali prezentati in sectiunea 8.3 si cum se ridica aceasta.

Parametri

E posibil ca parametrii din tabelul 8.3 sa afecteze performanta software-ului nostru.

rezolutia de redare a aplicatiei (#pixeli)

Culoare adancime (bits per pixel)

precizia Z-buffer-ului (bits per pixel)

Rezolutia structurii de adancime (#pixeli)

Rezolutia RGBD sau YUVD rezultata (#pixeli)

Latimea structurii functiei Z in D (#texeli)

Na

Bc

Bz

Nd

No

Nf

Tabelul 8.3. Parametrii care pot afecta performanta sofware-ului nostru.

8.3.2 Masuratori

Fiabilitatea

Noi am adaugat un cod in wrapper-ul nostru care masoara cat de mult timp ia efectuare pasilor prezentati in sectiunea 8.3. Lucrul acesta nu este la fel de simplu precum pare: nu este de ajuns sa se masoare timpul pentru a apelarile functiei OpenGL. Apelarile OpenGL doar trimit cereri de redare la buffer. Redarea actuala este realizata mai tarziu pe placa grafica, in mod nesincronizat. Pentru a obtine rezultate bune de timp, noi trebuie sa asteptam pana cand apelurile OpenGL au fos executate (de hardware). Apelul glFinish poate fi folosit in acest sens: el blocheaza pana cand comenzile anterioare au fost executate. El sincronizeaza CPU cu GPU. Aceasta inseamna ca codul de timp din wrapper afecteaza masuratorile, ceea ce este inevitabil.

In urmatoarele 5 sectiuni se vor discuta masuratorile individuale. Noi vom masura urmatorii pasi:

l        Actualizarea structurilor

l        Z la D

l        Redare RGBD a adancimii rezultate

l        Redare RGBD a adancimii introduse

l        YUVD rezultat

Noi nu vom masura timpii consumati de pasii salveaza si seteasa statusul si restoreaza statusul deoarece acestia sunt foarte mici.

Actualizarea structurilor

Actualizarea structurilor copiaza framebuffer-ul (atat RGB cat si Z) in doua structuri. Deoarece aceasta se realizeaza cu o memorie de copiere pe cardul grafic insusi, timpul pe care acesta il consuma va fi proportional cu rezolutia redata de aplicatie (Na). Alti doi parametri care afecteaza performanta sunt adancimea culorii a buffer-ului color (Bc) si precizia z-buffer-ului (Bz).

Noi am variat valoare Na si am masurat timpul consumat pentru actualizarea structurilor, (cu Bc = 8 si Bz = 24). Asa cum era de asteptat, performanta s-a ridicat in mod liniar cu rezolutia. Aceasta a avut ca rezultat 1.56ns/pixel pe Geforce5950 si 0.69 ns/pixel pe Geforce6800. Folosind aceste rezultate noi putem calcula viteza la care ambele carduri grafice pot copia memoria intern.

(8.2)

(8.3)

Aceste rezultate par corecte.

Noi am folosit doar un buffer color de 32-bits si un z-buffer de 24 bits deoarece buffer-ul color de 16-bits si cel Z de 16 bits nu mai sunt folositi de jocurile moderne.

Din Z la D

Timpul de transformare a lui Z la D va lua un timp proportional cu rezolutia structurii adancimii rezultate (Nd). Alti parametri care pot fi variati sunt rezolutia datelor intrate (textura Z-buffer, Na) si latimea (in texeli) a structurii functie (Nf).

Noi am variat rezolutia structurii adancimii Nd si am masurat timpul necesar de transformare a lui Z in D in timp ce am tinut alti parametri constanti (Na = 800x600 si Nf = 256). Dupa cum s-a asteptat, performanta s-a scalat proportional cu rezolutia. Aceasta a dus la 0.67ns/pixel pe un Geforce5950 si 0.24ns/pixel pe un Geforrce6800.

Noi nu am masurat efectul creat de varierea rezolutiei structurii Z Na, dar acesta ar trebui sa aiba un efect foarte mic. Numarul de aduceri de structura depinde numai de rezolutia structurii adancimii rezultate: o aducere de structura este realizata in structura Z si este pentru fiecare pixel in structura adancimii.

Schimband latimea structurii functie Z la D (Nf) nu a avut un impact masurabil asupra rezultatelor.

Redarea RGBD a adancimii rezultate

Performanta redarii RGBD a adancimii rezultate depinde de urmatorii parametri: rezolutia structurii de culoare (Na), rezolutia structurii de adancime (Nd), rezolutia rezultata (No) si parametrul de amplificare.

De departe, rezolutia rezultata este factorul cel mai important. Noi am variat rezolutia rezultata No si am masurat performanta in timp ce am pastrat toti ceilalti parametri constanti (Na = 800x600 si Nd = 800x600). Dupa cum s-a asteptat, a existat o relatie liniara intre performanta si rezolutia rezultata. Aceasta a dus la 12.07ns/pixel pe un Geforce5950 si 1.89ns/pixel pe un Geforce6800.

Variind rezolutia structurii adancimii (Nd) ar trebui sa aiba un efect foarte mic asupra performantei deoarece numarul de executari de structuri de adancime depinde numai de rezolutia rezultatului: o executare de structura in structura de adancime este realizata pentru fiecare pixel in imaginea rezultata. Noi nu am masurat acest efect.

Redarea RGBD a adancimii introduse

Performanta redarii RGBD a adancimii introduse depinde de urmatorii parametri: structurii de culoare (Na), rezolutia structurii de adancime (Nd), rezolutia rezultata (No) si parametrul de amplificare. Noi am variat rezolutia rezultata No in timp ce am pastrat toti ceilalti parametri constanti (Na = 800x600, Nd = 800x600 si interval de cautare de 11 pixeli de intrare). Dupa cum s-a asteptat, a existat o relatie liniara intre timpul necesar si rezolutia rezultata. Aceasta a dus la 3292 ns/pixel pe un Geforce5950 si 207.7 ns/pixel pe un Geforce6800.

Noi am variat de asemenea intervalul de cautare si am pastrat toti ceilalti parametri constanti. Masuratorile rezultate sunt prezentate in figura 8.1 si 8.2. Dupa cum se observa in aceste doua grafice, relatia dintre intervalul de cautare si timpul necesar este ne-liniara. Lucrul aceasta a fost de asteptat deoarece un interval de cautare mai mare inseamna ca cache-ul structurii de pe cardul grafic este folosit mai putin eficient.

Figura 8.1: Masuratori RGBD ale adancimii introduse pe un 5950

Figura 8.2: Masuratori RGBD ale adancimii introduse pe un 6800.

Performanta pixel shader-ului YUVD rezultat depinde in special de rezolutia rezultata (No) si doar putin de rezolutia de redare a aplicatiei (Na). In mod normal, aceste doua rezolutii sunt una si aceeasi, sau doar putin diferite. Cand se foloseste pixel shader-ul YUVD rezultat are sens sa se lase jocul sa redea un cadru la aceeasi rezolutie ca cea a YUVD rezultat. In acel caz, nu trebuie realizata nici o crestere sau reducere, deci nu se pierde calitatea. Numai atunci cand jocul nu se poate reda la rezolutia ceruta de YUVD rezultat, trebuie aleasa o alta rezolutie. De exemplu, atunci cand jocul nu se poate reda la 720x540, este configurat sa se redea la 640x480 in schimb.

Pixel shader-ul YUVD rezultat scaleaza automat aceasta valoare la 720x540.

Exista un numar diferit de variante ale YUVD output, ele difera numai in tipul de filtrare morfologica pe care ei o executa z-buffer.

Noi am variat rezolutia rezultata No in timp ce am pastrat toti ceilalti parametri constanti (Na = 800x600). Dupa cum s-a asteptat, a existat o relatie liniara intre timpul necesar si rezolutia rezultata. Rezultatele masuratorii sunt in tabelul 8.4.

8.3.3 Analize

Toate masuratorile detaliate sunt colectionate in tabelul 8.4:

etapa

simbol

ns/pixel

5950

6800

actualizare structuri

Put

1.56

0.69

Z inD

Pztod

0.67

0.24

RGBD adancime rezultata

Prgbd-od

12.07

1.89

RGBD adancime intrata

Prgbd-id

3292

207.7

YUVD

Pyuvd

7.87

1.54

YUVD morph 3x1

Pyuvd31

17.03

2.83

YUVD morph 5

Pyuvd5

21.04

4.17

YUVD morph 3x3

Pyuvd33

42.39

6.87

Tabelul 8.4. Masuratori de performanta detaliate

Ce poate fi concluzionat din masuratorile detaliate?

l        Pasul Z la D este foarte rapid cand este comparat cu pasul de redare RGBD. Optimizarea acestuia nu poate avea un efect mare.

l        YUVD rezultat cu morph 3x1 este aproximativ de doua ori mai incet decat YUVD rezultat (fare filtrare morfologica). Celelalte variante sunt mult mai incete, dar nu ofera o imbunatatire efectiva a calitatii. De aceea, varianta morph 3x1 este "recomandata" sa fie folosita.

Masuratorile din tabel pot fi folosite pentru a calcula framerate-ul pe o aplicatie grafica, dati fiind unii parametri de intrare.

Sa incepem cu cazul cel mai simplu: YUVD rezultat. In acel caz, framerate-ul f poate fi calculat dupa cum urmeaza:

(8.4)

Put este timpul necesar (in secude) etapei de copiere in structura (per pixel). Poate fi gasit in sectiunea 8.3.2. Pyuvd este timpul necesar (in secunde) de YUVD rezultat pentru fiecare pixel rezultat. Poate fi gasit in tabelul 8.4.

Cu o formula asemanatoare, framerate-ul tuturor ceilalte wrapper/pixel shader poate fi calculat. Nu vom discuta lucrul acesta mai departe intrucat nu are efectiv nici o intrebuintare practica.



https://www.opengl.org/about/overview.html

Suport foarte limitat pentru shaders a aparut in "DirectX 8 class hardware". "DirectX 9 class hardware si mai departe au un suport mai puternic pentru shaders. Doua exemple sunt Nvidia Geroforce FX si ATI Radeon 9500. Ambele suporta extensia OpenGL ARB_fragment_program.

Exemple: FarCry, Doom 3

calculare: 1600 1200 3 sub-pixeli 2 valori/sub-pixel 2 bytes/valoare = 22 MB

APG 8X are o latime de banda de 2.1 GB/s downstream si de 266 MB/s upstream, half-duplex.

PCI Express x16 are o latime de banda de 4GB/s in ambele directii, full-duplex

Redare la textura, vezi 9.2

https://www.opengl.org/resources/tutorials/advanced/advanced98/notes/node308.html

Implementarea curenta este mai putin eficienta: textura de adancime nu este redata direct ci este copiata din framebuffer

Plasamentul OpenGL pixel si texel : https://www.bpeers.com/articles/glpixel




Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 2143
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved