This is an old revision of the document!


Laboratorul 06

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 :) .

Pentru rezolvarea cerințelor din cadrul acestui labroator:

  1. Descărcați framwork-ul de laborator și copiați, din arhiva descărcată, directorul Lab6, în interiorul directorului gfx-framework-ppbg\src\lab din versiunea voastră de proiect.
  2. Adăugați în fișierul lab_list.h, linia #include “lab/lab6/lab6.h”.
  3. 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 pagina dedicată acestui lucru.

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-alungul 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.

Î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 observatorului, procesul devine complex. Există abordări pentru simularea lui, dar în general, în aplicații grafice în timp real se evită astfel de efecte vizuale.

Componenta indirectă a iluminării

În general, în aplicațiile grafice în timp real este precalculată și se evită utilizarea pentru un numar mare de obiecte dinamice. Odată cu apariția procesoarelor grafice ce au arhitecturi de ray-tracing, se 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.

Componentele de reflexie directă

Acestea se referă la transportul luminii de la poziția unei surse, prin reflexie pe o suprafață, la poziția observatorului. Pentru comoditate, se împarte acest tip de reflexie în două componente distincte:

Componenta de reflexie difuză

Această componentă se referă la cantitatea de lumină ce este impraștiată uniform prin reflexie de pe o suprafață, în toate direcțiile din jurul punctului de pe suprafață, deasupra ei.

Componenta de reflexie oglindă

Această componentă se referă la cantitatea de lumină ce este reflectată de-alungul 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 componenta speculară. Termenul speculum în limba latină se traduce în limba română cu termenul de oglindă :) .

Atenuarea intensității iluminării pe bază de distanță

În momentul în care o sursă de lumină se depărteaza 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.

Laborator

În practică, inclusiv în cadrul acestui laborator, se utilizează metode ce simulează fenomenele optice menționate mai sus.

Componenta emisivă

vec3 emissive_component = Ke; # GLSL

  • Ke – culoarea emisivă a obiectului

Componenta indirectă a iluminării

Este cunoscută în domeniul graficii pe calculator sub numele de componentă ambientală. Pentru a nu calcula tot transportul luminii cu toate reflexiile de pe suprafețe, se 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:

vec3 ambient_component = Ka * global_ambient_color; # GLSL

  • Ka – culoarea de reflexie ambientală a obiectului
  • global_ambient_color – culoarea ambientală a tuturor luminilor

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-alungul unei zone de dimensiune $B$. Se poate observa că în situația în care fasciculul este proiectat vertical pe suprafață, $B = A$.

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 cu vectorul normal este 90 de grade, unghiul față de vectorul $\vec{L}$, realizat 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ă:

$$ 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.

Î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.

În practică, în loc de cosinus, se utilizează produsul scalar dintre $\vec{L}$ și $\vec{N}$, cu ambii vectori de lungime 1. Interpretarea geometrică a produsului scalar este:

$$ \vec{V_1}\cdot\vec{V_2}=\frac{cos(\angle(\vec{V_1},\vec{V_2}))}{\lVert\vec{V_1}\rVert\lVert\vec{V_2}\lVert} $$

În situația în care vectorii $\vec{V_1}$ și $\vec{V_2}$ sunt amândoi de lungime 1, expresia de mai sus este echivalentă cu:

$$ \vec{V_1}\cdot\vec{V_2}=cos(\angle(\vec{V_1},\vec{V_2})) $$

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:

vec3 Vu = normalize(V);

Astfel, calculul componentei difuze a iluminării este:

$$ componentaDifuza = K_d \cdot culoareLumina \cdot max(\vec{N}\cdot \vec{L}, 0) $$

În limbajul GLSL, expresia de mai sus se transcrie sub forma:

vec3 diffuse_component = Kd * culoareLumina * max (dot(N,L), 0); # GLSL

  • 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; astfel, dacă $\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ă

Componenta speculară

Pentru calcularea componentei speculare, vom folosi modelul propus de Bui Tuong Phong in 1973:

$$ componentaSpeculara = K_s \cdot culoareLumina \cdot primesteLumina \cdot (max(\vec{V}\cdot \vec{R}, 0))^n $$

În limbajul GLSL, expresia de mai sus se transcrie sub forma:

vec3 specular_component = Ks * culoareLumina * primesteLumina * pow(max(dot(V, R), 0), n) # GLSL

  • 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) al materialului
  • primesteLumina – 1 dacă $\vec{N}\cdot \vec{L}$ este mai mare decât 0; sau 0 în caz contrar

Componenta speculară reprezintă lumina reflectată de suprafața obiectului numai în jurul acestei direcții, $\vec{R}$. Acest vector se obține prin:

vec3 R = reflect (-L, N) # GLSL

  • 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 figură

În modelul Phong, se 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).

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.

Atenuarea intensității iluminarii

Factorul de atenuare a intensității iluminării pe bază de distanță se aplică doar componentei difuze și speculare:

vec3 illumination = emissive_component + ambient_component
                    + attenuation_factor * ( diffuse_component + specular_component); # GLSL

  • attenuation_factor = $1/(d^2+1)$ este o funcție de atenuare
  • $d$ este distanța de la pozitia sursei de lumina la pozitia punctului de pe suprafață pentru care se calculeaza iluminarea

Surse de lumină de tip spot

Pentru a simula surse de lumina precum lanternele, ce imprastie lumina intr-o singura directie de iluminare, se poate utiliza orice model de reflexie. Singurele diferente fata de o sursa de lumina punctiforma este ca se introduce un factor de atenuare suplimentar si faptul ca sursa de lumina contine informatii suplimentare fata de o sursa de lumina punctiforma:

Nu toate sursele de lumina sunt punctiforme. Daca dorim sa implementam iluminarea folosind o sursa de lumina de tip spot trebuie sa tinem cont de o serie de constrangeri

Așa cum se poate vedea și în imaginea de mai sus, pentru a implementa o sursă de lumină de tip spot, avem nevoie de următorii parametri suplimentari:

  • Direcția de iluminare a sursei de lumină
  • Unghiul de tăiere a iluminării, ce controlează deschiderea conului de lumină
  • Un model de atenuare pe bază de unghi a intensității iluminării, ce ține cont de valoarea de unghiului de tăiere

Astfel, un punct se află în conul de lumină al unei sursa de tip spot dacă condiția următoare este indepilită:

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
}

Pentru a simula corect iluminarea de tip spot, este nevoie să tratăm și atenuarea iluminării corespunzătoare apropierii unghiului de taiere. Putem astfel sa utilizăm un model de atenuare patratică ce ofera un rezultat convingator.

float cos_theta_angle = dot(-L, light_direction);
float cos_phi_angle = cos(phi_angle);
 
// Quadratic attenuation
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);

Biblioteca GLM

Matrici de transformare

Biblioteca GLM ne pune la dispoziție metode de construcție a matricilor celor 3 tipuri de transformări analizate: translatie, modificare de scară și rotație. Următoarele 2 lanțuri de transformări sunt identice:

glm::mat4 model = glm::mat4(1);
model = glm::translate(model, glm::vec3(-5, 1.5f, 1));
model = glm::rotate(model, glm::radians(60.0f), glm::vec3(0, 1, 0));
model = glm::scale(model, glm::vec3(0.1f));
glm::mat4 model = glm::mat4(1);
model *= transform3D::Translate(glm::vec3(-5, 1.5f, 1));
model *= transform3D::RotateOY(glm::radians(60.0f));
model *= trasnform3D::Scale(glm::vec3(0.1f));

Aplicarea matricilor de transformare

Dacă dorim să rotim un vector cu 30 de grade față de axa OY, putem utiliza matricile de mai sus după cum urmează:

glm::vec3 v = glm::vec3(1, 0, 0);
 
glm::mat4 rotation = glm::rotate(glm::mat4(1), glm::radians(30.0f), glm::vec3(0, 1, 0));
 
// First option
v = glm::mat3(rotation) * v;
 
// Second option
v = glm::vec3(rotation * glm::vec4(v, 1.0f));

Transmiterea de vectori în atribute de tip uniform

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:

glm::vec3 light_positions[10];
 
glUniform3fv(location, 10, glm::value_ptr(light_positions[0]));

Detalii de implementare

  • Calculele de iluminare se vor face în spatiul lumii, deci înainte de a fi folosite, poziția și normala vor trebui aduse din spatiul obiectului în spatiul lumii. Aceste calcule se realizeaza in vertex shader si noua pozitie si vector normal se transmit spre fragment shader. Calculul se poate face astfel:
    • pentru poziție:
      vec3 world_position = (model_matrix * vec4(v_position,1)).xyz;
    • pentru normală:
      vec3 world_normal = normalize( mat3(model_matrix) * v_normal );
  • Vectorul normal N trebuie renormalizat in fragment shader, deoarece dupa procesul de interpolare, lungimea lui nu se pastreaza:
    vec3 N = normalize( world_normal );
  • Vectorul direcției luminii L:
    vec3 L = normalize( light_position - world_position );
  • Vectorul direcției din care priveste observatorul V:
    vec3 V = normalize( eye_position - world_position );

Funcții GLSL utile care pot fi folosite 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ă a 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

Cerințe laborator

Prin apasarea tastelor W, A, S, D, E si Q puteti controla pozitia unei surse de lumina. Prin apasarea tastei F puteti interschimba intre controlul a doua surse de lumina, una punctiforma si cealalta de tip spot.

  1. 0.05p - Trimiteti toate informatiile necesare calcularii iluminarii in atribute de tip uniform.
  2. 0.15p - Implementati calculul de iluminare in fisierele sursa ale programelor de tip shader:
    • Completati in fisierul VertexShader.glsl calculul pozitiei varfului si a vectorului normal in spatiul lumii si transmiteti-le spre fragment shader.
    • Completati in fisierul FragmentShader.glsl:
      • Calculul componentelor difuze si speculare ale iluminarii unei surse de lumina
      • Calculul factorului de atenuare a iluminarii pe baza de distanta
      • Calculul final de obtinere a iluminarii prin combinarea componentelor difuza si speculara, a factorului de atenuare si a culorii iluminarii
      • Calculul componentei ambientale a iluminarii globale
      • Până în acest punct, rezultatul pe care ar trebui să îl obțineti este următorul. Culoarea fiecarei lumini este aleasa aleator la inceputul fiecarei executii a aplicatiei grafice
  3. 0.05p - Implementati calculul de iluminare pentru sursele de lumina de tip spot:
    • Completati in fisierul FragmentShader.glsl:
      • Calculul factorului de atenuare specific unei surse de lumina de tip spot
      • Calculul final de obtinere a iluminarii prin combinarea componentelor difuza si speculara, a factorului de atenuare si a culorii iluminarii
  4. 0.05p - Pentru sursa de lumina de tip spot ce poate fi controlata de la tastatura, prin apasarea unor taste, modificati directia de iluminare si unghiul. Directia de vizualizare trebuie sa se poata roti fata de axa OX si OZ, in ambele sensuri, iar unghiul trebuie sa se poata mari si micsora.
ppbg/laboratoare/06.1700122189.txt.gz · Last modified: 2023/11/16 10:09 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