Differences

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

Link to this comparison view

ppbg:laboratoare:09 [2023/12/14 12:21]
andrei.lambru [Curbe Bézier]
ppbg:laboratoare:09 [2024/10/02 09:59] (current)
andrei.lambru
Line 5: Line 5:
 </​note>​ </​note>​
  
-<​note ​tip> +===== Obiecte de tip framebuffer și umbre ===== 
-Pentru rezolvarea cerințelor din cadrul acestui labroator: +  
-  - [[https://​github.com/​UPB-Graphics/​gfx-framework-ppbg | Descărcați]] framwork-ul ​de laborator ​și copiați, din arhiva descărcată, directorul **Lab9**, în interiorul directorului ​//gfx-framework-ppbg\src\lab// din versiunea voastră de proiect. +În acest laborator, vom introduce atât elemente noi de OpenGL, cât și o abordare pentru calcularea umbrelor realizate de iluminarea unei surse de lumină de tip spot. Metoda prezentată aici se numeste ​//metoda mapării umbrelor//, întâlnită în limba engleză sub numele ​de //shadow mapping//.
-  - Adăugați în fișierul ''​lab_list.h'',​ linia ''#​include "lab/lab9/lab9.h"''​. +
-  - Folosiți din nou utilitarul CMake pentru a regenera proiectul. Pentru a vă reaminti procesul de realizare a setup-ului, puteți să reconsultați [[:​ppbg:​setup-framework | pagina]] dedicată acestui lucru. +
-</​note>​+
  
-===== Curbe de formă liberă =====+Prima parte a laboratorului se concentrează doar pe descrierea obiectelor ​de tip framebuffer. Partea a doua descrie succint metoda mapării umbrelor și oferă mai multe detalii doar despre pașii tehnicii, ce țin de utilizarea obiectelor de tip framebuffer.
  
-Introducem conceptul ​de curbă de forma liberă pentru a defini acele curbe ce nu pot fi descrise analitic, printr-o formulă închisă. Exemple de curbe analitice sunt: +===== Obiecte ​de tip framebuffer =====
-  * Cercul -   $ F_c(t) ​(c + r \cdot cos(t), c + r \cdot sin(t)) $   +
-  * Elipsa -  $ F_e(t) ​(c + r_1 \cdot cos(t), c + r_2 \cdot sin(t)) $   +
-  * ... +
  
-Orice curbă ce poate fi desenată, indiferent ​de cât de neregulată este formase consideră curbă de formă liberă. Această ​clasa de curbe include și curbele analitice.+Redarea scenei în fereastra de desenare se realizează, de fapt prin redarea scenei într-o textură specială, ​ce este afișată ulterior în fereastră. API-ul grafic OpenGL nu permite desenarea direct într-o textură, ci impune utilizarea unui obiect suplimentar,​ numit buffer ​de cadru sau framebuffer. Acest obiect conține: 
 +  * **Texturile cu format ​de culoare în care se redă scena**. Pot să fie mai multe texturi pe care se desenează, până la un număr limită dat de procesorul grafic, care este în general 8. Putem să ne gândim la o textură ca la o structură de date în care păstrăm informație oarecarenu doar culoare. De exemplu: putem păstra poziția în spațiul lume a fragmentului,​ obținută prin interpolare între vârfuri, sau vectorul normal în spațiul lume al fragmentului,​ obținut prin același proces ​de interpolare. 
 +  * **Textura în care se păstrează informația de adâncime** a fragmentelor desenate în texturile cu format de culoare. Această ​informație este utilizată în pasul de test de adâncime din procesul de rasterizare.
  
-===== Curbe Bézier =====+Câte un exemplu din informația celor două tipuri de texturi poate fi vizualizat mai jos. Mai exact, în prima imagine de mai jos se poate vedea informația dintr-o textură cu format de culoare, iar sub ea se poate vizualiza informația din textura cu format de adâncime obținută în urma desenării pe textura a cărei informații este vizibilă în prima imagine.
  
-Prima curbă de formă liberă ce a fost definită, cronologic, este curba descrisă mai jos ce a fost popularizată de către Pierre Bézier în anii 60'Aceasta este descrisă inițial ​de către Paul de Casteljau pentru obținerea unui patent în anul 1959, dar este publicată abia în anii 80'. Cei doi autori au dezvoltat independent parametrizarea acestei forme.+{{ :​ppbg:​laboratoare:​color_texture.png?600 |}} 
 +{{ :​ppbg:​laboratoare:​depth_texture.png?​600 |}} 
 +==== Crearea obiectelor ​de tip framebuffer ====
  
-Curba Bézier este o curbă de aproximare ce conține o lista de puncte utilizate pentru ​controla forma curbei. Numarul de puncte din lista poate fi oricat de mare. Formulele pentru curba Bézier, in situatia in care este utilizat ​un numar de 2, 3 și 4 puncte ​de controlarată în felul urmator.+Pentru ​crea un obiect ​de tip framebufferputem folosi directiva OpenGL:
  
-^ Nr. \\ puncte \\ control ^ Formulă | +<code cpp> 
-| 2 |  $ B_2(P_0, P_1, t) = (1-t) \cdot P_0 + t \cdot P_1 $  | +unsigned int framebuffer_object;​
-| 3 |  $ B_3(P_0, P_1, P_2, t) = (1-t) \cdot B_2(P_0, P_1, t) + t \cdot B_2(P_1, P_2, t) $  | +
-| 4 |  $ B_4(P_0, P_1, P_2, P_3, t) = (1-t) \cdot B_3(P_0, P_1, P_2, t) + t \cdot B_3(P_1, P_2, P_3, t) $  |+
  
-^ Nr. \\ puncte \\ control ^ Reprezentare vizuală staticăt = 0.25 ^ Reprezentare vizuală animată, 0 <= t <= 1 | +glGenFramebuffers(1&​framebuffer_object);​ 
-| 2 | {{ :​ppbg:​laboratoare:​bézier_1.png?​400 |}} | {{ :​ppbg:​laboratoare:​bézier_1_big.gif?​400 |}} | +</code>
-| 3 | {{ :​ppbg:​laboratoare:​bézier_2.png?​400 |}} |  {{ :​ppbg:​laboratoare:​bézier_2_big.gif?​400 |}} | +
-| 4 | {{ :​ppbg:​laboratoare:​bézier_3.png?​400 |}} |  {{ :​ppbg:​laboratoare:​bézier_3_big.gif?​400 |}} |+
  
-==== Definiție recursivă ====+Fereastra de desenare deține un framebuffer implicit, ce este creat automat în framework-ul de laborator prin intermediul bibliotecii GLFW. Astfel, orice redare a scenei se realizează inițial în texturile acestui framebuffer. Pentru a desena în texturile obiectului de tip framebuffer creat de noi mai sus sau pentru a modifica acest obiect, este necesară legarea acestuia la banda grafică după cum urmează:
  
-Formula curbei Bézier se poate defini recursiv după cum urmează:+<code cpp> 
 +glBindFramebuffer(GL_FRAMEBUFFER,​ framebuffer_object);​ 
 +</​code>​
  
 +==== Crearea și atașarea texturilor la un framebuffer ====
  
 +În momentul de față avem un framebuffer nou, gol, ce nu conține nicio textură de culoare sau de adâncime, dar care este legat la banda grafică. Putem lega texturi la framebuffer și atunci când vom reda o scenă și acest framebuffer va fi legat la banda grafică, procesul de desenare va scrie rezultatele în texturile obiectului legat de noi.
  
-$$ +Reamintim că pentru a crea o textură cu format de culoarefolosim următoarele directive:
-B_{n}(P_0P_1,..., P_n, t) = (1-t) \cdot B_{n-1}(P_0,​ P_1,..., P_{n-1}, t) + t \cdot B_{n-1}(P_1,​ P_2,..., P_{n}, t) +
-$$+
  
 +<code cpp>
 +unsigned int color_texture;​
  
-==== Formă polinomială ====+glGenTextures(1,​ &​color_texture);​ 
 +glBindTexture(GL_TEXTURE_2D,​ color_texture);​
  
-Forma polinomială a curbei Bézier este după cum urmează:+// Pixelii din interiorul texturii au formatul RGB 
 +glTexImage2D(GL_TEXTURE_2D,​ 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE,​ NULL); 
 +</​code>​
  
 +Pentru a atașa textura cu format de culoare (R, RG, RGB, RGBA), creată mai sus, la framebuffer,​ folosim:
  
-$$ +<code cpp> 
-B(t) = \sum_{i=0}^{n}{\binom{n}{i} \cdot (1-t)^{n-i} \cdot t^i \cdot P_i}, \quad 0 \leq t \leq 1 +glFramebufferTexture(GL_FRAMEBUFFER,​ GL_COLOR_ATTACHMENT0+pct_atasare,​ color_texture, ​0); 
-$$+</​code>​
  
 +Astfel, atașăm textura ''​color_texture''​ la obiectul de tip framebuffer legat la banda grafică pe punctul de atașare ''​pct_atasare''​. Valoarea ''​0''​ de la final ne spune că atașăm primul nivel din mipmap (rezoluția maximă). Dupa cum se poate observa, obiectele de tip framebuffer au puncte de atașare ce sunt foarte similare din punct de vedere conceptual cu ideea de pipe, folosită la definirea informației la nivel de vertex. În API-ul grafic OpenGL, acest tip de proiectare este foarte des folosit. Dacă atașăm o textură la un punct de legare pe care deja este legată o altă textură, legătura veche se va pierde și va rămâne doar cea nouă.
  
-Pentru 4 puncte ​de controlforma curbei Bézier, pe baza definiției ​de mai susarată în felul următor:+Este important să observăm mai sus că punctul ​de atașare este de tip ''​GL_COLOR_ATTACHMENT''​. Mai există un alt tip de punct de atașarecu un singur punct (unic!) folosit pentru textura ​de adâncimenumit ''​GL_DEPTH_ATTACHEMENT''​. Pentru a lega o textură de adâncime, folosim:
  
 +<code cpp>
 +glFramebufferTexture(GL_FRAMEBUFFER,​ GL_DEPTH_ATTACHMENT,​ depth_texture,​ 0);
 +</​code>​
  
 +Procesul de creare a unei texturi ce conține informație de adâncime este similar cu cel de creare a unei texturi ce conține informație de culoare, descris mai sus, cu excepția formatului definit în directiva ''​glTexImage2D'':​
  
-$$ +<code cpp> 
-B(t) = (1-t)^3 \cdot P_0 + 3(1-t)^2 \cdot t \cdot P_1 + 3(1-t)^2 \cdot P_2 + t^3 \cdot P_3\quad \leq t \leq 1 +glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F,​ width, height, 0, GL_DEPTH_COMPONENT,​ GL_UNSIGNED_BYTE,​ 0); 
-$$+</​code>​
  
 +==== Specificarea texturilor de desenare ====
  
 +Putem atașa mai multe texturi la un framebuffer,​ dar API-ul grafic OpenGL ne dă posibilitatea să alegem pe care vrem să le folosim la un pas de desenare. Putem să nu utilizăm unele din texturile unui framebuffer,​ chiar dacă ele sunt atașate la framebuffer.
  
-<​note>​ +Pentru a seta texturile care dorim să fie utilizate ​în procesul ​de desenarefolosim:
-Polinomul următor, utilizat ​în definiția curbei Bézier descrisă mai sus, este cunoscut sub numele ​de polinom Bernsteindupa numele lui Sergei Bernstein, ce l-a propus în anul 1912:+
  
-$$ +<code cpp> 
-b_{i,n}(t) = \binom{n}{i} \cdot t^i \cdot (1-t)^{n-i},​ \quad i=0,...,n +std::vector<GLenumdraw_textures;​
-$$ +
-</note>+
  
 +draw_textures.push_back(GL_COLOR_ATTACHMENT0+attachment_index_color_texture);​
  
-===== Suprafețe generate =====+glDrawBuffers(draw_textures.size(),​ &​draw_textures[0]);​ 
 +</​code>​
  
-Definim o suprafață generată sub forma unei suprafețe create printr-o metodă de multiplicare a unei geometrii suportProcesul ​de creare a unei astfel de suprafețe necesită:​ +Pratic, cu directiva ''​glDrawBuffers'',​ setăm care sunt texturile în care se desenează. În exemplul ​de mai susavem o singură textură atașată pe atașamentul ​de culoare cu numărul 0, pe care o adaugăm într-un vector pe poziția 0.  Dacă avem obiectul ​de tip framebuffer în cauză legat la banda grafică și în fragment shader-ul utilizat pentru desenarea în acest framebufferavem codul de mai josdeoarece în out_color scriem un pixel roșu, toți pixelii texturii ​de culoare vor fi roșii.
-  * O geometrie generatorce 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 replicareurmat de o transformare de translațierotaț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.+<code glsl> 
 +layout(location = 0) out vec4 out_color;
  
-==== Suprafețe de translație ====+void main() 
 +
 +    out_color ​vec4(1, 0, 0, 1); 
 +
 +</​code>​
  
-O suprafață de translație este o suprafață generată prin instanțierea ​unui obiect generatorFiecare 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.+După cum s-a menționat mai sus, putem avea mai multe texturi cu format ​de culoare atașate ​unui framebufferAcest mecanism va fi prezentat în detaliu în laboratorul 6. Dar, ca o previzualizare a informației din acel laborator, codul de mai jos scrie în 4 texturi diferite, de tipuri diferite și se poate observa că textura din atașamentul de culoare numărul 0 este complet roșie, iar cea din atașamentul ​de culoare numărul 1 este complet albastră.
  
-Un exemplu de suprafață translatată este:+<code glsl> 
 +layout(location = 0) out vec4 out_color;​ 
 +layout(location = 1) out vec3 color2; 
 +layout(location = 2) out int int_texture;​ 
 +layout(location = 3) out float float_texture;​
  
-{{ :​ppbg:​laboratoare:​translation-surface.png?600 |}}+void main() 
 +{ 
 +    out_color = vec4(1, 0, 0, 1); 
 +    color2 = vec3(0, 0, 1); 
 +    int_texture = 1; 
 +    float_texture = 3.14; 
 +} 
 +</​code>​
  
-==== Suprafețe de rotație ====+În acest exemplu, pe atașamentul de culoare numărul 0 merge ce scris în out_color, pe atașamentul de culoare cu numărul 1 merge ce este scris în color2, pe atașamentul de culoare cu numărul 2 merge ce este scris în int_texture,​ iar pe atașamentul ​de culoare cu numărul 3 merge ce este scris în float_texture.
  
-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.+==== Verificarea statusului creării unui framebuffer ====
  
-{{ :ppbg:​laboratoare:​rotation-surface.png?​600 |}}+Ultima etapă necesară, înainte de folosirea obiectului de tip framebuffer,​ este testarea corectitudinii creării sale:
  
-===== Laborator =====+<code cpp> 
 +glCheckFramebufferStatus(GL_FRAMEBUFFER);​ 
 +</​code>​
  
 +==== Utilizarea obiectelor de tip framebuffer ====
  
-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).+Așa cum s-a menționat mai sus, pentru redarea scenei în texturile unui obiect ​de tip framebuffer, ​este necesară legarea acestui obiect înainte ​de desenare:
  
-Pentru a instanția implict geometrieexistă comanda:+<code cpp> 
 +glBindFramebuffer(GL_FRAMEBUFFERframebuffer_object);​ 
 +</​code>​ 
 + 
 +În general, înainte de desenarea într-un framebuffer,​ vrem să curățăm texturile cu format de culoare și de adâncime. Valoarea implicită de curățare este culoarea neagră pentru texturile cu format de culoare și valoarea 1 pentru texturile cu format de adâncime:
  
 <code cpp> <code cpp>
-glDrawElementsInstanced(topologie, nr_indici, tip_data, offset, instante).+glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 </​code>​ </​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:+Trebuie specificată și poarta ​de vizualizare în care vrem să desenăm în texturile obiectului ​de tip framebuffer:
  
 <code cpp> <code cpp>
-glDrawElementsInstanced(GL_TRIANGLES,​ 99, GL_UNSIGNED_INT, 0, 1540);+glViewport(0, 0, width, height);
 </​code>​ </​code>​
  
-Instanțierea explicită se face în shader, generând geometrie nouă prin comenzi glslîn acest caz prin comenzi ​de geometry shader: +În situația în care dorim sa desenăîn toată texturawidth și height ​de mai sus reprezintă rezoluția texturilor din framebuffer.
-<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();​+
  
-}+În momentul în care se dorește din nou redarea scenei în texturile obiectului de tip framebuffer implicit, putem folosi: 
 + 
 +<code cpp> 
 +glBindFramebuffer(GL_FRAMEBUFFER,​ 0);
 </​code>​ </​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''​.+===== Metoda mapării umbrelor =====
  
-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.+Noi vom utiliza metoda mapării umbrelor pentru a obține efectul ​de umbre ale iluminării realizate ​de către o sursă de lumină de tip spot.
  
-Pentru a lucra cu suprafețde translațierotație și/sau interpolarese utilizeaza instanțiereTotușichiar dacă avem N instanțe ​de geometrie generator, ​nu avem topologia necesară pentru a lega instanțeledeoarece generatorul este o curbă (topologie 2D)iar suprafața generată necesită topologie 3D.+Metoda conține 2 pași: 
 +  - Redarea scenei într-un framebuffer nou. Această desenare se realizează din poziția sursei ​de lumină, pe direcția de iluminare a surseispecifică tipului de sursă spot. Practic, dorim să vedem ceea ce "​vede"​ sursa de lumină. Pentru simplitate, în laboratorul acesta, sursa va avea un unghi de iluminare de 90 de grade, motiv pentru care se va folosi o proiecție perspectivă cu un unghi de vizualizare atât vertical cât și orizontal de 90 de grade. Texturile obiectului de tip framebufferobținute în urma desenării, **conțin toate punctele din scenă ce sunt iluminate de către sursa de lumină**. 
 +  - Redarea scenei în texturile obiectului de tip framebuffer implicit din perspectiva observatorului. În această desenare, se folosește textura cu format de adâncime obținută la pasul anterior. În fragment shaderfiecare fragment se verifică daca este iluminat ​de către sursa de lumină sau nu. Dacă pozitia în spațiul lume a fragmentuluiobținută prin interpolare între vârfuri"​apare"​ în texturile de culoare ale obiectului de tip framebuffer,​ obținut prin desenarea scenei de la pasul anterior, înseamnă că acel fragment este iluminat și trebuie să se calculeze intensitatea iluminării pentru acesta. Acest "​apare"​ este descris puțin mai în detaliu mai jos.
  
-{{ :​spg:​laboratoare:​poza_suprafete.png?​600 |}}+==== Umbrirea unui fragment ====
  
-Din imagine ​se observă clar cum avem mai multe tipuri de obiecte: +Pentru a verifica dacă un fragment obținut prin redarea scenei din perspectiva observatorului este iluminat sau se află în umbră, putem folosi textura cu format de adâncime ​din obiectul de tip framebuffer obținut la pasul 1. Se verifică dacă distanța dintre poziția în spațiul lume a fragmentului este aceeași cu cea din textura cu format ​de adâncime de la pasul 1, când poziția fragmentului este proiectată în această textură.
-  - 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 liniiadică exact ca în următoarea imagine:+O exemplificare a acestui ​proces ​se regăsește în imaginea de mai josunde pixelul marcat cu roșu în panoul a) este proiectat în pixelul marcat cu roșu din textura cu formatul de adâncime, vizibilă în panoul b). Se poate observa că fragmentul marcat cu roșu în panoul a) a fost obținut ​prin rasterizarea modelului ce descrie terenul, dar proiecția lui pe textura ​de adâncimeîntâlnește un pixel rezultat ​în urma rasterizării modelului de bambus.
  
-{{ :spg:​laboratoare:​poza_curbe.png?300 |}}+{{ :ppbg:​laboratoare:​sm.png?700 |}}
  
-===== Cerințe laborator =====+În situația în care distanța dintre poziția în spațiul lume a fragmentului pentru care se calculează iluminarea și sursa de lumină este mai mare decat cea din textura cu format de adâncime, înseamnă că în această textură este desenat un obiect ce se află mai aproape de sursa de lumină și astfel umbrește fragmentul pentru care calculăm intensitatea iluminării. Acest exemplu este chiar în imaginea de mai sus, unde poziția în spațiul lume a fragmentului din panoul a), de pe teren, este mai departe de sursa de lumină față de pixelul ce se regăsește la poziția proiecției lui în textura cu format de adâncime, unde se află un fragment din frunza bambusului. O observație importantă de care trebuie să se țină cont este ca cele două distanțe sa se compare în același spațiu.
  
 +Trimiterea texturii cu format de adâncime se poate realiza la fel ca trimiterea unei texturi cu format de culoare. API-ul grafic OpenGL are și un alt mecanism special pentru aceste tipuri de texturi, nefolosit în acest laborator. Vedeți observația de mai jos.
 +
 +<code cpp>
 +glActiveTexture(GL_TEXTURE0+nr_unitate_texturare);​
 +glBindTexture(GL_TEXTURE_2D,​ depth_texture);​
 +
 +glUniform1i(glGetUniformLocation(shader->​program,​ "​depth_texture"​),​ nr_unitate_texturare);​
 +</​code>​
 + 
 <note tip> <note tip>
-Prin utilizarea tastelor **1****2****3** și **4**împreună cu combinația acestora cu tastele **SHIFT** ș**CTRL**, separat șcumulat, puteți ​controla poziția celor 4 puncte ​de control ale curbei Bézier.+Există mai multe abordări de implementare a metodei de mapare a umbrelor. În laboratorul curentexistă o implementare minimală a metodeice are scop didactic. Implementarea se regăsește deja aproape completă în frameworkastfel că rămâne ca voi să vă concentrați pe gestionarea obiectelor de tip framebuffer. Dacă dorițsă aflați mai multe informații despre abordările posibile pentru implementarea acestei metode, puteți ​consulta următoarele resurse: 
 +  * LearnOpenGL - https://​learnopengl.com/​Advanced-Lighting/​Shadows/​Shadow-Mapping 
 +  * Tipul de date //shadow samplers// - [[https://​www.khronos.org/​opengl/​wiki/​Sampler_(GLSL)#​Shadow_samplers]]
 </​note>​ </​note>​
  
-  ​- 0.1p Modificați fișierul ''​GeometryShader.glsl'' ​pentru a desena ​o curbă Bézier pe baza a 4 puncte ​de control. +===== Cerințe laborator ===== 
-    * Utilizați formula specifică unei curbe Bézier cu 4 puncte ​de controldescrisă mai sus+ 
-    * Desenați o bandă de linii, 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. +  ​- 0.25p Creați un obiect de tip framebuffer ​și utilizați-l ​pentru a desena ​geometria obiectelor din perspectiva sursei de lumină de tip spot: 
-    * Permiteți modificarea ​de la tastatură a numărului de vârfuri ce descriu banda de liniiAcest număr trebuie să poată fi scăzut ​și crescut+    * Completați metoda ''​CreateFramebuffer()''​ pentru a genera un nou obiect ​de tip framebufferîmpreună cu texturile atașate la el
-    * După acest pas, rezultatul pe care ar trebui să îl obțineti este următorul: ​ +    * Legați, pe rând, obiectul ​de tip framebuffer,​ creat anterior, la banda grafică pentru pasul 1 al metodei ​de mapare a umbrelor ​și obiectul de tip framebuffer implicit pentru pasul 2. După acest procesdacă totul a fost realizat corect până aici, pe ecran se vor afișa în partea dreapta-jos,​ texturile cu format de culoare și de adâncime ale obiectului de tip framebuffer creat de voi, obținut prin redarea geometriei obiectelor din poziția sursei ​de lumină. Pentru a schimba între afișarea ​și ascunderea texturilor de pe ecran, se poate folosi tasta **F1**
-{{ :​ppbg:​laboratoare:​bezier-animation.gif?600 |}} +    * După acest pas, rezultatul pe care ar trebui să îl obțineti este următorul: {{ :​ppbg:​laboratoare:​shadows.png?600 |}} 
-  - 0.15p Modificați fisierul ''​GeometryShader.glsl''​ pentru a desena o suprafață de translație,​ pe baza curbei Bézier obținute anterior. +  - 0.05p Utilizați textura cu format de adâncime obținută prin redarea geometriei obiectelor din perspectiva sursei ​de lumină pentru a crea efectul de umbre: 
-    * 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+    * În metoda ''​RenderSimpleMesh'',​ trimiteți textura cu format ​de adâncime din obiectul ​de tip framebuffer creat de voi, obținută la pasul 1 al metodei de mapare a umbrelor
-    * Utilizați ​atributul ​de intrare ​''​instance'' ​pentru a translata banda desenata pe baza numarului de ordine al instanței desenate. +    * Utilizați ​factorul ​de umbrire în programul de tip fragment shader cu numele ​''​ShadowMappingPassTwo.FS.glsl''​. 
-    * 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:​shadows1.png?600 |}} 
-    * După acest pas, rezultatul pe care ar trebui să îl obțineti este următorul: ​ + 
-{{ :​ppbg:​laboratoare:​translation-surface-animation.gif?600 |}} +<note tip> 
-  - 0.05p - Modificațfișierul ''​GeometryShader.glsl''​ pentru a desena o suprafață de rotațiepe baza curbei Bézier obținute anterior. +Poziția sursei de lumină de tip spot poate fi controlată prin intermediul tastelor **W**, **S****A****D**, **Q** și **E**, în absența apăsării butonului dreapta de la mouseDe asemenea, direcția de iluminare ​sursei ​de lumină se poate controla prin săgeți. 
-    ​Desenați o bandă de triunghiuripe 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ézieralăturate. +</​note>​
-    ​Utilizaț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ă ​tipului ​de suprafață ce se desenează: suprafață de translație ș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 |}}+
  
 +Bonus: Completați fișierul ''​ShadowMappingPassTwo.FS''​ pentru a crea efectul de iluminare volumetrică. Rezultatul vizual ar trebui să fie similar cu cel din imaginea de mai jos:
 +{{ :​ppbg:​laboratoare:​volumetric-illumination.png?​600 |}}
  
ppbg/laboratoare/09.1702549273.txt.gz · Last modified: 2023/12/14 12:21 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