This is an old revision of the document!
Lumina este un factor foarte important în redarea cât mai realistă a unei scene 3D. Împreună cu proprietățile de material ale unui obiect, lumina determină modalitatea în care obiectul este afișat în scena 3D.
Există mai multe modele empirice pentru calculul reflexiei luminii într-un punct al unei suprafețe: Phong (1975), Blinn (1977), Oren-Nayar (1994), Cook-Torrance (1981), Lambert (1760), etc (la curs veți discuta despre modelul Lambert și despre modelul Phong).
Intensitatea luminii care este reflectată într-un punct de pe suprafață către observator este normalizată în intervalul \( [0,1] \), unde 0 reprezintă situația în care lumina care ajunge în punctul respectiv nu este reflectată deloc către observator și 1 este situația în care tot fasciculul de lumină care ajunge in punctul respectiv este reflectat către observator. Pentru a calcula această intensitate în punctul ales vom folosi un model de reflexie care extinde modelul Phong și care conține un total de 4 componente ale intensității luminii pentru a descrie intensitatea finală in punctul de pe suprafață:
Contribuția fiecărei componente este calculată ca o combinație dintre proprietățile de material ale obiectului (factorul de strălucire și de difuzie al materialului) și proprietățile sursei de lumină (intensitatea sursei de lumină, poziția sursei de lumină).
Astfel, intensitatea finală a luminii într-un punct aparținând unei suprafețe este:
float intensitate = emisiva + ambientala + difuza + speculara; # GLSL
În cele ce urmează prezentăm pe scurt ce reprezintă cele 4 componente și cum pot fi calculate.
Aceasta reprezintă lumina emisă de un obiect și nu ține cont de nicio sursă de lumină. Dacă un obiect care are o anumită culoare emisivă s-ar afla într-o scenă complet întunecată atunci el ar apărea exact cu această culoare.
O utilizare des întâlnită pentru componenta emisivă este aceea de a simula strălucirea unui obiect.
Avem astfel:
float emisiva = Ke; # GLSL
Aceasta reprezintă lumina reflectată de catre obiectele din scenă de atât de multe ori încât pare să vină de peste tot.
Astfel, lumina ambientală nu vine dintr-o direcție anume, apărând ca și cum ar veni din toate direcțiile. Din această cauză, componenta ambientală este independentă de poziția sursei de lumină.
Componenta ambientală depinde de intensitatea de material ambientală a suprafeței obiectului și de intensitatea luminii.
Similar componentei emisive, componenta ambientală este o constantă (se poate extinde modelul atribuind fiecărei lumini din scenă o intensitate ambientală).
Avem astfel:
float ambientala = Ka * intensitateAmbientalaGlobala; # GLSL
Aceasta reprezintă lumina reflectată de suprafața obiectului în mod egal în toate direcțiile.
Cantitatea de lumină reflectată este proporțională cu unghiul de incidență al razei de lumină cu suprafața obiectului.
Avem astfel: $difuza = K_d \cdot intensitateLumina \cdot max(\vec{N}\cdot \vec{L}, 0)$
float difuza = Kd * intensitateLumina * max (dot(N,L), 0); # GLSL
Un reflector perfect, de exemplu o oglindă, reflectă lumina numai într-o singură direcție $\vec{R}$, care este simetrică cu $\vec{L}$ față de normala la suprafață. Prin urmare, doar un observator situat exact pe direcția respectivă va percepe raza reflectată.
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
În modelul Phong se aproximează scăderea rapidă a intensității luminii reflectate atunci când $\alpha$ crește prin $cos^n \alpha$, 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.
Astfel avem: $speculara = K_s \cdot intensitateLumina \cdot primesteLumina \cdot (max(\vec{V}\cdot \vec{R}, 0))^n$
float speculara = Ks * intensitateLumina * primesteLumina * pow(max(dot(V, R), 0), n) # GLSL
Un alt model de iluminare (Blinn (1977)) pentru componenta speculară se bazează pe vectorul median, notat cu $\vec{H}$. El face unghiuri egale cu $\vec{L}$ și cu $\vec{V}$. Dacă suprafața ar fi orientată astfel încât normala sa să aibă direcția lui $\vec{H}$, atunci observatorul ar percepe lumina speculară maximă (deoarece ar fi pe direcția razei reflectate specular).
Termenul care exprimă reflexia speculară este în acest caz: $(\vec{N} \cdot \vec{H})^n$
pow(dot(N, H), n) # GLSL
Atunci când sursa de lumină și observatorul sunt la infinit, utilizarea termenului $\vec{N}\cdot \vec{H}$ este avantajoasă deoarece $\vec{H}$ este constant.
Ținând cont de toate acestea, avem pentru componenta speculară următoarea formulă: $speculara = K_s \cdot intensitateLumina \cdot primesteLumina \cdot (max(\vec{N}\cdot \vec{H}, 0)^n $
float speculara = Ks * intensitateLumina * primesteLumina * pow(max(dot(N, H), 0), n) # GLSL
Atunci când sursa de lumină punctiformă este suficient de îndepărtată de obiectele scenei vizualizate, vectorul $\vec{L}$ este același în orice punct. Sursa de lumină este numită în acest caz direcțională. Aplicând modelul pentru vizualizarea a două suprafețe paralele construite din același material, se va obține o aceeași intensitate (unghiul dintre $\vec{L}$ și normală este același pentru cele două suprafețe). Dacă proiecțiile suprafețelor se suprapun în imagine, atunci ele nu se vor distinge. Această situație apare deoarece în model nu se ține cont de faptul că intensitatea luminii descrește proporțional cu inversul pătratului distanței de la sursa de lumină la obiect. Deci, obiectele mai îndepărtate de sursă sunt mai slab luminate. O posibilă corecție a modelului, care poate fi aplicată pentru surse poziționale (la distanță finită de scenă) este:
float intensitate = emisiva + ambientala + factorAtenuare * ( difuza + speculara ); # GLSL
Corecția de mai sus nu satisface cazurile în care sursa este foarte îndepărtată. De asemenea, dacă sursa este la distanță foarte mică de scenă, intensitățile obținute pentru două suprafețe cu același unghi $i$, între $\vec{L}$ și $\vec{N}$, vor fi mult diferite.
Pentru a include in final culoarea de material a obiectului si culoare luminii (care alternativ pot fi incluse si in formulele de mai sus) se foloseste:
vec3 culoare = culoareObiect * (emisiva + culoareLumina * (ambientala + factorAtenuare * ( difuza + speculara ))); # GLSL
De asemenea, există mai multe modele de shading, care specifică metoda de implementare a modelului de calcul al reflexiei luminii. Mai exact, modelul de shading specifică unde se evaluează modelul de reflexie. Dacă vrem să calculăm iluminarea pentru o suprafață poligonală:
Figura 1. Diferite modele de shading: Lambert (o culoare per primitivă), Gouraud (o culoare per vârf), Phong (o culoare per fragment)
În acest laborator se va discuta modelul de shading Gouraud peste modelul de reflexie Phong.
Pentru simplitate, în cadrul laboratorului vom implementa modelul de shading Gouraud (în vertex shader):
vec3 world_pos = (model_matrix * vec4(v_position,1)).xyz;
vec3 world_normal = normalize( mat3(model_matrix) * v_normal );
vec3 L = normalize( light_position - world_pos );
vec3 V = normalize( eye_position - world_pos );
vec3 H = normalize( L + V );
Tasta F5 - reîncarcă programele shader în timpul execuției aplicației. Nu este nevoie să opriți aplicația întrucât un program shader este compilat și executat de către procesorul grafic și nu are legătură cu codul sursă C++ propriu-zis.
RenderSimpleMesh
astfel încât să trimiteți corect valorile uniforme către Shader: