This shows you the differences between two versions of the page.
ppbg:laboratoare:02 [2024/09/23 16:55] andrei.lambru [Banda grafică] |
ppbg:laboratoare:02 [2024/10/16 22:07] (current) andrei.lambru |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laboratorul 02 ====== | ====== Laboratorul 02 ====== | ||
+ | |||
+ | <note important> | ||
+ | Framework-ul de laborator are o proiectare modulară, unde fiecare clasă specifică unui laborator poate fi executată individual. Pentru a specifica ce laborator să fie executat, trebuie să modificați fișierul ''main.cpp'', la linia 49 și să initializați clasa specifică laboratorului dorit. De exemplu, pentru inițializarea laboratorului 2, codul arată în felul următor: | ||
+ | <code cpp> | ||
+ | World *world = new lab::Lab2(); | ||
+ | </code> | ||
+ | </note> | ||
===== Banda grafică ===== | ===== Banda grafică ===== | ||
- | Reprezinta succesiunea de pasi ce sunt realizati pentru crearea imaginii unui cadru. | + | //**Banda grafică** reprezintă secvența de pași ce sunt realizați pentru crearea imaginii unui cadru.// |
<note tip> | <note tip> | ||
- | Conceptul de banda vine din contextul unei **benzi de asamblare** pentru diferite industrii. Similar conceptului de banda de asamblare a unei masini, in care de-a lungul mai multor pasi, la final se creeaza masina, eventual fara finisaje, //banda grafica reprezinta sunccesiunea de pasi care produce la final imaginea unui cadru//. | + | Conceptul de //bandă// vine din contextul unei **benzi de asamblare** pentru diferite industrii. |
+ | |||
+ | Similar conceptului de bandă de asamblare a unei mașini, schițat în imaginea de mai jos, în care de-a lungul mai multor pași, la final rezultă o mașină aproape de forma ei finală, banda grafică reprezintă sunccesiunea de pași care produce la final imaginea unui cadru. Procesul de desenare se încheie la finalul benzii, dar asemănător cu procesul de creare a unei mașini, care mai necesită o serie de pași ulteriori, aplicația mai realizează câteva procese conexe pentru încheierea cadrului. | ||
+ | |||
+ | De altfel, traducerea în limba engleză a benzii grafice este **graphics pipeline**, ceea ce este similar cu traducerea în limba engleză pentru banda sau linia de asamblare, respectiv //assembly line//. | ||
{{ :ppbg:laboratoare:assembly-line.png?600 |}} | {{ :ppbg:laboratoare:assembly-line.png?600 |}} | ||
</note> | </note> | ||
+ | |||
+ | In continuarea acestui laborator, vom studia doar unul dintre pașii benzii grafice, ce poartă numele de proces de **rasterizare**. | ||
===== Rasterizatorul ===== | ===== Rasterizatorul ===== | ||
Line 19: | Line 32: | ||
<note tip> | <note tip> | ||
- | Noi vom studia, în primele 3 laboratoare de la această materie, procesul de desenare pe ecran a unei topologii descrise sub forma unei rețele de triunghiuri. Acest proces cuprinde mai mulți pași. Secvența de pași utilizați în desenarea pe ecran a unei rețele de triunghiuri poartă numele de **bandă grafică** sau, cum este cunoscută în limba engleză, **rendering pipeline**. | + | Noi vom studia, în următoarele 3 laboratoare de la această materie, procesul de desenare pe ecran a unei topologii descrise sub forma unei rețele de triunghiuri. Acest proces cuprinde mai mulți pași. |
+ | |||
+ | <hidden> | ||
+ | Secvența de pași utilizați în desenarea pe ecran a unei rețele de triunghiuri poartă numele de **bandă grafică** sau, cum este cunoscută în limba engleză, **rendering pipeline**. | ||
+ | </hidden> | ||
</note> | </note> | ||
Line 33: | Line 50: | ||
<note tip> | <note tip> | ||
- | În laboratorul 7 vom studia o abordare cu care se poate preciza informația la nivel de pixel. | + | În laboratorul 8 vom studia o abordare cu care se poate preciza informația la nivel de pixel. |
</note> | </note> | ||
- | În situația în care toate cele 3 vârfuri ale unui triunghi au aceeași culoare, toți pixelii ce se regăsesc în interiorul triunghiului au aceeași culoare. În situatia în care varfurile au culori diferite, culoarea unui pixel se calculează prin interpolare, pe baza distanței față de fiecare vârf. Un exemplu vizual se poate găsi în imaginea de mai jos, unde vârful de sus are culoarea albastră, vârful din stânga jos, culoarea roșie și vârful din dreapta jos culoarea verde. Se poate vedea că, un pixel cu cât este mai apropiat de un anumit vârf, cu atât are o nuanță de culoare mai apropiată de cea a vârfului respectiv. | + | În situația în care toate cele 3 vârfuri ale unui triunghi au aceeași culoare, toți pixelii ce se regăsesc în interiorul triunghiului au aceeași culoare. În situatia în care vârfurile au culori diferite, culoarea unui pixel se calculează prin interpolare, pe baza distanței față de fiecare vârf. Un exemplu vizual se poate găsi în imaginea de mai jos, unde vârful de sus are culoarea albastră, vârful din stânga jos, culoarea roșie și vârful din dreapta jos culoarea verde. Se poate vedea că, un pixel cu cât este mai apropiat de un anumit vârf, cu atât are o nuanță de culoare mai apropiată de cea a vârfului respectiv. |
{{ :ppbg:laboratoare:rasterizer-2.jpg?300 |}} | {{ :ppbg:laboratoare:rasterizer-2.jpg?300 |}} | ||
Line 46: | Line 63: | ||
Vom propune, suplimentar, ca pe lângă coordonate 2D ''(x, y)'', fiecare vârf al unui triunghi să aibă și o coordonată de adâncime ''(z)''. Această coordonată nu este folosită pentru a stabili dacă un pixel se regăsește în interiorul unui triunghi, dar este folosită pentru rezolvarea problemei în care suprafețele a două triunghiuri se suprapun între ele. | Vom propune, suplimentar, ca pe lângă coordonate 2D ''(x, y)'', fiecare vârf al unui triunghi să aibă și o coordonată de adâncime ''(z)''. Această coordonată nu este folosită pentru a stabili dacă un pixel se regăsește în interiorul unui triunghi, dar este folosită pentru rezolvarea problemei în care suprafețele a două triunghiuri se suprapun între ele. | ||
- | Pentru a rezolva această situație, trebuie să avem o ordine de afișare. Presupunem că o valoare de adâncime (z) mai mică determină afișarea peste o valoare de adâncime mai mică. Banda grafică hotărăște dacă 2 triunghiuri se pot rasteriza concomitent. Pentru simplitate vom considera că se desenează secvențial exact 2 triunghiuri ce se suprapun. | + | Pentru a rezolva această situație, trebuie să avem o ordine de afișare. Presupunem că o valoare de adâncime (z) mai mică determină afișarea peste o valoare de adâncime mai mare. Banda grafică hotărăște dacă 2 triunghiuri se pot rasteriza concomitent. Pentru simplitate vom considera că se desenează secvențial exact 2 triunghiuri ce se suprapun. |
- Primul triunghi este rasterizat în totalitate. Pentru fiecare pixel ce se află în interiorul lui, se calculează coordonata de adâncime, prin interpolare între, similar cu abordarea de mai sus, utilizată pentru calcularea culorii. Această coordonată se pastrează într-o grilă separată față de cea utilizata pentru a păstra pixelii. | - Primul triunghi este rasterizat în totalitate. Pentru fiecare pixel ce se află în interiorul lui, se calculează coordonata de adâncime, prin interpolare între, similar cu abordarea de mai sus, utilizată pentru calcularea culorii. Această coordonată se pastrează într-o grilă separată față de cea utilizata pentru a păstra pixelii. | ||
- În momentul în care se rasterizează triunghiul 2, și se stabilește un pixel ce se află în interiorul acestui triunghi, se calculează coordonata de adâncime pentru pixel și se compară cu valoarea ce se află la aceeași locație în grila de valori de adâncime. | - În momentul în care se rasterizează triunghiul 2, și se stabilește un pixel ce se află în interiorul acestui triunghi, se calculează coordonata de adâncime pentru pixel și se compară cu valoarea ce se află la aceeași locație în grila de valori de adâncime. | ||
Line 69: | Line 86: | ||
</code> | </code> | ||
- | Structura de date ''VertexFormat'' conține mai multe informații pentru fiecare vârf. În constructorul ei, primii 2 parametri transmiși sunt poziția (x, y, z), cu (x, y) în grila de pixeli și coordonata (z) cu valori între 0 si 1, respectiv al doilea parametru este culoarea în modelul de culoare rgb, unde fiecare canal are valorile între 0 și 1. Astfel, culoarea roșie este definită ca (1, 0, 0), culoarea verde (0, 1, 0), culoarea cyan (0, 1, 1). | + | Structura de date ''VertexFormat'' conține mai multe informații pentru fiecare vârf. În constructorul ei, primii 2 parametri transmiși sunt poziția (x, y, z), cu (x, y) în grila de pixeli și coordonata (z) cu valori între 0 și 1, respectiv al doilea parametru este culoarea în modelul de culoare rgb, unde fiecare canal are valorile între 0 și 1. Astfel, culoarea roșie este definită ca (1, 0, 0), culoarea verde (0, 1, 0), culoarea cyan (0, 1, 1). |
- | <note tip> | + | A doua structură de date utilizată pentru descrierea rețelei de triunghiuri este o mulțime ordonată de indici ai vârfurilor din prima structură de date: |
- | Structura de date ''glm::vec3'' reprezintă un vector de 3 dimensiuni (x, y, z). Aceasta face parte din biblioteca [[ https://glm.g-truc.net/0.9.9/ | glm ]], inclusă în framework-ul de laborator. Componentele individuale ale vectorului, x, y și z, pot fi accesate în felul următor: | + | |
- | + | ||
- | <code cpp> | + | |
- | glm::vec3 position = glm::vec3 (10.0f, 10.0f, 0.1f); | + | |
- | + | ||
- | float x = position.x; | + | |
- | float y = position.y; | + | |
- | float z = position.z; | + | |
- | </code> | + | |
- | </note> | + | |
- | + | ||
- | A doua structura de date utilizată pentru descrierea rețelei de triunghiuri este o mulțime ordonată de indici ai vârfurilor din prima structură de date: | + | |
<code cpp> | <code cpp> | ||
Line 103: | Line 108: | ||
Abordarea propusă pentru implementare, în acest laborator, este următoarea: | Abordarea propusă pentru implementare, în acest laborator, este următoarea: | ||
- | * Se parcurg pe rând toți pixelii din dreptunghiul incadrator al triunghiului | + | * Se parcurg pe rând toți pixelii din dreptunghiul încadrator al triunghiului |
* În situația în care centrul pixelului se află în interiorul triunghiului | * În situația în care centrul pixelului se află în interiorul triunghiului | ||
* Se calculează informația de adâncime a pixelului prin interpolare între vârfuri | * Se calculează informația de adâncime a pixelului prin interpolare între vârfuri | ||
Line 114: | Line 119: | ||
Din acest motiv, o grilă de pixeli de rezoluție 1280x720, are ultima coloană egală cu 1279 și ultima linie egală cu 719. Observăm că rezoluția unei grile este dată mai întâi de lățime, ce reprezintă numărul de coloane și apoi de înălțime, ce reprezintă numărul de linii. | Din acest motiv, o grilă de pixeli de rezoluție 1280x720, are ultima coloană egală cu 1279 și ultima linie egală cu 719. Observăm că rezoluția unei grile este dată mai întâi de lățime, ce reprezintă numărul de coloane și apoi de înălțime, ce reprezintă numărul de linii. | ||
</note> | </note> | ||
- | |||
- | === Punct în interiorul unui triunghi === | ||
- | |||
- | Pentru a verifica dacă un punct se află în interiorul unui triunghi, se pot folosi ariile triunghiului și cele ale triunghiurilor formate de punct cu perechi de vârfuri din triunghi. În imaginea de mai jos se pot vedea aceste suprafețe. | ||
- | |||
- | {{ :ppbg:laboratoare:rasterizer-3.png?200 |}} | ||
- | |||
- | Astfel, în situația în care suma ariilor triunghiurilor interioare este egală cu aria triunghiului, punctul se află în interior. | ||
- | |||
- | |||
- | $$ | ||
- | A_{\Delta V_1 V_2 V_3} = A_{\Delta P V_1 V_3} + A_{\Delta P V_1 V_2} + A_{\Delta P V_2 V_3} | ||
- | $$ | ||
- | |||
- | Deoarece ariile sunt calculate cu tipuri de date în virgulă mobilă, nu se poate folosi direct comparația de egalitate și trebuie să ne asumăm un anumit nivel de eroare în calcule. Astfel, în cod, comparația va fi în felul următor: | ||
- | |||
- | <code cpp> | ||
- | const float EPSILON = 5.0f; | ||
- | |||
- | bool inside_triangle = abs(area_v1v2v3 - (area_pv1v3 + area_pv1v2 + area_pv2v3)) < EPSILON; | ||
- | </code> | ||
- | |||
- | === Aria unui triunghi oarecare === | ||
- | |||
- | Pentru calcularea ariei unui triunghi oarecare, se poate folosi formula lui Heron: | ||
- | |||
- | |||
- | |||
- | $$ | ||
- | |||
- | |||
- | A_{\Delta V_1 V_2 V_3} = \sqrt{s \cdot (s-a) \cdot (s-b) \cdot (s-c)} \\ | ||
- | s = \frac{1}{2} \cdot (a+b+c) \\ | ||
- | |||
- | a=\lVert V_1-V_2 \rVert \\ | ||
- | b=\lVert V_1-V_3 \rVert \\ | ||
- | c=\lVert V_2-V_3 \rVert \\ | ||
- | $$ | ||
- | |||
- | Pentru a calcula norma unui vector $\lVert\vec{V_1V_2}\rVert=\lVert V_1-V_2 \rVert$, se poate folosi biblioteca glm în felul următor: | ||
- | |||
- | <code cpp> | ||
- | float norm_vec12 = glm::length(v1 - v2); | ||
- | </code> | ||
=== Interpolarea informației din vârfuri === | === Interpolarea informației din vârfuri === | ||
Line 204: | Line 165: | ||
<note tip> | <note tip> | ||
- | Se poate observa că fiecare din cele două triunghiuri se află parțial în spate și parțial în fața celuilalt. Acest rezultat este obținut deoarece triunghiul ce are în vârfuri culorile roșu, verde și albastru are toate coordonatele de adâncime egale cu 0.5, iar triunghiul ce are în vârfuri culorile galben, magenta și cyan, are coordonata de adâncime a vârfului de culoare cyan egală cu 1 și coordonatele de adâncime a celorlalte 2 vârfuri egale cu 0. Din acest motiv, apare efectul de întretăiere a celor două triunghiuri. | + | Se poate observa că fiecare din cele două triunghiuri se află parțial în spate și parțial în fața celuilalt. Acest rezultat este obținut deoarece triunghiul ce are în vârfuri culorile roșu, verde și albastru are toate coordonatele de adâncime egale cu 0.5, iar triunghiul ce are în vârfuri culorile galben, magenta și cyan, are coordonata de adâncime a vârfului de culoare cyan egală cu 0 și coordonatele de adâncime a celorlalte 2 vârfuri egale cu 1. Din acest motiv, apare efectul de întretăiere a celor două triunghiuri. |
</note> | </note> | ||