Differences

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

Link to this comparison view

ppbg:laboratoare:07 [2023/11/23 10:54]
andrei.lambru [Stocarea unor informații generice]
ppbg:laboratoare:07 [2024/11/30 21:58] (current)
andrei.lambru
Line 4: Line 4:
 **Reamintire!!!** Puteți prezenta rezolvările cerințelor de până la 2 laboratoare,​ în fiecare săptămână. De exemplu, puteți prezenta laboratorul curent și pe cel din săptămâna anterioară,​ în totalitate sau parțial, inclusiv punctajul pentru cerința bonus :) . **Reamintire!!!** Puteți prezenta rezolvările cerințelor de până la 2 laboratoare,​ în fiecare săptămână. De exemplu, puteți prezenta laboratorul curent și pe cel din săptămâna anterioară,​ în totalitate sau parțial, inclusiv punctajul pentru cerința bonus :) .
 </​note>​ </​note>​
 +
 +===== Modele de iluminare =====
 +
 +În laboratoarele anterioare, am analizat modalitatea prin care se poate desena pe ecran geometria unui model 3D. Până în acest moment, culorile atribuite pixelilor în care a fost discretizată suprafața geometriei au fost alese artificial prin diferite abordări, precum interpolarea între culorile vârfurilor. Deoarece ochiul uman „vede” doar lumină :) , culoarea unui pixel în care a fost discretizată o suprafață trebuie să se calculeze pe baza influenței unei surse de lumină asupra zonei din suprafață,​ reprezentată de pixel. Pentru acest proces, se introduce în procesul de desenare conceptul de //**sursă de lumină**//​. Există mai multe tipuri de astfel de surse:
 +  * Sursă de lumina **punctiformă**,​ ce are o poziție în spațiu și împrăștie lumină uniform în toate direcțiile în jurul poziției;
 +  * Sursă de lumină de **tip spot**, ce are o poziție în spațiu și împrăștie lumină de la această poziție de-a lungul unei singure direcții. Acest tip de sursă este similar cu o lanternă.
 +
 +Calcularea influenței iluminării ce provine de la o sursă de lumină, de orice tip, asupra unui punct de pe o suprafață,​ se realizează prin simularea procesului de transport al luminii de la poziția sursei, prin reflexie pe suprafață,​ în poziția punctului de pe suprafață,​ la poziția observatorului. O abordare care simulează acest proces de transport al luminii poartă numele de **model de iluminare** sau **model de reflexie**.
 +
 +În general, în majoritatea modelelor de iluminare, influența luminii asupra unui punct este împărțită în 4 componente:
 +  * Componenta emisivă, reprezentată de lumina care este emisă direct de către suprafață. Este vorba aici de suprafețe ce emit lumină, precum suprafața unui bec sau a ecranului unui televizor.
 +  * Componenta de reflexie indirectă a luminii, ce se referă la procesul de transport al luminii, de la o sursă, prin reflexia pe mai multe suprafețe, secvențial,​ la poziția observatorului.
 +  * Componenta de reflexie difuză, ce se referă la transportul luminii de la o sursă, prin reflexia pe //exact o singură suprafață//,​ într-un punct, la poziția observatorului.
 +  * Componenta de reflexie oglindă, ce se referă, similar cu cea de reflexie difuză, la transportul luminii de la o sursă, prin reflexia pe //o singură suprafață//,​ într-un punct, la poziția observatorului.
 +
 +Diferenta dintre ultimele două componente este dată de comportamentul de reflexie, respectiv o reflexie difuză și o reflexie oglindă.
 +
 +Deoarece lumina este aditivă, cu cât mai mulți fotoni ajung în ochii nostri, cu atât lumina este mai „puternică” :), rezultatul final al influenței iluminării într-un punct este dat de suma celor 4 componente:
 +
 +$$
 +iluminare = componentaEmisiva + componentaIndirecta + componentaDifuza + compoentaOglinda
 +$$
 +
 +==== Componenta emisivă ====
 +
 +În situația în care ne referim strict la transportul luminii de la suprafața sursei la poziția observatorului,​ această componenta se poate aproxima printr-o distribuire uniformă a împrăștierii luminii de la suprafață în toate direcțiile,​ astfel că poate fi utilizată o singură valoare uniformă pentru toată suprafața.
  
 <note tip> <note tip>
-Pentru rezolvarea cerințelor din cadrul acestui labroator:​ +În situația în care dorim să simulăm procesul de transport al luminii ​de la o suprafață ce emite luminăprin reflexie pe o altă suprafață, la poziția observatoruluiprocesul devine complexExistă abordări pentru simularea lui, dar în generalîn aplicații grafice în timp real se evită astfel ​de efecte vizuale.
-  - [[https://​github.com/​UPB-Graphics/​gfx-framework-ppbg | Descărcați]] framwork-ul ​de laborator și copiațidin arhiva descărcată, directorul **Lab7**în interiorul directorului //​gfx-framework-ppbg\src\lab//​ din versiunea voastră de proiect. +
-  - Adăugați ​în fișierul ''​lab_list.h''​linia ''#​include "​lab/​lab7/​lab7.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>​ </​note>​
  
-===== Obiecte de tip textură =====+==== Componenta indirectă a iluminării ​====
  
-Un obiect de tip textură reprezintă o secvență continuă de informație în interiorul memoriei RAM a procesorului graficÎn particular, în cadrul acestui laboratorne referim la obiecte ​de tip textură ce pastrează informație din interiorul unei grile de două dimensiuni.+În general, în aplicațiile grafice în timp real este precalculată și se evită utilizarea pentru un număr mare de obiecte dinamiceOdată cu apariția procesoarelor grafice ce au arhitecturi de ray-tracingse folosesc astfel ​de tehnici pentru simularea transportului luminii de la o sursăce ajunge prin reflexii multiple pe mai multe suprafețe, secvențial,​ la poziția observatorului.
  
-Într-o grilă ​de două dimensiuni, putem stoca informația unei imagini :) în care, în fiecare celulă, păstrăm informația unui pixel.+==== Componentele ​de reflexie directă ====
  
-<​note>​ +Acestea se referă la transportul luminii ​de la poziția unei surse, prin reflexie pe suprafață, la poziția observatoruluiPentru comoditate, se împarte acest tip de reflexie în două componente distincte:
-General, în API-ul grafic OpenGL, un obiect de tip textură poate fi de mai multe tipuri: +
-  * O grilă cu singură dimensiune. +
-  * O grilă de două dimensiuni. +
-  * O grilă de trei dimensiuni. +
-  * O textură cubică, ce păstrează informația a 6 grile de două dimensiuni. +
-  * Un set de grile cu o singură dimensiune. +
-  * Un set de grile de două dimensiuni. +
-  * ... +
-Pentru a vizualiza toate tipurile posibile, puteți consulta documentația oficialăhttps://​www.khronos.org/​opengl/​wiki/​Texture#​Theory. +
-</​note>​+
  
-===== Proiectarea texturilor =====+=== Componenta de reflexie difuză ​===
  
-Conținutul informației unei imagini se poate proiecta pe suprafața unui model 3D, respectiv pe suprafața triunghiurilor din care este compusă rețeaua de triunghiuri ce descrie modelul 3D, prin utilizarea unei informații suplimentare,​ în fiecare vârf, denumită **coordonată de textură**. O astfel de coordonată are două dimensiuni ​și fiecare componentă a ei, respectiv x și y, se află în intervalul [0,1]. Aceasta este coordonata în spațiul finit al grilei 2D stocate în obiectul de tip textură, spațiu delimitat ​în colțul din stânga-jos ​de coordonata (0, 0) și în colțul din dreapta-sus de coordonata (11). Un astfel de spațiu poate fi utilizat pentru a eșantiona valorile din grilă.+Această componentă se referă la cantitatea ​de lumină ce este împrăștiată uniform prin reflexie de pe o suprafață, în toate direcțiile din jurul punctului ​de pe suprafațădeasupra ei.
  
-Pentru a exemplifica,​ în partea stângă a imaginii de jos se poate observa un triunghi pentru care s-au asociat în vârfuri coordonate de textură: (0.7, 0.75), (0.1, 0.3) și (0.95, 0.2). Presupunem că prin procesul de rasterizare,​ s-a obținut un pixel ce se află în interiorul acestui triunghi și care a obținut prin interpolare de la vârfuri coordonata ​de textură (0.7, 0.55). Prin transformarea acestei coordonate în spațiul grilei 2D, obținem valoarea (716.8, 563.2).+=== Componenta ​de reflexie oglindă ===
  
-{{ :​ppbg:​laboratoare:​texture-mapping.png?600 |}}+Această componentă se referă la cantitatea de lumină ce este reflectată **de-a lungul direcției de reflexie simetrică față de direcția de incidență a luminii cu direcția vectorului normal**. Această componentă este cunoscută sub numele de ** componentă speculară**. Termenul //​speculum//​ în limba latină se traduce în limba română cu termenul de //​oglindă//​ :) .
  
-Avem mai multe posibilități pentru a eșantiona o valoare din informația celulelor din grila 2D.+==== Atenuarea intensității iluminării pe bază de distanță ====
  
-==== Eșantionare directă ====+În momentul în care o sursă de lumină se depărtează de un obiect, prin procesul de difuzie, cantitatea de lumină emisă de la sursă rămâne constantă, dar obiectul primește o cantitate mai mică de lumină. Simularea acestui fenomen se realizează prin scăderea intenstității iluminării pe baza distanței dintre poziția sursei de lumină ​și poziția pentru care se calculează iluminarea.
  
-Se eșantioneaza direct valoarea celulei de la coordonata în spațiul grilei 2D, cu valoarea fiecărei componente a coordonatei rotunjită în jos. Astfel, pentru exemplul de sus, unde coordonata de texturare este (716.8, 563.2), se eșantionează valoarea celulei (716, 563).+===== Laborator =====
  
-==== Eșantionare liniară ====+În practică, inclusiv în cadrul acestui laborator, se utilizează metode ce simulează fenomenele optice menționate mai sus.
  
-O altă variantă utilizează o eșantionare a informației prin interpolare liniară de la toate celulele din jurul coordonatei,​ respectiv:+==== Componenta emisivă ====
  
-<​code ​cpp+<​code ​glsl>  
-glm::vec3 c1 glm::​vec3(716,​ 563)+vec3 emissive_component ​Ke# GLSL 
-glm::vec3 c2 = glm::​vec3(716,​ 564); +</​code>​ 
-glm::vec3 c3 = glm::​vec3(717,​ 563); +<note tip> 
-glm::vec3 c4 = glm::​vec3(717,​ 564);+  * Ke – culoarea emisivă a obiectului 
 +</​note>​
  
-glm::vec3 c12 glm::​mix(c1,​ c2, 0.8); // din partea fractionara a componentei x, 716.8 +==== Componenta indirectă ​iluminării ====
-glm::vec3 c34 glm::​mix(c3,​ c4, 0.8); // din partea fractionara ​componentei x, 716.8+
  
-glm::vec3 c1234 = glm::​mix(c12,​ c34, 0.2) // din partea fractionara ​componentei y563.2+Este cunoscută în domeniul graficii pe calculator sub numele de **componentă ambientală**Pentru ​nu calcula tot transportul luminii cu toate reflexiile de pe suprafețese consideră că influența indirectă a iluminării este **aceeași în toate punctele din scenă**Această aproximare obține rezultate satisfăcătoare pentru o parte din scenarii. 
 + 
 +Avem astfel: 
 + 
 +<code glsl> 
 +vec3 ambient_component = Ka * global_ambient_color;​ # GLSL
 </​code>​ </​code>​
  
 <note tip> <note tip>
-glm::mix(a, b, t) reprezintă interpolare liniară:+  * Ka – culoarea de reflexie ambientală ​obiectului 
 +  * global_ambient_color – culoarea ambientală a tuturor luminilor 
 +</​note>​ 
 + 
 +==== Componenta difuză ==== 
 + 
 +În imaginea de mai jos se poate observa că un fascicul de lumină ce are o lățime de dimensiune $A$ este proiectat pe o suprafațăde-a lungul unei zone de dimensiune $B$. Se poate observa că în situația în care fasciculul este proiectat vertical pe suprafață, $B = A$. 
 + 
 +{{ :​ppbg:​laboratoare:lambert-cosine-law.png?​500 |}}
  
 +Notăm cu $\alpha$ unghiul dintre vectorul $\vec{L}$, ce reprezintă direcția de la poziția punctului spre poziția sursei de lumină și vectorul normal, $\vec{N}$. Deoarece unghiul făcut de vectorul normal cu suprafața este 90 de grade, unghiul făcut de vectorul $\vec{L}$ cu suprafața este de $90-\alpha$. Pentru că suma unghiurilor unui triunghi este de 180 de grade și triunghiul din imagine este dreptunghic,​ rezultă că cel de-al treilea unghi din triunghi are dimensiunea $\alpha$. Astfel, rezultă că:
  
  
 $$ $$
-mix(a, b, t) = (1-t) \cdot a + t \cdot b+cos(\alpha)=\frac{A}{B} ​\
 +B=\frac{A}{cos(\alpha)}
 $$ $$
  
  
 +Din acest motiv, se poate deduce că intensitatea de iluminare pentru orice punct de pe suprafață este $cos(\alpha)$. În situația în care $\alpha$ este de 0 grade, intensitatea de iluminare este $cos(0)=1$. Această abordare poartă numele de **legea cosinusului a lui Lambert**, propusă de Johann Heinrich Lambert în anul 1760.
  
-</​note>​+În domeniul graficii pe calculator, această lege a cosinusului este utilizată pentru calculul componentei difuze a iluminării,​ ce se referă la lumina împrăștiată uniform în toate directiile. Mai exact, se consideră că lumina se împrăștie uniform în toate direcțiile cu intensitatea de iluminare dată de legea cosinusului a lui Lambert.
  
-<note tip> +În practicăîn loc de cosinus, se utilizează produsul scalar dintre $\vec{L}$ și $\vec{N}$, cu ambii vectori ​de lungime 1Reamintim faptul că interpretarea geometrică a produsului scalar este:
-Acest proces este regăsit în limba engleză sub numele ​de **bilinear interpolation**. +
-</​note>​+
  
-==== Piramida "​Mipmap"​ ====+$$ 
 +\vec{V_1}\cdot\vec{V_2}=\lVert\vec{V_1}\rVert\lVert\vec{V_2}\lVert\cos(\angle(\vec{V_1},​\vec{V_2})) 
 +$$
  
-Conceptul de piramidă "​mipmap"​ a fost propus de Lance Williams în anul 1983 și constă în stocarea unei "​piramide"​ de versiuni de diferite rezoluții ale unei imagini. Un astfel de exemplu se poate observa în imaginea de mai jos, în care în aceeași grilă, în partea stângă este stocată imaginea la rezoluția inițială, iar în partea dreaptă ​sunt stocate versiunile imaginii inițiale la rezoluție ​de 24, 8, până la 128 de ori mai mică.+În situația în care vectorii $\vec{V_1}$ ​și $\vec{V_2}$ ​sunt amândoi ​de lungime 1expresia ​de mai sus este echivalentă cu:
  
-{{ :​ppbg:​laboratoare:​mipmap.jpg?​300 |}}+ 
 + 
 +$$ 
 +\vec{V_1}\cdot\vec{V_2}=cos(\angle(\vec{V_1},​\vec{V_2})) 
 +$$
  
 <note tip> <note tip>
-Termenul ​de "​mipmap"​ provine ​de la primele litere ale cuvintelor din fraza în limba latină //multum in parvo//mip, ceea ce în limba română se traduce prin //mult în puțin// și de la termenul de "​map"​ din limba englezăceea ce în limba română se traduce prin hartă.+Pentru a obține un vector $\vec{V_u}$, ​de lungime 1, cunoscut sub numele ​de **vector unitate**pe direcția și în sensul dat de un vector $\vec{V}$putem aplica ​în limbajul GLSL: 
 +<code glsl> 
 +vec3 Vu = normalize(V);​ 
 +</​code>​
 </​note>​ </​note>​
  
-Această piramidă este utilă în momentul în care este dorită o eșantionare într-o vecinatate mai mare de 2x2. Situația aceasta apare în momentul în care prin procesul de interpolaredoi pixeli vecini obținuti prin rasterizare au atribuite coordonate de texturare ce in grila 2D se află la distanță mai mare de o celulă. De exemplu, dacă doi pixeli vecini se află la distanță de 50 de celule în grila 2D, putem considera că dimensiunea pixelului, în spațiul grilei 2D este de 50 de celule. Astfel, putem utiliza versiunile imaginii ce au rezoluția cea mai apropiată de dimensiunea pixelului. Pentru imaginea de mai sus, aceste versiuni au rezoluție de 64x64 și 32x32. Pentru eșantionare,​ avem două opțiuni.+Astfelcalculul componentei difuze a iluminării este:
  
-=== Eșantionare directă ===+$$ 
 +componentaDifuza ​K_d \cdot culoareLumina \cdot max(\vec{N}\cdot \vec{L}, 0) 
 +$$
  
-Se eșantionează direct sau liniar DOAR versiunea imaginii ce are rezoluția cea mai apropiată. Pentru exemplul ​de mai susse alege versiunea imaginii de rezoluție 64x64.+În limbajul GLSL, expresia ​de mai sus se transcrie sub forma:
  
-=== Eșantionare liniară === +<code glsl> 
- +vec3 diffuse_component ​Kd * culoareLumina * max (dot(N,L), 0); # GLSL 
-Se eșantionează direct sau liniar cele două versiuni ale imaginii ce au rezoluția cea mai apropiată și se interpolează liniar între cele două valori obținute din eșantionarea celor două versiuni.+</​code>​
  
 <note tip> <note tip>
-Procesul ​de eșantionarecu toate opțiunile menționate ​mai suseste implementat hardware ​în interiorul procesorului grafic.+  * Kd - culoarea ​de reflexie difuză a obiectului 
 +  * culoareLumina – culoarea luminii 
 +  * $\vec{N}$ – vector normal (normalizat)  
 +  * $\vec{L}$ – vectorul direcției luminii incidente (normalizat) 
 +  * $max(\vec{N}\cdot \vec{L}, 0)$ – produsul scalar $\vec{N}\cdot \vec{L}$ reprezintă măsura unghiului dintre acești 2 vectori; astfeldacă $\alpha$ este mai mare decât $\pi/2$valoarea produsului scalar va fi mai mică decât 0, acest lucru însemnând că suprafața nu primește lumină ( sursa de lumină se află în spatele suprafeței ) și de aici și formula care asigură că în acest caz suprafața nu primește lumină difuză
 </​note>​ </​note>​
  
-===== Gestionarea obiectelor de tip textură în API-ul grafic OpenGL =====+{{ :​egc:​laboratoare:​lab07:​difuză.jpg?300 |}}
  
-==== Crearea unui obiect de tip textură ====+==== Componenta speculară ====
  
-Pentru ​gestionarea unui obiect ​de tip textură ​în API-ul grafic OpenGL, trebuie creat un astfel de obiect:+Pentru ​calcularea componentei speculare, vom folosi modelul propus ​de Bui Tuong Phong în anul 1973:
  
-<code cpp> 
-unsigned int texture_id; 
  
-glGenTextures(1&​texture_id); +$$ 
-</​code>​+componentaSpeculara = K_s \cdot culoareLumina \cdot primesteLumina \cdot (max(\vec{V}\cdot \vec{R}0))^n 
 +$$
  
-Pentru a modifica informațiile stocate ​de obiectul de tip textură sau pentru a utiliza obiectul, el trebuie legat:+În limbajul GLSL, expresia ​de mai sus se transcrie sub forma:
  
-<​code ​cpp+<​code ​glsl
-glBindTexture(GL_TEXTURE_2Dtexture_id);+vec3 specular_component = Ks * culoareLumina * primesteLumina * pow(max(dot(V, R), 0)n# GLSL
 </​code>​ </​code>​
  
-Pentru ​asocia informație ​obiectului de tip textură, se utilizează:+<note tip> 
 +  * Ks - culoarea speculară de reflexie ​a obiectului 
 +  * $\vec{V}$ – vectorul direcției ​de vizualizare (normalizat) 
 +  * $\vec{R}$ – vectorul direcției luminii reflectate (normalizat) 
 +  * n – coeficientul de strălucire (shininess) a materialului 
 +  * primesteLumina – 1 dacă $\vec{N}\cdot \vec{L}$ este mai mare decât 0; sau 0 în caz contrar 
 +</​note>​
  
-<​code ​cpp+{{ :​egc:​laboratoare:​lab07:​specular.jpg?​300 |}} 
-glTexImage2D(GL_TEXTURE_2D,​ 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTEdata);+ 
 +Componenta speculară reprezintă lumina reflectată de suprafața obiectului numai în jurul direcției $\vec{R}$. Acest vector se obține prin: 
 + 
 +<​code ​glsl
 +vec3 R = reflect ​(-LN# GLSL
 </​code>​ </​code>​
  
 <note tip> <note tip>
-Directiva de mai sus este complexă și suportă foarte mulți parametri. Pentru ​mai multe detalii, puteți consulta documentația oficială: https://​registry.khronos.org/​OpenGL-Refpages/​gl4/​html/​glTexImage2D.xhtml.+  * Este necesar să se utilizeze -L, deoarece ''​reflect()''​ are primul parametru vectorul incident, care intră în suprafață, nu cel care iese din ea așa cum este reprezentat în imaginea de mai sus.
 </​note>​ </​note>​
  
-<note important>​ +În modelul Phongse aproximează scăderea rapidă a intensității luminii reflectate atunci când $\alpha$ crește prin $(cos \alpha)^n$, unde $n$ este exponentul de reflexie speculară al materialului (shininess).
-Directiva ''​glTexImage2D()''​ asociază primele celule din memorie cu linia din partea de **jos** a grilei 2D. Din acest motivputem considera că API-ul grafic OpenGL încarcă informația în memorie în formă rasturnată pentru componenta y. +
-</​note>​+
  
-Suplimentar, se pot specifica parametri ​pentru ​diferite procese în care este implicat obiectul de tip textură.+După cum se observăfață de celelalte 3 componente, componenta speculară depinde și de poziția observatorului. Dacă observatorul nu se află într-o poziție unde poate vedea razele reflectate, atunci nu va vedea reflexie speculară ​pentru ​zona respectivă. De asemenea, nu va vedea reflexie speculară dacă lumina se află în spatele suprafeței.
  
-Pentru procesul de eșantionare,​ se pot specifica parametrii:+==== Atenuarea intensității iluminarii ====
  
-<​code ​cpp+Factorul de atenuare a intensității iluminării pe bază de distanță se aplică doar componentei difuze și speculare:  
-glTexParameteri(GL_TEXTURE_2D,​ GL_TEXTURE_MIN_FILTER,​ GL_NEAREST);​ + 
-glTexParameteri(GL_TEXTURE_2D,​ GL_TEXTURE_MAG_FILTER,​ GL_LINEAR);+<​code ​glsl
 +vec3 illumination = emissive_component + ambient_component 
 +                    + attenuation_factor * diffuse_component + specular_component); # GLSL
 </​code>​ </​code>​
  
 <note tip> <note tip>
-Procesul de eșantionare ​este cunoscut sub numele ​de **filtrare**.+  * attenuation_factor = $1/​(d^2+1)$ ​este o funcție ​de atenuare 
 +  ​$d$ este distanța de la poziția sursei de lumină la poziția punctului de pe suprafață pentru care se calculează iluminarea 
 +</​note>  ​
  
-Pentru parametrul ​de filtrare în situația în care doi pixeli vecini obținuti prin rasterizare au coordonate de textură la distanță mai mare de o celulă din grila 2D, prin parametrul ''​GL_TEXTURE_MIN_FILTER''​ se poate specifica:​ +==== Sursa de lumină de tip spot ====
-  * ''​GL_NEAREST''​ - eșantionare directă doar din imaginea inițială. +
-  * ''​GL_LINEAR''​ - eșantionare liniară doar din imaginea inițială. +
-  * ''​GL_NEAREST_MIPMAP_NEAREST'':​ eșantionare directă din versiunea imaginii inițiale ce are rezoluția cea mai apropiată de dimensiunea pixelului în spațiul grilei 2D. +
-  * ''​GL_LINEAR_MIPMAP_NEAREST'':​ eșantionare liniară din versiunea imaginii inițiale ce are rezoluția cea mai apropiata de dimensiunea pixelului în spațiul grilei 2D. +
-  * ''​GL_NEAREST_MIPMAP_LINEAR'':​ interpolare liniară între valorile obținute prin eșantionare directă a versiunilor imaginii inițiale ce au rezoluțiile cele mai apropiate de dimensiunea pixelului în spațiul grilei 2D. +
-  * ''​GL_LINEAR_MIPMAP_LINEAR'':​ interpolare liniară între valorile obținute prin eșantionare liniară a versiunilor imaginii inițiale ce au rezoluțiile cele mai apropiate ​de dimensiunea pixelului în spațiul grilei 2D.+
  
-Pentru ​parametrul ​de filtrare în situația în care doi pixeli vecini obținuti prin rasterizare au coordonate ​de textură la distanța mai mică de o celulă din grila 2D, prin parametrul ''​GL_TEXTURE_MAG_FILTER''​ se poate specifica: +Pentru ​a simula o sursă ​de lumină precum o lanternă, ce împrăștie lumină de-a lungul unei direcții de iluminare, se introduc câteva informații suplimentare:​ 
-  * ''​GL_NEAREST''​ - eșantionare directă doar din imaginea inițială. +  * Vectorul ​de direcție iluminării sursei ​de lumină 
-  * ''​GL_LINEAR''​ - eșantionare liniară doar din imaginea inițială.+  * Unghiul de tăiere a iluminării,​ ce controlează deschiderea conului de lumină 
 +  * Un model de atenuare a intensității iluminări pe baza unghiului de tăiere
  
-Pentru mai multe detalii în legatură cu parametrii ce pot fi specificați,​ puteți consulta documentația oficialăhttps://​registry.khronos.org/​OpenGL-Refpages/​gl4/​html/​glTexParameter.xhtml. +{{ :ppbg:laboratoare:​spot-light.png?600 |}}
-</​note>​+
  
-Pentru a genera piramida "​mipmap"​ se utilizează:+În domeniul graficii pe calculator, o astfel de sursă de lumină poartă numele de **sursă de tip spot**.
  
-<​code ​cpp+Un punct se află în conul de lumină al unei surse de tip spot dacă condiția următoare este îndepilită:​ 
-glGenerateMipmap(GL_TEXTURE_2D);+<​code ​glsl
 +float cos_theta_angle = dot(-L, light_direction); 
 +float cos_phi_angle = cos(phi_angle);​ 
 + 
 +if (cos_theta_angle > cos_phi_angle ) 
 +
 + // fragmentul este iluminat, astfel ca se calculeaza valoarea luminii conform modelului Phong 
 + // se calculeaza atenuarea luminii 
 +}
 </​code>​ </​code>​
  
-==== Unitatea ​de texturare ====+Pentru a simula corect iluminarea ​de tip spot, este nevoie să tratăm și atenuarea iluminării corespunzătoare apropierii unghiului de tăiere. Putem astfel să utilizăm un model de atenuare pătratică ce oferă un rezultat convingător.
  
-Procesul de esantionare este realizat de o entitate autonoma implementata hardware sub forma unui procesor in interiorul procesorului grafic sau software in driver-ul companion procesorului. Aceasta entitate autonoma este numita **unitate de texturare** si numarul lor este in general limitat la 32.+<code glsl> 
 +float spot_linear_att_factor = (cos_theta_angle ​cos_phi_angle) / (1.0f - cos_phi_angle);​ 
 +float quadratic_spot_light_att_factor = pow(spot_linear_att_factor,​ 2); 
 +</​code>​
  
-Pentru a utiliza procesul de esantionare,​ trebuie sa asociem obiectul de tip textura pe care dorim sa il esantionam cu o unitate de texturare, numerotat cu identificatori de la 0 la 31 si sa transmitem la un program de tip shader numarul unitatii de texturare:+==== Biblioteca GLM ====
  
-<code cpp> +=== Matrici de transformare ===
-glActiveTexture(GL_TEXTURE0);​+
  
-glBindTexture(GL_TEXTURE_2Dtexture_id);​+Biblioteca GLM ne pune la dispoziție metode de construcție a matricilor celor 3 tipuri de transformări analizate: translațiemodificare de scară și rotație. Următoarele 2 lanțuri de transformări sunt identice:
  
-glUniform1i(glGetUniformLocation(shader->program"​texture_unit"​), 0);+<code cpp> 
 +glm::mat4 model = glm::mat4(1); 
 +model = glm::​translate(model,​ glm::vec3(-51.5f, 1)); 
 +model = glm::​rotate(modelglm::​radians(60.0f),​ glm::vec3(0, 1, 0)); 
 +model = glm::​scale(model,​ glm::​vec3(0.1f));
 </​code>​ </​code>​
  
-Pentru a utiliza unitatea de texturare, putem folosi intr-un program de tip shader ''​texture()'':​ 
  
-<​code ​glsl+<​code ​cpp
-#version 330 +glm::mat4 model = glm::​mat4(1);​ 
-  +model *= transform3D::​Translate(glm::​vec3(-5,​ 1.5f, 1)); 
-uniform sampler2D texture_unit+model *= transform3D::​RotateOY(glm::​radians(60.0f))
-  +model *= trasnform3D::​Scale(glm::​vec3(0.1f)); 
-in vec2 texture_coord;+</​code>​
  
-layout(location ​0) out vec4 out_color;+=== Aplicarea matricilor de transformare ===
  
-void main() +Dacă dorim să rotim un vector cu 30 de grade față de axa OYputem utiliza construcția matricii pentru transformarea de rotație, pusă la dispoziție de biblioteca glm, după cum urmează:
-+
- vec4 color = texture(texture_unittexture_coord);​ +
- out_color = color; +
-+
-</​code>​+
  
-===== Stocarea unor informații generice =====+<code cpp> 
 +glm::vec3 v glm::​vec3(1,​ 0, 0);
  
-În interiorul memoriei stocate de un obiect de tip texturăse pot păstra informații generice.+glm::mat4 rotation = glm::​rotate(glm::​mat4(1)glm::​radians(30.0f), glm::​vec3(0,​ 1, 0));
  
-Un prim exemplu este reprezentat de situația în care într-o grilă 2D se poate păstra informație de culoare în componentele rgb și o informație binară în componenta alpha. Această ultimă informație se poate interpreta astfel încâtpentru un pixel prelucrat de un program de tip fragment shader, pentru care pe baza coordonatelor de textură se eșantionează valoarea ​1, i se asociază pixelului culoarea dată de atributul de ieșire a programului de tip fragment shader, iar unui pixel pentru care se eșantionează valoarea 0 nu i se asociază culoarea dată de atributul de ieșire. Un astfel de exemplu este în imaginea de mai jos, unde în partea stângă se prezintă doar valoarea componentei alpha.+// First option 
 +v = glm::​mat3(rotation) * v; 
 + 
 +// Second option 
 +v = glm::​vec3(rotation * glm::vec4(v, 1.0f)); 
 +</​code>​
  
-{{ egc:​laboratoare:​lab9texturephoto5.png?​600 |}}+=== Transmiterea de vectori în atribute de tip uniform ===
  
-Pentru a nu asocia pixelului culoarea ​de la atributul ​de ieșire a programului ​de tip fragment ​shader, se poate folosi directiva ''​discard''​:+Pentru a transmite un vector ​de obiecte ce au tipuri ​de date din biblioteca GLM într-un atribut ​de tip uniform, la un shader, se poate utiliza:
  
 <code cpp> <code cpp>
-vec4 color = texture2D(texture_unit,​ texture_coord);+glm::vec3 light_positions[10];
  
-if(color.a < 0.5+glUniform3fv(location, 10, glm::​value_ptr(light_positions[0]));
-    discard; +
-}+
 </​code>​ </​code>​
  
-Directiva ''​discard''​ oprește programul ​de tip fragment shader ​la momentul apelului ei.+==== Detalii de implementare ==== 
 + 
 +  * În acest laborator, nu se va utiliza componenta emisivă. 
 +  * Vectorul normal al fiecărui vârf se regăsește în datele conținute ​de fișierul modelului încărcat și se primește în vertex shader într-un atribut de intrare spefic vârfului: <code glsl>​layout(location = 1) in vec3 v_normal;</​code>​ 
 +  * Calculele de iluminare se vor face în spațiul lumii, astfel că poziția și vectorul normal vor trebui transformate din spațiul obiectului, în care se află inițial, în spațiul lumii. Aceste calcule se realizează în vertex shader și noua poziție și vector normal se transmit spre fragment shader. ​Calculul se poate face astfel: 
 +    * pentru poziție: <code glsl>​vec3 world_position = (model_matrix * vec4(v_position,​1)).xyz;</​code>​ 
 +    * pentru vectorul normal: <code glsl>​vec3 world_normal = normalize( mat3(model_matrix) * v_normal );</​code>​ 
 +  * Vectorul normal trebuie normalizat în fragment shader, deoarece după procesul de interpolare,​ lungimea lui nu se pastrează: <code glsl>​vec3 N = normalize( world_normal );</​code>​ 
 +  * Vectorul direcției luminii L: <code glsl>​vec3 L = normalize( light_position - world_position );</​code>​ 
 +  * Vectorul direcției din care privește observatorul V: <code glsl>​vec3 V = normalize( eye_position - world_position );</​code>​
  
 <note tip> <note tip>
-În codul de mai sus, s-a folosit directiva ''​discard''​ pentru valori ale componentei alpha mai mici decât valoarea 0.5 pentru ​se ține cont de posibilitatea utilizării unui proces de eșantionare liniară, ce se aplică și pentru componenta alpha.+Funcții GLSL utile care pot fi utilizate pentru implementarea modelului ​de iluminare 
 +  * normalize(V) – normalizează vectorul V  
 +  * normalize(V1+V2) – normalizează vectorul obținut prin V1+V2  
 +  * normalize(P1-P2) - returnează un vector de direcție normalizat între punctele P1 și P2 
 +  * dot(V1,V2) – calculează produsul scalar dintre V1 și V2 
 +  * pow(a, shininess) – calculează ​la puterea shininess 
 +  * max(a,b) – returnează maximul dintre a și b 
 +  * distance(P1,​P2) – returnează distanța euclidiană dintre punctele P1 și P2  
 +  * reflect(V,N) - calculează vectorul de reflexie pornind de la incidenta V și normala N
 </​note>​ </​note>​
- 
-Un alt exemplu de aplicare a utilizării obitectelor de tip textură pentru a stoca informații generice este utilizarea unei grile 2D pentru a păstra un deplasament în spațiul obiectului. Astfel, la desenarea unui plan, se poate modifica componenta y a coordonatei fiecărui vârf pe baza informației din grila 2D, proiectată pe toată suprafața planului. Un exemplu de imagine ce păstrează o astfel de informație se poate vedea mai jos: 
- 
-{{ ppbg:​laboratoare:​heightmap.png?​200 | }} 
- 
-Rezultatul deformării unui plan pe baza imaginii de mai sus este: 
- 
-{{ ppbg:​laboratoare:​terrain.png?​600 | }} 
  
 ===== Cerințe laborator ===== ===== Cerințe laborator =====
  
-  - 0.1p - Utilizați obiecte de tip textură pentru desenarea geometriei: +<​note ​tip> 
-    Completațmetoda ''​CreateTexture()''​ pentru a crea un obiect de tip textură. +Prin apăsarea tastelor **W**, **A**, **S**, **D**, **E** și **Q**, puteți controla poziția unei surse de lumină. Prin apăsarea tastei ​**F**, puteți interschimba între controlul ​două surse de lumină diferiteuna punctiformă și cealaltă de tip spot
-    ​Completați metoda ''​RenderSimpleMesh()''​ pentru a asocia o unitate ​de texturare fiecărei din cele 2 obiecte de tip textură și pentru a transmite la programul de tip shader numerele unităților de texturare asociate. +</note>
-    ​Completati in fisierul ''​LabShader.VS.glsl''​ calcularea valorii atributului de iesire pentru coordonata de textura. +
-    ​Completati in fisierul ''​LabShader.FS.glsl''​ esantionarea informatiei dintr-un singur obiect de tip textura. +
-    ​Utilizati directiva ''​discard''​ pentru a opri programele de tip fragment shader pe baza valorii componentei alpha esantionate. +
-    ​In metoda ''​Init()''​specificati coordonatele de textura ale varfurilor unui patrulater. Aveti in vedere ca directiva ''​glTexImage2D()''​ considera ca prima linie de pixeli ​unei imagini incepe din partea din stanga-jos, astfel ca este necesara inversarea componentei y a coordonatelor ​de textura. +
-    * Până în acest punctrezultatul pe care ar trebui să îl obțineti este următorul:  +
-{{ ppbg:​laboratoare:​textures.png?​600 | }} +
-  - 0.05p - Completati metoda ''​CreateStrippedTexture()''​ pentru a crea continutul unei grile 2D ce contine o culoare RGB in fiecare celula. Grila 3D trebuie sa contina acelasi triplet (R, G, B) in toate celulele ce se afla pe aceeasi linie. Altfel spus, toate valorile de culoare de pe o linie sunt identice. Culoarea celulelor unei linii este aleasa aleator. Un exemplu de rezultat posibil este: +
-  - 0.05p - Creati un alt program ​de tip shader in care sa esantionati informatia din doua obiecte de tip textura+
-    - Utilizati acest program de tip shader pentru desenarea cubului din dreapta. +
-    - Culoarea pixelului obtinut prin rasterizare se calculeaza prin interpolare liniara: <code glsl>​vec3 color = mix(color1, color2, 0.5f);</code> +
-  - 0.05p - Creati un alt program de tip shader in care sa creati un efect de rotatie a globului pamantesc doar prin modificarea coordonatelor de textura: +
-    - Utilizati acest program de tip shader pentru desenarea sferei. +
-    - Utilizati timpul aplicatiei ''​Engine::​GetElapsedTime()''​. +
-  - 0.05p - Creati un alt program de tip shader in care sa modificati coordonatele varfurilor pe baza unei harti de inaltimi: +
-    - Utilizati acest program de tip shader pentru desenarea planului din departare. +
-    - Aveti in vedere faptul ca valorile coordonatelor in spatiul obiect, ale varfurilor modelului de plan sunt in intervalul [-25, 25]. Esantionarea se realizeaza in spatiul [0, 1]. Rezultatul obtinut este cel de la sectiunea Stocarea unor informatii generice, de mai sus. +
- +
-Bonus: Utilizati imaginile ''​lab7/​images/​snow.png''​ si ''​lab7/​images/​water.png'',​ impreuna cu valoarea de inaltime a fiecarui pixel, pentru a obtine rezultatul de mai jos. Observati ca trecerea de la zona de apa la cea de pamant este graduala. Acelasi lucru este valabil si pentru trecerea de la zona de pamant la cea de zapada :) .+
  
-{{ ppbg:​laboratoare:​terrain2.png?600 | }}+  - 0.05p - Trimiteți toate informațiile,​ necesare calculării iluminării,​ în atribute de tip uniform. 
 +  - 0.15p - Implementați calculul de iluminare în fișierele sursă ale programelor de tip shader: 
 +    * Completați în fișierul ''​VertexShader.glsl''​ calculul poziției vârfului și a vectorului normal în spațiul lumii și transmiteți-le spre fragment shader. 
 +    * Completați în fișierul ''​FragmentShader.glsl'':​ 
 +      * Calculul componentei difuze și speculare a iluminării unei surse de lumină 
 +      * Calculul factorului de atenuare a iluminării pe bază de distanță 
 +      * Calculul final de obținere a iluminării prin combinarea componentei difuze și speculare, a factorului de atenuare și a culorii iluminării 
 +      * Calculul componentei ambientale a iluminării globale 
 +      * Până în acest punct, rezultatul pe care ar trebui să îl obțineti este următorul. Culoarea fiecărei lumini este aleasă aleatoriu la începutul fiecărei execuții a aplicatiei grafice ​{{ :ppbg:​laboratoare:​illumination.png?600 |}} 
 +  - 0.05p - Implementați calculul de iluminare pentru sursele de lumină de tip spot: 
 +    * Completati în fisierul ''​FragmentShader.glsl'':​ 
 +      * Calculul factorului de atenuare specific unei surse de lumină de tip spot 
 +      * Calculul final de obținere a iluminării prin combinarea componentei difuze și speculare, a factorului de atenuare pe bază de distanță, a factorului de atenuare specific unei surse de lumină de tip spot și a culorii iluminării 
 +  - 0.05p - Pentru sursa de lumină de tip spot ce poate fi controlată de la tastatură, prin apăsarea unor taste, modificați direcția de iluminare și unghiul. Direcția de iluminare trebuie să se poata roti față de axa OX și OZ, în ambele sensuri, iar unghiul trebuie să se poată mări și micșora.
ppbg/laboratoare/07.1700729689.txt.gz · Last modified: 2023/11/23 10:54 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