This is an old revision of the document!
Va reamintim formulele pentru calculul culorii intr-un punct al unei suprafețe:
$culoarea = c_e + c_a + c_d + c_s$
Emisiva: $c_e = K_e$
Ambientala: $c_a = I_a \cdot K_a$
Difuza: $c_d = K_d \cdot I_{sursă} \cdot max(\vec{N}\cdot \vec{L}, 0)$
Speculara: $c_s = K_s \cdot I_{sursă} \cdot lum \cdot (max(\vec{N}\cdot \vec{H}, 0)^n $, unde $lum = (\vec{N}\cdot \vec{L}>0) ? 1 : 0$
Dacă introducem mai multe lumini în scenă și ținem cont și de factorul de atenuare, atunci culoarea intr-un punct al unei suprafețe este:
$culoarea = K_e + I_a \cdot K_a + \sum{f_{at_i} \cdot I_{sursă_i} (K_d \cdot max(\vec{N}\cdot \vec{L_i}, 0) + K_s \cdot lum_i \cdot (max(\vec{N}\cdot \vec{H_i}, 0)^n})$
La laboratorul de saptamana trecuta, pentru ușurința implementării, am considerat mai multe simplificări:
Totuși, trebuie să menționăm că modelul complet urmărește formula de mai sus, unde constantele de material $K_e, K_a, K_d, K_s$ sunt diferite și au 3 canale $(R,G,B)$, iar intensitatea luminii ambientale și intensitatea sursei de lumină au de asemenea 3 canale. Expresia luminii se evaluează separat pentru cele trei canale.
Modeulul de iluminare aplicat in cazul implementarii in fragment shader este acelasi cu cel studiat in Laboratorul 07. Totusi, exista o diferenta majora intre cele doua implementari prin faptul ca iluminarea nu se mai aplica la nivelul fiecarul vertex ci la nivel de fragment. Rezultatul final este superior calitativ intrucat iluminarea fiecarui fragment nu se va mai calcula pe baza interpolarii luminii calculate la nivel de vertex ci pe baza normalei si pozitiei in spatiu a fiecarui fragment.
Valorile de intrare primite de Fragment Shader sunt interpolate linar intre valorile vertexilor ce compun primitiva utilizata la desenare.
Imaginea de mai sus este obtinuta prin desenarea unui triunghi avand cele 3 varfuri de culori diferite: rosu, verde, albastru
Prin transmiterea culorii de la Vertex Shader la Fragment Shader culoarea fiecarui fragment de pe suprafata triunghiului este calculata ca o interpolare linara intre culorile vertexilor ce compun primitiva specificata (in acest caz, un triunghi).
Acelasi procedeu se aplica pentru orice alta proprietate, cum ar fi:
Mai multe detalii despre modelele de interpolare se pot gasi accesind urmatoarele resurse:
Astfel, utilizand valorile interpolate de pozitie si normala (in spatiul lume) putem sa calculam modeul de iluminare Phong pentru fiecare fragment al unei primitive rasterizate, rezultatul final fiind mult superior intrucat prin interpolarea normalelor se obtine o trecere lina intre suprafete adiacente (sunt interpolate normalele de pe muchii), deci si iluminarea finala va oferi impresia unei suprafete netede. Astfel poligoanele componente ale obiectelor nu vor mai aparea vizibil in imagine.
Detalii de implementare
Pentru a primi valoarea unei variabile de tip uniform
este suficient sa declarati respectiva variabila in shaderul in care este necesara. Deci, NU trimiteti valoarea unei variabile de la Vertex Shader la Fragment Shader
// Vertex Shader uniform vec3 light_position;
// Fragment Shader uniform vec3 light_position;
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:
Astfel, punctul P se afla in conul de lumina (primeste lumina) daca conditia urmatoare este indepilita:
float cut_off = radians(30); float spot_light = dot(-L, light_direction); if (spot_light > cos(cut_off)) { // fragmentul este iluminat de spot, deci 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 cut_off = radians(30); float spot_light = dot(-L, light_direction); float spot_light_limit = cos(cut_off); // Quadratic attenuation float linear_att = (spot_light - spot_light_limit) / (1 - spot_light_limit); float light_att_factor = pow(linear_att, 2);
tasta F5 - reincarca shaderele in timpul rularii aplicatiei.
In cazul in care ati modificat doar sursele shader nu este nevoie sa opriti aplicatia intrucat shaderele sunt compilate si rulate de catre placa video si nu au legatura cu codul sursa C++ propriu zis, iar framework-ul ofera suport pentru reincarcarea acestora la runtime.
uniform vec3 light_direction
[Bonus]
OnInputUpdate