Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pgapi:laboratoare:02 [2024/10/08 16:51]
andrei.lambru
pgapi:laboratoare:02 [2025/09/29 18:23] (current)
andrei.lambru
Line 1: Line 1:
-====== Laboratorul 02 ======+===== Laboratorul 02 =====
  
-<​hidden>​ +===== Deferred Rendering ​=====
-===== Suprafețe generate ​=====+
  
-În multe cazuri, putem cunoaște propietățile unei suprafețe fără a-i cunoaște geometria explicită. Putem genera această suprafață folosind o geometrie generatoare și un proces de generare. În acest laborator, vom explora câteva din metodele de generare existente.+==== Introducere ====
  
-Orice suprafață generată are: +Pentru a desena obiecte iluminate 3D metoda studiată până acum este prin aplicarea directă a calculelor ​de iluminare (iluminare în vertex sau fragment shader) pentru a determina culorile pixelilor suprafețelor desenateAceastă tehnică se numește forward rendering.
-  * Un generator, adică o geometrie explicit definită pe baza căreia are loc procesul ​de generare +
-  * Un algoritm de generareAcesta poate fi bazat pe rotație, translație sau pe orice fel de curbă definită prin puncte de control (ex: Bezier, Hermite, etc)+
  
-Procesul de generare decurge astfel: întâi ​se desenează geometria generator, pe baza căreia va fi construită suprafața generată. După aceasta, ​se desenează un număr ​de instanțe ale geometriei generator, fiecare transformată de funcția de generare într-un mod progresiv. Rezultatul final este obținut prin combinarea topologică a acestor instanțe.+Tehnica forward rendering nu se scalează bine când sunt multe surse de lumină deoarece ​se realizează calculele ​de iluminare și pentru pixelii unor suprafețe care sunt pe urmă obturațde pixelii altor suprafețe care sunt mai apropiați de observator.
  
-===== Diferite tipuri ​de instanțiere =====+Pentru multe surse de lumină este avantajos să realizăm calculele de iluminare doar pentru pixelii care râmăn afișați în final pe ecran.
  
-Instanțierea reprezintă un mecanism prin care se amplifică numărul de primitive trimise la banda grafică. Această amplificare este fie explicită (programată de utilizator ​în shader)fie implicită (generată prin comenzi OpenGL).+Deferred Rendering este o tehnică avansată, extensibilă si versatilă de sinteză în timp real de imagini ale obiectelor dintr-o scenă 3DCu un nume sugestiv, '​intârziat'​ sau '​amânat',​ tehnica se bazează pe desenarea ​de informație a geometriei din fiecare pixel(poziție in spațiul lume, vectorul normal ​în spațiul lumeconstanta difuză, constanta speculară, strălucirea etc.în texturi separate într-un prim pas, amânând procesul de iluminare pentru un pas urmator. Astfel când începe procesul de iluminare se vor folosi informațiile pixelilor celor mai apropiați de observator.
  
-Pentru ​instanția implict geometrieexistă comanda:+==== Forward Rendering ==== 
 +In forward rendering culoarea finală ​unui pixel se obține prin contribuția fiecărui fragment afișat in acel pixeliar pentru culoarea fragmentelor se evaluează contribuția de la fiecare lumină din scenă. Din cauza aceasta, sunt evaluate fragmente ce vor fi acoperite ulterior sau se calculează contribuția neglijabilă a unei lumini îndepărtate.
  
-<code cpp> +==== Deferred Rendering ==== 
-glDrawElementsInstanced(topologienr_indecsitip_data, offset, instante). +In deferred rendering, ecuația de iluminare nu se mai execută pentru fiecare combinație posibilă ​(obiectlumina)ci doar pentru luminile ce garantat au o contribuție ne-neglijabila.
-</​code>​+
  
-De exempludacă aș dori să desenez ​de 15 ori (instanțeun obiect cu 99 de indecși, format din triunghiuri din buffer-ul ​de indecși, legat curent la banda grafică, atunci comanda ar fi:+Acest lucru se face in 3 etape: 
 +  - GEOMETRY PASS: evaluarea informațiilor geometrice si texturale per pixel 
 +  - LIGHT ACCUMULATION PASS: folosind functia de blend (GL_ONEGL_ONE), se acumulează într-o textură rezultatul calculului ​de iluminare pentru fiecare lumină, utilizând informațiile geometrice randate în G-buffer la pasul 1. 
 +  - FINAL(COMPOSITIONPASS: se evaluează culoarea finală a pixelului ca funcție ​de iluminarea acumulată la pasul anterior ​și de informațiile texturale(și poate și geometricee.g. rim light etc.)
  
-<code cpp> +=== Geometry Buffer ===
-glDrawElementsInstanced(GL_TRIANGLES,​ 99, GL_UNSIGNED_INT,​ 0, 15); +
-</​code>​+
  
-Instanțierea explicită se face în shadergenerând geometrie nouă prin comenzi glslîn acest caz prin comenzi de geometry shader: +Pentru a implementa deferred renderingvom folosi un frame buffer maredenumit Geometry Buffersau G-Buffer. Acesta are atașate mai multe render textures utilizând GL_COLOR_ATTACHMENT_i. 
-<code glsl> +{{:pgapi:​laboratoare:​g-buffer.png?500|}}
-for (int index = 0; index < 15; index++) { +
-      gl_Position = P*V*M*vec4(p11);​ EmitVertex();​ +
-      gl_Position = P*V*M*vec4(p2,​ 1);​ EmitVertex();​ +
-      gl_Position = P*V*M*vec4(p3,​ 1);​ EmitVertex();​ +
-      EndPrimitive();​ +
-+
-</​code>​ +
-Instanțirea oferă posibilitatea ușoară de a crește rapid numărul de obiecte din scenă, dacă obiectele sunt identiceExcopaci, tile-uri de teren, unități într-un rts, etc.+
  
-Pentru a lucra cu suprafețe de translație,​ rotație și/sau interpolare,​ vom folosi instanțiere. Totuși, chiar dacă avem N instanțe de geometrie generator, nu avem topologia necesară pentru a lega instanțele,​ deoarece generatorul este o curbă (topologie 2D), iar suprafața generată necesită topologie 3D.+=== Geometry Pass === 
 +In această etapă sunt completate urmatoarele render targets din G-buffer: 
 +  * adâncime(se face automat) 
 +  * poziție 
 +  * normală 
 +  * culoare
  
-{{ :​pgapi:​laboratoare:​poza_suprafete.png?nolink |}}+=== Light Accumulation Pass === 
 +In această etapă sunt completate intrările din G-buffer pentru acumularea de lumină.
  
-Din figură se observă clar cum avem mai multe tipuri de obiecte+Pentru a calcula intersecția intre obiecte și lumini vom folosi obiecte geometrice aferente luminilor: sfera cu rază egala cu distanța maximă de influență pentru lumina omnidirectională, con cu sferă în baza pentru spot light(nu e implementat in laborator).
-  - Obiectul generator (prima linie neagră din stânga) +
-  - Obiectul nou generat (2 instanțe ale generatorului ​și topologie de legatură între linii) +
-  - Suprafața finală generată+
  
-Dacă nu am fi folosit acest proces, atunci prin instanțiere am fi obținut liniile instanțiate,​ dar nu și topologia de legatură între linii, adică exact ca în următoarea imagine:+Pentru fiecare fragment de obiect ce reprezintă o lumină se încarcă poziția si normala din G-buffer ​și se evaluează ecuația de iluminare. Rezultatul este acumulat in bufferul de acumulare din G-buffer.
  
-{{ :​pgapi:​laboratoare:​poza_curbe.png?​nolink |}} +=== Final Pass ===
-</​hidden>​+
  
-===== Suprafețe generate =====+In aceasta etapă se calculează rezultatul final per pixel. Culoarea nu se scrie in G-buffer, ci direct in framebuffer-ul default (cel al ferestrei grafice) sau în altul pregatit pentru postprocesare. Se combină culoarea pixelului cu iluminarea calculată și cu lumina ambientală.
  
-Definim o suprafață generată sub forma unei suprafețe create printr-o metodă de multiplicare a unei geometrii suport. Procesul de creare a unei astfel de suprafețe necesită: +{{:pgapi:​laboratoare:​deferred.png?735|}}
-  * O geometrie generator, ce este definită explicit și pe baza căreia are loc procesul de generare. +
-  * Un algoritm de generare. Acesta poate fi bazat pe un proces de replicare, urmat de o transformare de translație,​ rotație sau orice alt tip de transformare.+
  
-Procesul de generare decurge astfel: întâi se desenează geometria generator, pe baza căreia este construită suprafața generată. După aceasta, se desenează un număr de instanțe ale geometriei generator, fiecare transformată de funcția de generare într-un mod progresiv. Rezultatul final este obținut prin combinarea topologică a acestor instanțe. 
  
-==== Suprafețe de translație ​====+==== Avantaje ​==== 
 +  - Desenarea informațiilor geometrice este eficientă deoarece nu se fac calcule de iluminare. Astfel se determină rapid pixelii cei mai apropiați de observator. 
 +  - Pentru sursele de lumină de intensitate mică se vor realiza calculele de iluminare într-o zonă restrânsă pe ecran. Astfel se evită calcularea contribuției fiecărei surse de lumină pentru fiecare pixel de pe ecran. 
 +  - Extensibilitatea,​ facilitează compoziția cu diverse etape de postprocesare ale informațiilor vizuale(de exemplu detecția contururilor folosind textura de normale și/sau textura de adâncime; efecte de bloom sau strălucire etc.) 
 +  - Nu mai este necesară scrierea de fragment shadere care să primească ca variabile de tip uniform o listă cu sursele de lumină. În pasul de iluminare pentru fiecare sursă de lumină se folosește un shader care tratează doar acea sursă de lumină. 
 +  - Având N obiecte și L surse de lumină complexitatea tehnicii deferred este O(N + L), în timp ce complexitatea forward rendering este O(N * L). De ce? Se separă buclele iterative peste mulțimea de lumini si mulțimea de obiecte din scenă:
  
-O suprafață de translație este o suprafață generată prin instanțierea unui obiect ​generator. Fiecare instanță a generatorului suferă o transformare de translație. O suprafață de translație poate fi definită prin instanțierea unui generator cu fiecare instanță translatată progresiv dupa o funcție.+ Forward: 
 + for (obiect ​in obiecte): 
 + for (lumina in lumini): 
 + calculeaza_iluminarea(lumina,​ obiect)
  
-Un exemplu de suprafață translatată este:+ Deferred: 
 + for (obiect in obiecte): 
 + deseneaza(obiect,​ Gbuffer) 
 + for (lumina in lumini): 
 + deseneaza(lumina)
  
-{{ :​ppbg:​laboratoare:​translation-surface.png?​600 ​|}}+==== Dezavantaje ==== 
 +  
 +  ​Complexitatea algoritmului poate fi dezavantajoasă dacă sunt puține surse de lumină în scenă 
 +  - Nu se pot folosi metode de netezire a muchiilor folosind accelerație hardware ([[https://​www.khronos.org/​opengl/​wiki/​Multisampling#​Multisamplingmultisampling]]). În schimb se pot folosi soluții de sinteză avansată de anti-aliasing,​ precum SSAA, MSAA, FXAA(foarte rapid), TAA, etc. 
 +  - Pentru fiecare informație a suprafeței necesară calculelor de iluminare este necesară adăugarea acestora în G-Buffer pentru fiecare pixel pe ecran. Astfel, se încarcă memoria procesorului grafic. 
 +  - Din cauză că deferred rendering se bazează pe faptul că un singur obiect va fi vizibil per pixel, algoritmul funcționează cât timp obiectele din scenă sunt opace. Obiectele transparente trebuie desenate în alt mod.
  
-==== Suprafețe de rotație ==== +==== Cerințe laborator ====
- +
-O suprafață de rotație este o suprafață generată prin instanțierea unui obiect generator. Fiecare instanță a generatorului suferă o transformare de rotație. Aceasta poate fi definită prin instanțierea unui generator cu fiecare instanță rotită progresiv dupa o funcție. +
- +
-{{ :​ppbg:​laboratoare:​rotation-surface.png?​600 |}} +
- +
-===== Laborator ===== +
- +
- +
-Instanțierea reprezintă un mecanism prin care se amplifică numărul de primitive trimise la banda grafică. Această amplificare este fie explicită (programată de utilizator în shader), fie implicită (generată prin comenzi OpenGL). +
- +
-Pentru a instanția implict geometrie, există comanda: +
- +
-<code cpp> +
-glDrawElementsInstanced(topologie,​ nr_indici, tip_data, offset, instante). +
-</​code>​ +
- +
-De exemplu, dacă se doreste desenarea de 1540 de ori (instanțe) ale unui obiect cu 99 de indici, format din triunghiuri din buffer-ul de indici, legat curent la banda grafică, atunci comanda ar fi: +
- +
-<code cpp> +
-glDrawElementsInstanced(GL_TRIANGLES,​ 99, GL_UNSIGNED_INT,​ 0, 1540); +
-</​code>​ +
- +
-Instanțierea explicită se face în shader, generând geometrie nouă prin comenzi glsl, în acest caz prin comenzi de geometry shader: +
-<code glsl> +
-for (int i=0;​i<​10;​i++) { +
-    gl_Position = P*V*M*vec4(p1,​ 1);​ EmitVertex();​ +
-    gl_Position = P*V*M*vec4(p2,​ 1);​ EmitVertex();​ +
-    gl_Position = P*V*M*vec4(p3,​ 1);​ EmitVertex();​ +
-EndPrimitive();​ +
- +
-+
-</​code>​ +
- +
-În situația în care se utilizează instanțiere implicită, în programul de tip vertex shader, se poate obține numărul de ordine al instanței din care face parte vârful procesat, prin utilizarea atributului de intrare implicit ''​gl_InstanceID''​. +
- +
-<note important>​ +
-In cadrul laboratorului curent, se utilizeaza numarul de ordine al instantei in programul de tip geometry shader. Implicit, standardul OpenGL nu permite accesul la atributul de intrare ''​gl_InstanceID''​. +
- +
-Din acest motiv, a fost creat un atribut de iesire din vertex shader cu numele ''​instance''​ ce este primit sub forma de atribut de intrare in geometry shader cu tipul de data vector de 2 componente ''​instance[2]'',​ conform codului de glsl de mai jos: +
- +
-<code glsl> +
-// Vertex Shader +
-... +
-out int instance; +
- +
-void main() +
-+
-    instance = gl_InstanceID;​ +
-    ... +
-+
-</​code>​ +
- +
-<code glsl> +
-// Geometry Shader +
-in int instance[2];​ +
-... +
-</​code>​ +
- +
-Ambele valori ale vectorului sunt identice si reprezinta numarul de ordine al instantei din care face parte linia de la intrarea programului de tip geometry shader. +
-</​note>​ +
- +
-Instanțirea oferă posibilitatea ușoară de a crește rapid numărul de obiecte din scenă, dacă obiectele sunt identice. Ex: copaci, tile-uri de teren, unități într-un rts, etc. +
- +
-Pentru a lucra cu suprafețe de translație,​ rotație și/sau interpolare,​ se utilizeaza instanțiere. Totuși, chiar dacă avem N instanțe de geometrie generator, nu avem topologia necesară pentru a lega instanțele,​ deoarece generatorul este o curbă (topologie 2D), iar suprafața generată necesită topologie 3D. +
- +
-{{ :​pgapi:​laboratoare:​poza_suprafete.png?​600 |}} +
- +
-Din imagine se observă clar cum avem mai multe tipuri de obiecte: +
-  - Obiectul generator (prima linie neagră din stânga) +
-  - Obiectul nou generat (2 instanțe ale generatorului și topologie de legatură între linii) +
-  - Suprafața finală generată +
- +
-Dacă nu am fi folosit acest proces, atunci prin instanțiere am fi obținut liniile instanțiate,​ dar nu și topologia de legatură între linii, adică exact ca în următoarea imagine: +
- +
-{{ :​pgapi:​laboratoare:​poza_curbe.png?​300 |}} +
- +
-===== Cerințe laborator ==== +
- +
-<note tip> +
-Prin utilizarea tastelor **1**, **2**, **3** și **4**, împreună cu combinația acestora cu tastele **SHIFT** și **CTRL**, puteți controla poziția celor 4 puncte de control ale curbei Bézier. +
-</​note>​ +
- +
-<note important>​ +
-  * În laborator, geometria suport pentru curbă este deja definită. Există două tipuri de instanțieri:​ +
-      * Instanțierea implicită, facută cu comanda glDrawElementsInstanced,​ care este deja implementată și care generează geometria suport de N ori +
-      * Instanțierea explicită, care va fi implementată în geometry shader. +
-  * //Geometria suport trimisă către shader este o linie, ce leagă primul și ultimul punct de control.// Punctele de control sunt accesabile în geometry shader sub numele ''​control_p1'',​ ''​control_p2'',​ ''​control_p3'',​ ''​control_p4''​.  +
-</​note>​+
  
   - Descărcați [[https://​github.com/​UPB-Graphics/​gfx-framework|framework-ul de laborator]]   - Descărcați [[https://​github.com/​UPB-Graphics/​gfx-framework|framework-ul de laborator]]
-  - Trimiteți către shader numărul de puncte generate pe o curbă bezier (''​no_of_generated_points''​) și controlați ​de la tastatură atât acest număr (''​no_of_generated_points''​)cât și numărul de instanțe (''​no_of_instances''​)+  - Completați în metoda ​''​Init''​, atribuirea pentru fiecare din cele 40 de surse de lumină din scenă a unei pozițiia unei raze și a unei culori alese aleatoriu
-  - Modificați fișierul ''​GeometryShader.glsl''​ pentru a desena o curbă Bézier pe baza a 4 puncte ​de control. +  - Pentru fiecare sursă de lumină, desenați o sferă la poziția ei, cu o rază egală cu dublul razei de influență a acesteiaSetați variabilele ​''​light_position'',​ ''​light_color''​ și ''​light_radius''​de tipul uniform, cu informațiile sursei ​de lumină. 
-    * Desenați o polinie, pe baza tipului de geometrie de ieșire ''​line_strip'',​ prin emiterea mai multor vârfuri ale căror poziții se obțin prin eșantionarea curbei Bézier. +  - În fișierul ''​LightPass.FS.glsl'' ​eșantionați texturile din G-buffer ​și folosiți metoda PhongLight ​pentru a calcula influența sursei ​de lumină ce va fi acumulată. 
-    * Permiteți modificarea de la tastatură a numărului de vârfuri ce descriu polilinii. Acest număr trebuie să poată fi scăzut și crescut. +  - Completați în fișierul ''​Composition.FS.glsl'',​ calculul ​de compoziție între culoarea obiectelor ​și influența luminilor asupra obiectelor
-    * După acest pas, rezultatul pe care ar trebui să îl obțineti este următorul: \\ {{ :​ppbg:​laboratoare:​bezier-animation.gif?600 |}} +  - Realizați o animație de orbitare a surselor de lumină. Orbita ​pentru ​fiecare sursă de lumină este în jurul centrului scenei față de axa Oy.
-  - Modificați fisierul ​''​GeometryShader.glsl'' ​pentru a desena o suprafață de translațiepe baza curbei Bézier obținute anterior. +
-    * Desenați o bandă de triunghiuri,​ pe baza tipului de geometrie de ieșire ​''​triangle_strip''​, prin emiterea mai multor vârfuri ale caror poziții se obțin prin eșantionarea a două curbe Bézier, alăturate. +
-    * Utilizațatributul de intrare ​''​instance'' ​pentru a translata banda desenata pe baza numarului ​de ordine al instanței desenate. +
-    * Permiteți modificarea ​de la tastatură a numărului de benzi desenate. Acest număr trebuie să poată fi scăzut și crescut. +
-    * După acest pas, rezultatul pe care ar trebui să îl obțineti este următorul: \\ {{ :​ppbg:​laboratoare:​translation-surface-animation.gif?​600 |}} +
-  - Modificați ​fișierul ''​GeometryShader.glsl'' ​pentru a desena o suprafață de rotație, pe baza curbei Bézier obținute anterior. +
-    * Desenați o bandă de triunghiuri,​ pe baza tipului de geometrie de ieșire ''​triangle_strip'',​ prin emiterea mai multor vârfuri ale căror poziții se obțin prin eșantionarea a două curbe Bézier, alăturate. +
-    * Utilizați atributul de intrare ''​instance'' ​pentru a roti banda desenată pe baza numărului de ordine al instanței desenate. +
-    * Permiteți modificarea de la tastatură ​numărului ​de benzi desenate. Acest număr trebuie să poată fi scăzut și crescut+
-    * Permiteți modificarea ​de la tastatură a tipului de suprafață ce se desenează: suprafață de translație și de rotație. +
-    * După acest pas, rezultatul pe care ar trebui să îl obțineti este următorul: \\ {{ :​ppbg:​laboratoare:​rotation-surface-animation.gif?​600 |}} +
- +
-<​hidden>​ +
-  * Geometria suport trimisă către shader este o linie, ce leagă primul și ultimul punct de control. Punctele de control sunt accesabile în geometry shader sub numele control_p1, control_p2, control_p3, control_p4.  +
-  - Trimiteți către shader numărul de puncte generate pe curbă bezier (no_of_generated_points) și controlațde la tastatură atât acest număr (no_of_generated_points),​ cât și numărul de instanțe (no_of_instances). +
-  - Geometria suport va fi în primul rând folosită ​pentru ​a genera o curbă de tip Bezier. Pentru acest lucru se vor genera de mână în geometry shader mai multe puncte (no_of_generated_points) pentru care se va evalua curba Bezier. +
-  - Se vor genera instanțe deplasate ale curbei bezier folosind translații sau rotații +
-  - Pentru două curbe adiacente, se vor genera triunghiuri,​ ce vor lega geometria generată a instanței curente ​de geometria generată a instanței următoare, generată prin translație sau rotație (practic se vor lega cate 2 triunghiuri pentru fiecare 2 puncte corespondente de pe 2 curbe - vedeți figura de mai jos)Astfel, plecând de la curbe Bezier, se va crea o suprafață. Modificați output-ul GeometryShader-ului astfel încât să trimita mai departe triangle_strip pentru a procesa corect triunghiurile. +
- +
-{{ :​pgapi:​laboratoare:​triunghiuri_curbe.png |}} +
-</​hidden>​ +
pgapi/laboratoare/02.1728395492.txt.gz · Last modified: 2024/10/08 16:51 by andrei.lambru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0