This shows you the differences between two versions of the page.
ppbg:laboratoare:02 [2024/09/23 20:28] andrei.lambru |
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ă ===== | ||
Line 16: | Line 23: | ||
</note> | </note> | ||
- | In continuarea acestui laborator, vom studia doar unul dintre pasii benzii grafice, ce poarta numele de proces de **rasterizare**. | + | In continuarea acestui laborator, vom studia doar unul dintre pașii benzii grafice, ce poartă numele de proces de **rasterizare**. |
===== Rasterizatorul ===== | ===== Rasterizatorul ===== | ||
Line 25: | 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. | + | 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> | <hidden> | ||
Line 43: | 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 56: | 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 79: | 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 113: | 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 124: | 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 214: | 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> | ||