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 unor modele 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 sursei lumină asupra punctului de pe suprafață. 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 din jurul poziției.
  • Sursă de lumină de tip spot, ce are o poziție în spațiu și împrăștie lumină de-alungul unei singure direcții, de la această poziție.

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 despre 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 refera la transportul luminii de la o sursă, prin reflexia pe exact o singură suprafață, într-un punct, la poziția observatorului.
  • Componenta de reflexie strălucitoare, ce se referă, similar cu cea de reflexie difuză, la transportul luminii de la o sursa, prin reflexia pe o singură suprafață, într-un punct, la poziția observatorului.

Diferenta dintre ultimele doua componente este data de comportamentul de reflexie, respectiv o reflexie difuza si o reflexie oglinda.

Deoarece lumina este aditiva, cu cat mai multi fotoni ajung in ochii nostri, cu atat lumina este mai “puternica” :), rezultatul final al influentei iluminarii intr-un punct este dat de suma celor 4 componente:

influenta_finala = componenta_emisiva + componenta_indirecta +
                   componenta_difuza + componenta_stralucire; # GLSL

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ă se poate aproxima printr-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 refera la cantitatea de lumină ce este impraștiată uniform prin reflexie pe o suprafață, în toate direcțiile din jurul punctului de pe suprafață, deasupra ei.

Componenta de reflexie oglinda

Aceasta componenta se refera la cantitatea de lumina ce este reflectata de-alungul directiei de reflexie simetrica fata de directia de incidenta a luminii cu directia vectorului normal. Aceasta componenta este cunoscuta sub numele de componenta speculara. Termenul speculum in limba latina se traduce in limba romana cu termenul de oglinda :) .

Atenuarea intensitatii iluminarii pe baza de distanta

In momentul in care sursa de lumina a un fascicul difuz se departeaza de un obiect, prin procesul de difuzie, cantitatea de lumina emisa se pastreaza, dar obiectul primeste o cantitate mai mica de lumina. Calculul acestui fenomen se realizeaza pe baza de distanta fata pozitia sursei de lumina si pozitia pentru care se calculeaza iluminarea.

Laborator

In practica, inclusiv in cadrul acestui laborator, se utilizeaza simulari ale fenomenelor optice.

Componenta emisivă

componenta_emisiva = Ke; # GLSL

  • Ke – culoarea emisivă a materialului

Componenta indirecta a iluminarii

Este cunoscuta in practica sub numele de componenta ambientala. Pentru a nu calcula tot transportul luminii cu toate reflexiile de pe suprafete, se considera ca influenta indirecta a iluminarii este aceeasi in toate punctele din scena. Aceasta aproximare obtine rezultate satisfacatoare pentru o parte din scenarii.

Avem astfel:

ambient_component = Ka * global_ambient_color; # GLSL

  • Ka – constanta de reflexie ambientală a materialului
  • global_ambient_color – culoarea ambientală a luminii

Componenta difuză

In imaginea de mai jos se poate observa ca un fascicul de lumina ce are o latime de dimensiune A, este proiectat pe suprafata de-alungul unei zone de dimensiune B. Se poate ca in situatia in care fasciculul este proiectat vertical pe suprafata, B = A.

Notam cu alpha unghiul dintre vectorul spre directia sursei de lumina, L, si vectorul normal, N. Deoarece unghiul facut cu normala este 90 de grade, unghiul fata de vectorul L, realizat cu suprafata este de 90-alpha. Pentru ca suma unghiurilor unui triunghi este de 180 si triunghiul este dreptunghic, rezulta ca cel de-al treilea unghi din triunghi are dimensiunea alpha. Astfel, rezulta:

$$ cos(\alpha)=\frac{A}{B} \\ B=\frac{A}{cos(\alpha)} $$

Din acest motiv, se poate deduce ca intensitatea de iluminare pentru orice punct de pe suprafata este cos(alpha). In situatia in care alpha este 0 grade, intensitatea de iluminare este cos(0) = 1. Aceasta abordare poarta numele de legea cosinusului a lui Lambert, propusa de Johann Heinrich Lambert in 1760.

In grafica pe calculator, aceasta lege a cosinusului este utilizata pentru calculul de reflexie a uniforma in toate directiile. Mai exact, se considera ca lumina se imprastie uniform in toate directiile cu intensitatea de iluminare data de legea cosinusului a lui Lambert.

In practica, in loc de cosinus se utilizeaza produsul scalar dintre L si N, cu L si N, ambii de lungime 1. Interpretarea geometrica 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} $$

In situatia in care vectorii V1 si V2 sunt de lungime 1 amandoi, expresia de mai sus este echivalenta cu:

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

Pentru a obtine un vector unitate, de lungime 1, V' pe directia si in sensul dat de un vector V, putem aplica in limbajul glsl:

vec3 Vu = normalize(V);

Astfel, calculul componentei difuze a iluminarii este:

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

In limbajul glsl, expresia de mai sus se transcrie sub forma:

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

  • Kd - constanta de reflexie difuză a materialului
  • culoareLumina – culoarea luminii
  • N – normala la suprafață (normalizată)
  • 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ă $i$ 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 $$

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

  • Ks - constanta speculară de reflexie a materialului
  • V – vectorul direcției de vizualizare (normalizat)
  • 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 intensitatii iluminarii pe baza de distanta se aplica doar componentelor difuza si speculara:

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 lumina de tip spot

Pentru a simula

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

Asa cum se poate vedea si in poza pentru a implementa o sursa de lumina de tip spot avem nevoie de urmatorii parametri aditionali:

  • Directia de iluminare a sursei de lumina
  • Unghiul de taiere a iluminarii ce controleaza deschiderea conului de lumina
  • Un model de atenuare pe baza de unghi a intensitatii iluminarii ce tine cont valoarea de unghiului de taiere

Astfel, punctul P se afla in conul de lumina (primeste lumina) daca conditia urmatoare este indepilita:

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 sa tratam si atenuarea luminii corespunzatoare apropierii unghiului de cut-off. Putem astfel sa utilizam un model de atenuare patratica 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

Biblioteca GLM ne pune la dispozitie constructia de matrici pentru cele 3 tipuri de transformari analizate: translatie, modificare de scara si rotatie. Urmatoarele 2 lanturi de transformari 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));

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

Cerinte 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.1700092923.txt.gz · Last modified: 2023/11/16 02:02 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