Differences

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

Link to this comparison view

ppbg:laboratoare:06 [2023/11/16 01:38]
andrei.lambru
ppbg:laboratoare:06 [2024/11/14 09:59] (current)
andrei.lambru
Line 1: Line 1:
 ====== Laboratorul 06 ====== ====== Laboratorul 06 ======
 +
 +<note important>​
 +Pentru rezolvarea cerințelor din acest laborator, aveți nevoie de codul utilizat în rezolvarea cerințelor din cadrul laboratorului 4. În situatia în care nu ați rezolvat [[:​ppbg:​laboratoare:​04|laboratorul 4]], va trebui să îl realizați mai întâi pe el și ulterior să reveniți la cerințele celui curent.
 +</​note>​
  
 <note tip> <note tip>
 **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>​
 +
 +===== Banda grafică programabilă =====
 +
 +În [[:​ppbg:​laboratoare:​04#​modele_3d|laboratorul anterior]], am analizat modalitatea prin care sunt stocate listele de vârfuri și de indici ce descriu un model 3D compus dintr-o rețea de triunghiuri. În API-ul grafic OpenGL, noi am utilizat 3 tipuri de obiecte diferite, un obiect ce păstrează buffer-ul de vârfuri (VBO), un obiect ce păstrează buffer-ul de indici (IBO) și un container ce le înglobează pe amândouă, VAO. Pentru desenare, informația listelor de vârfuri și indici trebuie să se regăsească în memoria RAM a procesorului grafic.
 +
 +În [[:​ppbg:​laboratoare:​03##​lantul_de_transformari_3d|laboratorul 3]], am analizat modalitatea prin care coordonatele vârfurilor unui model 3D sunt transformate din spațiul inițial în care au fost definite, numit **spațiul obiect**, la poziția și forma finală în scenă, al cărei spațiu este cunoscut sub numele de **spațiul lume**. Din acest spațiu, coordonatele vârfurilor sunt transformate în **spațiul de vizualizare** și ulterior în **spațiul de decupare**. După împărțirea perspectivă,​ decuparea triunghiurilor la limitele volumului de decupare, eliminarea triunghiurilor pe baza opțiunii de afișare a fețelor și transformarea în poarta de afișare, triunghiurile sunt transmise în procesul de rasterizare. Pe baza acestui proces, triunghiurile sunt desenate în grila de pixeli. Toți acești pași se regăsesc în imaginea de mai jos, unde este prezentată o privire de ansamblu a benzii grafice.
 +
 +{{ :​ppbg:​laboratoare:​shaders.png?​600 |}}
 +
 +Procesorul grafic, prin intermediul driver-ului video și a standardului API OpenGL, ne pune la dispoziție posibilitatea de a scrie programe de calculator ce sunt executate direct de către unitatea grafică de procesare. Pașii în care putem executa aceste programe sunt ficși în banda grafică. Există mai multe tipuri de astfel de programe, dar în acest laborator, vom analiza doar două. Toate tipurile de programe poartă denumirea în limba engleză de **shader**. De asemenea, pentru programarea fiecărui tip de program, se utilizează un limbaj special, particular pentru fiecare tip de program. Acest limbaj se numeste generic Limbaj de colorare OpenGL, sau în limba engleză, OpenGL Shading Language (**GLSL**).
  
 <note tip> <note tip>
-Pentru rezolvarea cerințelor din cadrul acestui labroator:​ +Înainte de a merge mai departe, pentru a avea evidențiere și auto-completare pentru limbajul de programare GLSL, în mediul de dezvoltare Visual Studio, este recomandat să instalați o [[https://marketplace.visualstudio.com/items?​itemName=DanielScherzer.GLSL2022extensie specifică]] :) . Pentru ​versiuni mai vechi de Visual Studio 2022, puteți ​utiliza ​[[https://​marketplace.visualstudio.com/​items?​itemName=DanielScherzer.GLSL|această extensie]].
-  ​- [[https://github.com/UPB-Graphics/​gfx-framework-ppbg ​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. +
-  - Adăugați în fișierul ''​lab_list.h'',​ linia ''#​include "​lab/​lab6/​lab6.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>​
  
-===== Modele ​de iluminare =====+==== Programe ​de tip shader pentru prelucrarea vârfurilor ​====
  
-In laboratoarele anterioare, am analizat modalitatea prin care se poate desena pe ecran geometria unor modele 3D. Pana in acest moment, culorile atribuite pixelilor in care fost discretizata suprafata geometriei au fost alese artificial prin diferite abordari, precum interpolarea intre culorile varfurilor. Deoarece ochiul uman "​vede"​ doar lumina, culoarea unui pixel in care a fost discretizata o suprafata, trebuie sa se calculeze pe baza influentei sursei lumina asupra punctului de pe suprafata. Pentru acest proces, se introduce ​in procesul ​de desenareconceptul de **sursa de lumina**. Exista mai multe tipuri ​de astfel de surse: +Pentru ​prelucra informația fiecărui vârf în parte, se introduce ​un program ​de tip shaderdenumit în limba engleză ​**Vertex Shader**. // Pentru fiecare vârf din lista de vârfuri, se execută ​**o singură instanță** de program ​de tip vertex shader.// Sintaxa lui este în felul următor:
-  ​Sursa de lumina ​**punctiforma**, ce are o pozitia in spatiul lume si imprastie lumina uniform in toate directiile in jurul acestei pozitii +
-  * Sursa de lumina ​de **tip spot**, similara cu o lanterna, ce are o pozitie in spatiul lume si imprastie lumina de-alungul unei singure directii, de la aceasta pozitie.+
  
-Calcularea influentei unei sursa de lumina, de orice tip, asupra unui punct de pe o suprafata se realizeaza prin simularea procesului de transport al luminii de la pozitia sursei, prin reflexie pe suprafata, in pozitia punctului de calcul, la pozitia observatorului. Abordarea de simulare a acestui proces de simulare a transportului luminii poarta numele de **model de iluminare** sau de **model de reflexie**.+<code glsl> 
 +#version 330
  
-In general, ​in toate modelele de iluminare, influenta luminii asupra unui punct este impartita ​in 4 componente: +layout(location = 0) in vec3 v_position;​ 
-  * Componenta emisiva, reprezentata de lumini care este emisa direct de catre suprafata. Este vorba despre suprafetele ce emit lumina, precum suprafata unui bec sau a ecranului unui televizor. +layout(location = 1) in vec3 v_normal; 
-  * Componenta de reflexie indirecta a luminii, ce se refera la procesul de transport al luminii, de la o sursa, prin reflexia pe mai multe, secvential, la pozitia observatorului. +layout(location = 2) in vec2 v_tex_coord;​ 
-  * Componenta de reflexie difuza, ce se refera la transportul luminii de la o sursa, prin reflexia pe **exact o singura suprafata**,​ intr-un punct, la pozitia observatorului. +layout(location = 3) in vec3 v_color;
-  * Componenta de reflexie stralucitoare,​ ce se refera, similar cu cea de reflexie difuza, la transportul luminii de la o sursa, prin reflexia pe **o singura suprafata**,​ intr-un punct, la pozitia observatorului.+
  
-Diferenta dintre ultimele doua componente este data de comportamentul de reflexie, respectiv o reflexie difuza si o reflexie oglinda.+// Uniform properties 
 +uniform mat4 Model; 
 +uniform mat4 View; 
 +uniform mat4 Projection;
  
-Deoarece lumina este aditivacu 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:+void main() 
 +
 +    gl_Position = Projection * View * Model * vec4(v_position1.0); 
 +
 +</​code>​ 
 + 
 +Directiva de mai jos specifică versiunea limbajului ce se dorește să fie utilizată. Limbajul GLSL are mai multe versiuni posibile. Directiva ​este obligatorie și trebuie să fie prima directivă din codul sursă ​al programului.
  
 <code glsl> <code glsl>
-influenta_finala = componenta_emisiva + componenta_indirecta + +#version 330
-                   ​componenta_difuza + componenta_stralucire; ​GLSL+
 </​code>​ </​code>​
  
-==== Componenta emisiva ====+Următoarele atribute sunt date de intrare specifice unui singur vârf. După cum se poate observa, tipurile de date sunt similare bibliotecii ''​glm''​. Biblioteca respectă standardul limbajului de programare GLSL.
  
-In situatia ​in care ne referim strict la transportul luminii de la suprafata la pozitia observatorului,​ aceasta componenta se poate aproxima printr-o distributie uniforma a imprastierii luminii de la suprafata ​in toate directiile, astfel ca se poate folosi o valoare constanta.+<code glsl> 
 +layout(location = 0) in vec3 v_position;​ 
 +layout(location = 1) in vec3 v_normal; 
 +layout(location = 2) in vec2 v_tex_coord;​ 
 +layout(location = 3) in vec3 v_color; 
 +</​code>​
  
-<note tip> +În situația framework-ului utilizat în cadrul acestui laborator, aceste date sunt aceleași cu cele ce se regăsesc în structura ''​VertexFormat''​. Felul în care se specifică legătura dintre formatul informației unui vârf și formatul datelor ​de intrare ​de mai susdin programul ​de tip vertex shader, va fi descris mai jos.
-In situatia in care dorim sa simulam procesul ​de transport al luminii ​de la o suprafata ce emite luminaprin reflexie pe o alta suprafata, la pozitia observatorului,​ procesul este devine foarte complex. Exista abordari pentru simularea lui, dar in general in aplicatii grafice in timp real se evita astfel ​de efecte vizualeO metoda  +
-</​note>​+
  
-==== Componenta indirecta a iluminarii ====+<code cpp> 
 +struct VertexFormat 
 +
 +    glm::vec3 position; 
 +    glm::vec3 normal; 
 +    glm::vec2 text_coord;​ 
 +    glm::vec3 color; 
 +}; 
 +</​code>​
  
-In general, este precalculata in aplicatiile grafice in timp real si se evita utilizarea pentru un numar mare de obiecte dinamiceOdata cu aparitia procesoarelor grafice ce au arhitecturi ​de ray-tracing,​ se folosesc astfel ​de tehnici ​pentru ​simularea transportului luminii de la o sursace ajunge prin reflexii multiple pe mai multe suprafetesecvential, la pozitia observatorului.+Următoarele atribute sunt de asemenea date de intrareEle sunt //comune tuturor instanțelor ​de programe ​de tip vertex shader executate// ​pentru ​vârfurile din listă. De asemeneaaceste atribute sunt comune tuturor instanțelor executateindiferent de tipul de shader. Acest tip de atribut poartă numele de **uniform** în limba engleză.
  
-==== Componentele de reflexie directa ====+<code glsl> 
 +uniform mat4 Model; 
 +uniform mat4 View; 
 +uniform mat4 Projection;​ 
 +</​code>​
  
-Acestea se refera la transportul luminii ​de la pozitia unei surse, prin reflexie pe o suprafata la pozitia observatorului. Pentru comoditate, se imparte acest tip de reflexie in doua componente distincte:+Toate programele ​de tip shader trebuie sa conțină un ''​void main()'' ​de unde se începe execuția codului.
  
-=== Componenta de reflexie difuza ===+<code glsl> 
 +void main() 
 +
 +    gl_Position ​Projection * View * Model * vec4(v_position,​ 1.0); 
 +
 +</​code>​
  
-Aceasta componenta se refera la cantitatea ​de lumina ​ce este imprastiata uniform prin reflexie ​pe o suprafata in toate directiile din jurul punctului ​de pe suprafatadeasupra ei.+Atributul ''​gl_Position''​ este //implicit în programul ​de tip vertex shader// și reprezintă **coordonatele vârfurilor în spațiul de decupare**. Conform lanțului de transformări,​ vizibil și în imaginea de mai sus, asupra coordonatelor inițiale ale vârfului ​ce se află în spațiul obiect, s-au aplicat ​pe rând transformările ​de modelarede vizualizare și de proiecție.
  
-=== Componenta ​de reflexie oglinda ​===+==== Programe ​de tip shader pentru prelucrarea pixelilor ====
  
-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// :) .+Pentru //fiecare pixel ce a fost procesat ​de către rasterizator și pentru care trebuie să i se atribuie o culoare, rasterizatorul execută o instanță a programului pentru prelucrarea ​de pixeli//. Acest tip de program poate avea mai multe date de ieșire, dar în acest laborator ne vom concentra exclusiv pe //**culoarea pe care trebuie să o atribuie pixelului prelucrat**//​Tipul de program utilizat pentru prelucrarea pixelilor poartă ​numele, în limba engleză, ​de **fragment shader** sau **pixel shader**.
  
-==== Atenuarea intensitatii iluminarii pe baza de distanta ====+<note tip> 
 +Majoritatea API-urilor grafice adoptă termenul ​de **fragment shader**, deoarece aceste API-uri ne oferă posibilitatea de a executa mai multe instanțe de fragment shader per pixel, în situația în care dorim acest lucru. Această abordare poartă numele de eșantionare multiplă și mai multe detalii despre ea pot fi consultate în documentația oficială: https://​www.khronos.org/​opengl/​wiki/​Multisampling. 
 +</​note>​
  
-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.+Sintaxa unui fragment shader este în felul următor:
  
-===== Laborator =====+<code glsl> 
 +#version 330
  
-In practica, inclusiv in cadrul acestui laborator, se utilizeaza simulari ale fenomenelor optice.+// Uniform properties 
 +uniform mat4 Model; 
 +uniform mat4 View; 
 +uniform mat4 Projection;
  
-==== Componenta emisivă ====+layout(location ​0) out vec4 out_color;
  
-<code glsl> ​ +void main() 
-componenta_emisiva ​Ke# GLSL+
 +    out_color ​vec4(1, 0, 0, 0); 
 +}
 </​code>​ </​code>​
-<note tip> 
-  * Ke – culoarea emisivă a materialului 
-</​note>​ 
  
-==== Componenta indirecta a iluminarii ====+Similar ca în situația programului de tip vertex shader, este obligatoriu ca prima directivă să fie cea care specifică versiunea utilizată pentru limbajul de programare GLSL. De asemenea, toate atributele de intrare de tip uniform sunt disponibile în fragment shader. În plus, și acest tip de program are un ''​void main()''​ din care se începe execuția codului.
  
-Este cunoscuta in practica sub numele ​de **componenta ambientala**. Pentru a nu calcula tot transportul luminii cu toate reflexiile ​de pe suprafetese considera ca influenta indirecta a iluminarii ​este **aceeasi in toate punctele din scena**. Aceasta aproximare obtine rezultate satisfacatoare pentru o parte din scenarii.+Atributul ​de mai jos este un atribut ​de ieșire pentru fragment shader. În situația acestui laboratorsingurul atribut de ieșire dintr-un program de tip fragment shader ​este culoarea pixelului ​din grilă.
  
-Avem astfel:+<code glsl> 
 +layout(location = 0) out vec4 out_color;​ 
 +</​code>​ 
 + 
 +Programul de mai jos asociază tuturor pixelilor culoarea roșie.
  
 <code glsl> <code glsl>
-ambient_component ​Ka * global_ambient_color# GLSL+void main() 
 +
 +    out_color ​vec4(1, 0, 0, 0); 
 +}
 </​code>​ </​code>​
  
-<​note ​tip+<​note ​important
-  Ka – constanta de reflexie ambientală a materialului +API-ul grafic OpenGL ​**NU** permite utilizarea în banda grafică a unui singur tip de program din cele două. Este necesar să se utilizeze ambele tipuri de programe.
-  ​global_ambient_color – culoarea ambientală a luminii+
 </​note>​ </​note>​
  
-==== Componenta difuză ​====+===== Gestionarea programelor de tip shader în API-ul grafic OpenGL =====
  
-In imaginea de mai jos se poate observa ca un fascicul de lumina ce are o latime de dimensiune Aeste 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.+În API-ul grafic OpenGLtoate programele ​de tip shader sunt **compilate și legate între ele** pentru a fi executate ​de către procesorul grafic **în timpul execuției aplicației grafice**.
  
-{{ :​ppbg:​laboratoare:​lambert-cosine-law.png?​500 |}}+==== Gestionarea unui obiect de tip shader ====
  
-Notam cu alpha unghiul dintre vectorul spre directia sursei ​de luminaLsi vectorul normal, N. Deoarece unghiul facut cu normala este 90 de grade, unghiul fata de vectorul Lrealizat ​cu suprafata este de 90-alphaPentru 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:+Pentru a gestiona un program ​de tip shaderîn API-ul grafic OpenGLtrebuie să utilizăm un obiect ​de tip shader pentru fiecare din cele două tipuri ​de programe vertex shader și fragment shaderîmpreună ​cu un obiect suplimentar ce înglobează programele ​de tip shader utilizate.
  
 +Pentru crearea unui obiect de tip shader, se utilizează:​
  
-$$ +<code cpp> 
-cos(\alpha)=\frac{A}{B} \\ +// GL_VERTEX_SHADER sau GL_FRAGMENT_SHADER,​ pe baza tipului dorit 
-B=\frac{A}{cos(\alpha)+unsigned int shader_id ​glCreateShader(GL_VERTEX_SHADER);
-$$+
  
 +const char *shader_source = ...;
  
-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 gradeintensitatea de iluminare este cos(0) = 1. Aceasta abordare poarta numele de **legea cosinusului a lui Lambert**, propusa de Johann Heinrich Lambert in 1760.+glShaderSource(shader_id, 1, &​shader_source, 0);
  
-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.+glCompileShader(shader_id);​ 
 +</​code>​
  
-In practicain 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+Pentru legarea a două programe vertex shader și fragment shader, se utilizează:​
  
 +<code cpp>
 +unsigned int program_id = glCreateProgram();​
  
 +glAttachShader(program_id,​ vertex_shader_id);​
 +glAttachShader(program_id,​ fragment_shader_id);​
  
-$$ +glLinkProgram(program_id); 
-\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} +</​code>​
-$$ +
- +
-In situatia in care vectorii V1 si V2 sunt de lungime 1 amandoi, expresia de mai sus este echivalenta cu:+
  
 +Pentru desenarea cu cele două programe de tip shader create mai sus, se utilizează:​
  
 +<code cpp>
 +glUseProgram(program_id);​
  
-$$ +glBindVertexArray(VAO_id);​ 
-\vec{V_1}\cdot\vec{V_2}=cos(\angle(\vec{V_1},​\vec{V_2})+glDrawElements(GL_TRIANGLES,​ indices.size(), GL_UNSIGNED_INT0);
-$$ +
- +
-<note tip> +
-Pentru a obtine un vector unitatede lungime 1V' pe directia si in sensul dat de un vector V, putem aplica in limbajul glsl: +
-<code glsl> +
-vec3 Vu = normalize(V);+
 </​code>​ </​code>​
-</​note>​ 
  
-Astfel, calculul componentei difuze a iluminarii este:+==== Specificarea formatului de date din lista de vârfuri ====
  
-$$ +API-ul grafic OpenGL utilizează memoria stocată în VBO. Pentru a specifica legătura dintre formatul datelor din lista de vârfuri și formatul datelor de intrare din programul de tip vertex shader, API-ul OpenGL pune la dispoziție directiva ''​glVertexAttribPointer'':​ 
-componentaDifuza = K_d \cdot culoareLumina \cdot max(\vec{N}\cdot \vec{L}0+ 
-$$+<code cpp> 
 +glVertexAttribPointer(33, GL_FLOAT, GL_FALSE, sizeof(VertexFormat),​ (void*)(2 * sizeof(glm::​vec3) + sizeof(glm::​vec2))); 
 +</​code>​
  
-In limbajul glsl, expresia ​de mai sus se transcrie sub forma:+Primul parametru reprezintă **locația** atributului ​de intrare din programul de tip vertex shader:
  
 <code glsl> <code glsl>
-vec3 diffuse_component ​Kd * culoareLumina * max (dot(N,L), 0); # GLSL+layout(location ​3in vec3 v_color;
 </​code>​ </​code>​
  
-<note tip> +Pentru exemplul ​de mai susspecificarea formatului ​se realizează în felul următor:
-  * 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 0acest 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>​+
  
-==== Componenta speculară ====+<code cpp> 
 +glBindVertexArray(VAO);​
  
-Pentru calcularea componentei specularevom folosi modelul propus de Bui Tuong Phong in 1973:+// Set vertex position attribute 
 +glEnableVertexAttribArray(0);​ 
 +glVertexAttribPointer(03, GL_FLOAT, GL_FALSE, sizeof(VertexFormat),​ 0);
  
 +// Set vertex normal attribute
 +glEnableVertexAttribArray(1);​
 +glVertexAttribPointer(1,​ 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat),​ (void*)(sizeof(glm::​vec3)));​
  
-$$ +// Set texture coordinate attribute 
-componentaSpeculara = K_s \cdot culoareLumina \cdot primesteLumina \cdot (max(\vec{V}\cdot \vec{R}0))^n +glEnableVertexAttribArray(2); 
-$$+glVertexAttribPointer(22, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(2 * sizeof(glm::​vec3)));​
  
-<code glsl> +// Set vertex color attribute 
-vec3 specular_component = Ks * culoareLumina * primesteLumina * pow(max(dot(VR)0), n# GLSL+glEnableVertexAttribArray(3); 
 +glVertexAttribPointer(33GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(2 * sizeof(glm::​vec3) + sizeof(glm::​vec2)));
 </​code>​ </​code>​
  
-<​note ​tip+<​note>​ 
-  * Ks - constanta speculară de reflexie a materialului +Pentru mai multe detalii despre directiva ''​glVertexAttribPointer'',​ puteți consulta documentația oficială: https://​registry.khronos.org/​OpenGL-Refpages/​gl4/​html/​glVertexAttribPointer.xhtml.
-  * 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+
 </​note>​ </​note>​
  
-{{ :​egc:​laboratoare:​lab07:​specular.jpg?​300 |}}+==== Transmiterea datelor de tip uniform la shader ====
  
-Componenta speculară reprezintă lumina reflectată ​de suprafața obiectului numai în jurul acestei direcții$\vec{R}$Acest vector se obține prin:+Pentru a transmite un atribut ​de tip uniform la un program shader, API-ul grafic OpenGL ne pune la dispoziție mai multe directivespecifice fiecărui tip de date pe care îl permite limbajul de programare GLSLDoar pentru a enumera câteva, directivele sunt:
  
-<​code ​glsl+<​code ​cpp
-     vec3 R = reflect ​(-L, N# GLSL +glUseProgram(program_id);
-</​code>​+
  
-<note tip> +//void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat ​*value) 
-  ​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ă +glm::mat4 matrix(1.0f); 
-</​note>​+glUniformMatrix4fv(location,​ 1, GL_FALSE, glm::​value_ptr(matrix));​
  
-Î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).+// void glUniform1f(GLint locationGLfloat v0) 
 +glUniform1f(location,​ 1.5f);
  
-După cum se observăfață de celelalte 3 componentecomponenta speculară depinde și de poziția observatorului. Dacă observatorul nu se află într-o poziție unde poate vedea razele reflectateatunci nu va vedea reflexie speculară pentru zona respectivăDe asemeneanu va vedea reflexie speculară dacă lumina se află în spatele suprafeței.+// void glUniform4f(GLint locationGLfloat v0GLfloat v1GLfloat v2, GLfloat v3) 
 +glUniform4f(location,​ 1, 0.5f0.3f, 0);
  
-==== Atenuarea intensității iluminarii ====+//void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) 
 +glUniform3i(location,​ 1, 2, 3);
  
-Factorul de atenuare a intensitatii iluminarii pe baza de distanta se aplica doar componentelor difuza si speculara+//void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) 
 +glm::vec3 color = glm::​vec3(1.0f,​ 0.5f, 0.8f); 
 +glUniform3fv(location,​ 1, glm::​value_ptr(color));​ 
 +</​code>​
  
-<​code ​glsl+API-ul grafic OpenGL nu impune obligativitatea utilizării unei locații explicite pentru atributele de tip uniform, dar această locație există implicit. Pentru a obține locația implicită a unui atribut, indiferent de tipul lui, utilizăm:​ 
-vec3 illumination ​emissive_component + ambient_component + 
-                    + attenuation_factor * diffuse_component + specular_component); # GLSL+<​code ​cpp
 +int location ​glGetUniformLocation(program_id, "​uniform_variable_name_in_shader"​);
 </​code>​ </​code>​
  
 <note tip> <note tip>
-  * attenuation_factor = $1/(d^2+1)$ este o funcție ​de atenuare +Pentru mai multe detalii despre directivele ​de transmitere ​atributelor ​de tip uniform, ​pe baza tipului, puteți consulta documentația oficială: https://​registry.khronos.org/​OpenGL-Refpages/​gl4/​html/​glUniform.xhtml . 
-  * $d$ este distanța de la pozitia sursei de lumina la pozitia punctului de pe suprafață pentru care se calculeaza iluminarea +</​note>​
-</​note> ​ +
  
-<​hidden>​ +==== Comunicarea între vertex shader și fragment shader ====
-<​note>​ +
-Modele de colorare+
  
-Există mai multe modele pentru a specifica abordarea ​de implementare a modelului ​de calcul al reflexiei luminii. Mai exactse specifică unde se evaluează modelul ​de reflexieO astfel de abordare poarta numele de model de colorare si se intalneste in limba engleza sub numele de **shading model**. Dacă vrem să calculăm iluminarea pentru o suprafață poligonală+Pe lângă atributul implicit ''​gl_Position'',​ un program ​de tip vertex shader poate avea atribute ​de ieșire explicitece devin atribute de intrare pentru următorul tip de program din banda grafică, respectiv pentru laboratorul curent, pentru programul ​de tip fragment shaderExistă două posibilități de declarare a acestor atribute
-  * Se poate calcula o singură culoare ​pentru ​un triunghi ​al suprafeței. Acesta poarta numele ​de model de colorare Lambert. +  * Utilizarea aceluiași nume pentru ​atribut în codul sursă ​al ambelor programe ​de tip shader, cum se poate vedea în continuare: 
-  Se poate calcula câte o culoare pentru fiecare vârf al unui poligon si prin interpolare intre varfuri se calculeaza culorile pixelilor rasterizati pe baza triunghiului. Acesta poarta numele de model de colorare Gouraud. +    Vertex shader: <code glsl> 
-  * Se poate calcula câte o normală ​pentru ​fiecare vârf al unui triunghi si pentru fiecare pixel se determină o normală prin interpolare între normalele din vârfuri. Astfel, se calculează o culoare pentru fiecare pixel rasterizat pe baza triunghiului în fragment ​shader. Aceasta abordare poarta numele de model de colorare Phong. +out vec3 attribute_name;​ 
- +</​code>​ 
-Rezultatele vizuale ale celor abordari se pot vedea mai jos. +    * Fragment shader: <code glsl> 
- +in vec3 attribute_name;​ 
-{{ :egc:​laboratoare:​lab07:​iluminareglsl.png?​500 |}} +</​code>​ 
- +  * Utilizarea aceleiași locații explicite ​pentru ​atribut, după cum urmează
-În acest laborator se va discuta modelul de shading Phong.+    * Vertex ​shader: <code glsl> 
 +layout(location = 3) out vec3 some_attribute;​ 
 +</​code>​ 
 +    * Fragment shader<code glsl> 
 +layout(location = 3) in vec3 the_same_attribute;​ 
 +</​code>​
  
 +<note tip>
 +Valoarea unui **atribut de intrare dintr-un program de tip fragment shader**, se obține prin **interpolare între valorile acelorași atribute de ieșire de la programele de tip vertex shader** ce au prelucrat cele 3 vârfuri care au format triunghiul rasterizat.
 </​note>​ </​note>​
-</​hidden>​ 
  
-==== Surse de lumina de tip spot ====+===== Laborator =====
  
-Pentru a simula+==== Codul sursă al programelor de tip shader ====
  
-Nu toate sursele ​de lumina sunt punctiformeDaca dorim sa implementam iluminarea folosind o sursa de lumina ​de tip spot trebuie sa tinem cont de o serie de constrangeri+În cadrul laboratorului,​ codul sursă al unui program ​de tip shader este într-un fișier dedicat special pentru fiecare tip de program în directorul cu numele ''​shaders''​Acest director se regăsește în interiorul directorului specific fiecărui laborator. Pentru laboratorul curent, fișierele codului sursă al programelor ​de tip shader se regăsește în ''​lab5/​shaders''​. Ierarhia filtrelor din mediul ​de dezvoltare Visual Studio pentru laboratorul curent poate fi vizualizată în imaginea ​de mai jos:
  
-{{ :​ppbg:​laboratoare:​spot-light.png?600 |}}+{{ :​ppbg:​laboratoare:​shaders-lab.png?250 |}}
  
-Asa cum se poate vedea si in poza pentru a implementa o sursa de lumina de tip spot avem nevoie de urmatorii parametri aditionali:​ +==== Erori de compilare sau de legare ​programelor ​de tip shader ==== 
-  * Directia ​de iluminare ​sursei ​de lumina + 
-  * Unghiul ​de taiere ​iluminarii ce controleaza deschiderea conului ​de lumina +Posibilele erori de compilare ​codului sursă pentru programele ​de tip shader se regăsesc în consolă. De exemplu, pentru codul sursă al unui program ​de tip vertex shader, ​ce conține o eroare ​de compilare după cum urmează:
-  * 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: 
 <code glsl> <code glsl>
-float cos_theta_angle = dot(-L, light_direction);​ +#version 330
-float cos_phi_angle = cos(phi_angle);​+
  
-if (cos_theta_angle > cos_phi_angle ​)+uniform mat4 Model; 
 + 
 +void main()
 { {
- // fragmentul este iluminat, astfel ca se calculeaza valoarea luminii conform modelului Phong +    vec4 pos = Model * ;
- // se calculeaza atenuarea luminii+
 } }
 +
 </​code>​ </​code>​
  
-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.+Eroarea ​de compilare ​este marcată în consolă în felul următor:
  
-<code glsl> +{{ :​ppbg:​laboratoare:​shaders-compilation-error.png?​600 |}}
-float cos_theta_angle = dot(-L, light_direction);​ +
-float cos_phi_angle = cos(phi_angle);​+
  
-// Quadratic attenuation +Textul erorii menționează la început, prin marcajul ''​0(7)'',​ că eroarea se găsește la linia 7 din codul sursă.
-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>​+Textul posibilelor erori de legare dintre două programe de tip shader apar tot în consolă.
  
-==== 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: +==== Încărcarea modelelor 3D din fișiere ====
- +
-<code cpp> +
-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));​ +
-</​code>​+
  
 +Framework-ul de laborator permite încărcarea și desenarea modelelor 3D din fișiere ce au diferite formate. De exemplu, pentru a încărca modelul unei sfere, se poate folosi:
  
 <code cpp> <code cpp>
-glm::mat4 model glm::mat4(1); +Mesh* mesh new Mesh("​sphere"​); 
-model *= transform3D::​Translate(glm::vec3(-5, 1.5f1)); +mesh->​LoadMesh(PATH_JOIN(window->props.selfDirRESOURCE_PATH::MODELS, "​primitives"​),​ "​sphere.obj"); 
-model *= transform3D::RotateOY(glm::​radians(60.0f)); +meshes[mesh->​GetMeshID()] = mesh;
-model *= trasnform3D::​Scale(glm::​vec3(0.1f));+
 </​code>​ </​code>​
  
-==== Detalii ​de implementare ====+Modelul se regăsește deja în interiorul proiectului,​ în directorul ''​assets/​models/​primitives''​. Puteți încerca să încarcați alte modele puse la dispoziție în cadrul framework-ului ​de laborator :) .
  
-  ​Calculele ​de iluminare se vor face în spatiul lumiideci î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: +<note important>​ 
-     ​* ​  ​pentru poziție: <code glsl>vec3 world_position = (model_matrix * vec4(v_position,1)).xyz;</​code>​ +Majoritatea modelelor 3D încărcate din fișiere **NU*au asociată informația ​de culoare ​în vârfuri. Din acest motivaceste modele, inclusiv modelul ​de sferă ce este utilizat în laboratorul curent ​și este vizibil ​în imaginea de mai jos, au valoarea ''​vec3(00, 0)''​ asociată ​pentru ​atributul ​de intrare specific informației vârfului de la locația 3, v_color. 
-     ​* ​  pentru ​normală: <code glsl>​vec3 world_normal = normalize( mat3(model_matrix) * v_normal );</​code>​ +</note>
-  * Vectorul normal N trebuie renormalizat in fragment shader, deoarece dupa procesul ​de interpolare,​ lungimea lui nu se pastreaza: <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 priveste observatorul V: <code glsl>​vec3 V = normalize( eye_position - world_position );</code>+
  
-<​note ​tip+===== Cerințe laborator ===== 
-Funcții GLSL utile care pot fi folosite pentru implementarea modelului de iluminare +<​note ​important
-  * normalize(V) – normalizează vectorul V  +Inițial, execuția laboratorului 5, fără rezolvarea niciunei cerințe, va aduce după sine o eroare ​de execuție. Este normaldeoarece utilizăm un program de tip shader ce nu fost compilat ​și legat cu succes :. După rezolvarea cerinței 1, de mai jos, eroarea ​de execuție va dispărea.
-  * 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 +
-  * 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>​
 +  - 0.05p - Completați metoda ''​CreateShader()''​ pentru a crea un program de tip shader.
 +  - 0.05p - Completați metoda ''​RenderMesh()''​ pentru a transmite atributele de tip uniform la cele două programe de tip shader. Atributele transmise sunt matricile utilizate pentru transformarea de modelare, vizualizare și proiecție.
 +  - 0.05p - Completați codul sursă al programelor de tip shader:
 +    - Completați codul sursă al programului de tip vertex shader, din fișierul ''​LabShader.VS.glsl'',​ ce se regăsește în interiorul directorului ''​shaders'':​
 +      * Se declară atributele de intrare pentru programul de tip vertex shader folosind layout location <code glsl>
 +layout(location = 0) in vec3 v_position;
 +// same for the rest of the attributes ( check Lab5.cpp CreateMesh() );
 +</​code>​
 +      * Se declară atributele de ieșire către programul de tip fragment shader <code glsl>
 +out vec3 color;
 +// same for other attributes
 +</​code>​
 +      * Se salvează valorile pentru atributele de ieșire, în ''​main()''​ <code glsl>
 +color = v_color;
 +// same for other attributes
 +</​code>​
 +      * Se calculează poziția în spațiul de decupare a vârfului primit folosind matricile Model, View, Projection <code glsl>
 +gl_Position = Projection * View * Model * vec4(v_position,​ 1.0);
 +</​code>​
 +    - Completați codul sursă al programului de tip fragment shader, din fișierul ''​LabShader.FS.glsl''​ ce se regăsește în interiorul directorului ''​shaders'':​
 +      * Se primesc valorile atributelor trimise de la programul de tip vertex shader <code glsl>
 +in vec3 color;
 +</​code>​
 +      * Se calculează atributul de ieșire al programului de tip fragment shader, ce reprezentă culoarea pixelului <code glsl>
 +out_color = vec4(color, 1);
 +</​code>​
 +      * Până în acest punct, rezultatul pe care ar trebui să îl obțineti este următorul: {{ :​ppbg:​laboratoare:​shaders-result.png?​600 |}}
 +        * Sfera din colorată în culoarea neagră deoarece geometria ei a fost încărcată dintr-un fișier text ce nu conține informație de culoare asociată în vârfuri
 +  - 0.05p - Trimiteți timpul aplicației (opținut cu metoda ''​Engine::​GetElapsedTime()''​),​ și creați o animație de pulsație a obiectelor prin modificarea scării lor după o funcție de timp (trigonometrică etc.)
 +  - 0.05p - Pe baza timpului aplicației,​ trimis anterior, modificați culoarea (unul sau mai multe canale de culoare) după o funcție de timp (trigonometrică etc.)
 +  - 0.05p - Pe baza timpului aplicației,​ creați o animație de oscilație de-a lungul axei OY **globală**,​ după o funcție de timp (trigonometrică etc.) pentru cubul din partea dreaptă
 +    * Pentru desenarea cubului din dreapta, utilizați programul de tip shader denumit ''"​LastTask"''​.
 +    * Completați codul sursă al programelor de tip shader din fișierele ''​LastTask.VS.glsl''​ și ''​LastTask.FS.glsl'',​ conform cerinței 3.
 +    * Pe baza timpului aplicației,​ modificați coordonatele vârfurilor de-a lungul axei OY globală.
  
-===== Cerinte laborator =====+Bonus: Creați o animație de deformare la nivel de vârfuri, diferită pentru fiecare vârf, similar cu animația vizibilă mai jos :) . Creați fișierele pentru un al treilea program de tip shader și utilizați-l pentru desenarea geometriei sferei din stânga. Realizați animatia pe geometria sferei. Pentru a asocia culori vârfurilor,​ puteți utiliza informația de poziție în spațiul obiect pentru culoarea pixelilor.
  
-<note tip> +{{ :​ppbg:​laboratoare:​shaders-bonus.gif?600 |}}
-Prin apasarea tastelor **W**, **A**, **S**, **D**, **E** si **Q** puteti controla pozitia unei surse de luminaPrin apasarea tastei **F** puteti interschimba intre controlul a doua surse de lumina, una punctiforma si cealalta de tip spot. +
-</​note>​+
  
-  - 0.05p - Trimiteti toate informatiile necesare calcularii iluminarii in atribute de tip uniform. 
-  - 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 {{ :​ppbg:​laboratoare:​illumination.png?​600 |}} 
-  - 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 
-  - 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.1700091502.txt.gz · Last modified: 2023/11/16 01:38 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