This shows you the differences between two versions of the page.
ppbg:laboratoare:03 [2023/10/26 14:25] andrei.lambru [Transformarea de vizualizare] |
ppbg:laboratoare:03 [2024/10/24 12:36] (current) andrei.lambru |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laboratorul 03 ====== | ====== Laboratorul 03 ====== | ||
- | <note tip> | + | <note important> |
- | Pentru rezolvarea cerințelor din acest laborator, aveți nevoie de codul utilizat în rezolvarea cerințelor din cadrul laboratorului 1 și a laboratorului 2. În situatia în care nu ați rezolvat [[:ppbg:laboratoare:01|laboratorul 1]] sau [[:ppbg:laboratoare:02|laboratorul 2]], va trebui să le realizați mai întâi pe ele și ulterior să reveniți la cerințele celui curent. | + | Pentru rezolvarea cerințelor din acest laborator, aveți nevoie de codul utilizat în rezolvarea cerințelor din cadrul laboratorului 2. În laboratoarele 3 și 4, vom reutiliza acest cod. În situatia în care nu ați rezolvat [[:ppbg:laboratoare:02|laboratorul 2]], va trebui sa îl realizați mai întâi pe el și ulterior să reveniți la cerințele celui curent. |
- | + | ||
- | **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> | ||
<note tip> | <note tip> | ||
- | **Pentru rezolvarea cerințelor din cadrul acestui labroator și a tuturor celor ce vor urma, până la finalul semestrului** | + | **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 :) . |
- | + | ||
- | - [[https://github.com/UPB-Graphics/gfx-framework-ppbg | Descărcați]] framwork-ul de laborator și copiați, din arhiva descărcată, directorul **Lab3**, î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/lab3/lab3.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. | + | |
- | + | ||
- | Acest proces va fi necesar pentru fiecare din următoarele laboratoare, cu utilizarea numărului laboratorului pe care doriți să îl specificați :) . | + | |
</note> | </note> | ||
- | ===== Lanțul de transformări 3D ===== | + | ===== Transformări în spații 2D ===== |
- | În laboratorul anterior, am văzut cum putem desena obiecte pe ecran, independent de spațiul în care am definit coordonatele vârfurilor unui obiect. Mai precis, am folosit un spațiu logic, pe care l-am denumit fereastră peste spațiul 2D și în care am definit inițial coordonatele vârfurilor. Prin utilizarea transformării fereastră-poartă, am putut desena obiectele într-o poartă de afișare de pe ecran, la orice rezoluție de pixeli a acestei porți. De asemenea, am văzut cum se pot prelucra obiectele prin diferite transformări. În laboratorul anterior, am analizat doar 3 tipuri transformări de bază: translație, modificare de scară și rotație. | + | În laboratorul anterior, am văzut cum se poate desena un triunghi pe ecran, dacă avem la dispoziție informația necesară pentru fiecare vârf: coordonatele în spațiul 2D, valoarea de adâncime și o culoare. Cu toate acestea, un astfel de sistem nu este suficient de flexibil, deoarece, în cadrul unei aplicații grafice în timp real, dorim să realizăm animații cu un model 3D, reprezentat de o rețea de triunghiuri. Coordonatele inițiale ale triunghiurilor trebuie modificate pentru a realiza o animație. //Realizarea aceleeași modificări, sau transformări, pentru toate vârfurile unei rețele de triunghiuri, produce, din punct de vedere vizual, efectul de aplicare a modificării pentru întreg ansamblul, respectiv pentru tot modelul 3D.// |
- | ===== Spațiul de decupare ===== | + | Din acest motiv, de-a lungul timpului, au fost standardizate mai multe tipuri de modificări asupra informației unui vârf, în particular asupra coordonatelor lui, ce pot fi utilizate în vederea realizării animațiilor. |
- | Lucrul cu un spațiu 3D nu este cu mult diferit față de lucrul cu un spațiu 2D. Pentru desenarea pe ecran a unor obiecte dintr-un spațiu 3D, este necesar să ne stabilim un spațiu logic, din care să transformăm coordonatele vârfurilor în coordonatele grilei de pixeli. În grafica pe calculator, spațiul standard ales pentru acest proces este volumul unui cub, cu latura de dimensiune 2 și centrat în originea axelor de coordonate. Astfel, colțul stânga-jos-față al cubului are coordonatele (-1, -1, -1) și colțul dreapta-sus-spate are coordonatele (1, 1, 1). O reprezentare vizuală a acestui volum se poate găsi în imaginea următoare: | + | ==== Transformarea de translație (deplasare) ==== |
- | {{ :ppbg:laboratoare:clip_space.png?300 |}} | + | Transformarea cea mai de bază este cea utilizată pentru deplasarea unui vârf de la poziția inițială, la o altă poziție în spațiu. Acest proces se realizează prin deplasarea coordonatelor unui vârf cu un anumit vector de deplasare și poartă numele de translație sau translatare. |
- | + | ||
- | Coordonatele vârfurilor ce se regăsesc în acest volum pot fi aduse în grila de pixeli printr-o transformare fereastră-poartă, similar ca săptămâna trecută: | + | |
+ | În imaginea de mai jos, în partea dreaptă, se poate observa rezultatul translației pătratului din partea stângă cu vectorul de translație $\vec{t}=\begin{bmatrix} | ||
+ | 2 & 1 | ||
+ | \end{bmatrix}$ . | ||
+ | {{ :ppbg:laboratoare:translation1.png?600 |}} | ||
+ | Formula pentru realizarea procesului de translație este: | ||
$$ | $$ | ||
- | \begin{bmatrix} | + | x'=x+t_x\\ |
- | x' \\ y' \\ z' \\ 1 | + | y'=y+t_y |
- | \end{bmatrix} = | + | |
- | \begin{bmatrix} | + | |
- | 1 & 0 & 0 & V_{x}\\ | + | |
- | 0 & 1 & 0 & V_{y}\\ | + | |
- | 0 & 0 & 1 & 0\\ | + | |
- | 0 & 0 & 0 & 1 | + | |
- | \end{bmatrix} | + | |
- | \begin{bmatrix} | + | |
- | V_{w}/2 & 0 & 0\\ | + | |
- | 0 & V_{h}/2 & 0\\ | + | |
- | 0 & 0 & 1/2 & 0\\ | + | |
- | 0 & 0 & 0 & 1 | + | |
- | \end{bmatrix} | + | |
- | \begin{bmatrix} | + | |
- | 1 & 0 & 0 & -1\\ | + | |
- | 0 & 1 & 0 & -1\\ | + | |
- | 0 & 0 & 1 & -1\\ | + | |
- | 0 & 0 & 0 & 1 | + | |
- | \end{bmatrix} | + | |
- | + | ||
- | \begin{bmatrix} | + | |
- | x \\ y \\ z \\ 1 | + | |
- | \end{bmatrix} | + | |
$$ | $$ | ||
- | <note tip> | + | ==== Transformarea de modificare a scării ==== |
- | În cuvinte, se normalizează coordonatele vârfurilor din spațiul ([-1, 1], [-1, 1], [-1, 1]) în spațiul ([0, viewport_width], [0, viewport_height], [0,1]). | + | |
- | </note> | + | |
- | Observăm că se proiecteaza paralel coordonatele vârfurilor pe fața z=-1 a cubului. Practic, se păstreaza componentele (x, y) ale coordonatelor din vârfuri și putem să consideram că pentru componentele (x, y) se utilizează o transformare fereastră-poartă dintr-o fereastră peste spatiul 2D. | + | O altă transformare, ce poate fi utilizată în realizarea animațiilor, este modificarea scării unui obiect, respectiv mărirea sau micșorarea obiectului. |
- | Pentru componenta z, din moment ce nu se poate transforma direct în coordonatele grilei de pixeli, se normalizează între 0 și 1 și se utilizează cu scopul de valore de adâncime în procesul de rasterizare studiat în [[:ppbg:laboratoare:01#testul_de_adancime | laboratorul 1]] :) . | + | În imaginea de mai jos, în partea dreaptă, se poate observa rezultatul modificării scării pentru pătratul din partea stângă, cu vectorul de scară $\vec{s}=\begin{bmatrix} |
+ | 2 & 2 | ||
+ | \end{bmatrix}$ . | ||
- | ==== Procesul de decupare ==== | + | {{ :ppbg:laboratoare:scale1.png?600 |}} |
- | Pe ecran ajung să fie desenate doar suprafețele dintr-un triunghi ce se regăsesc în volumul cubului de latură 2, centrat în originea axelor de coordonate. Cu toate acestea, este posibil ca nu toată suprafața unui triunghi să se afle în volumul cubului, astfel că în procesul de rasterizare trebuie să se realizeze procesări suplimentare pentru a nu se desena în afara grilei de pixeli. Pentru a evita realizarea acestor calcule, putem decupa triunghiurile la limitele volumului și să utilizam în procesul de rasterizare doar triunghiurile rezultate în urma decupării. Acest mecanism poate genera de la 0 sau pana la 3 triunghiuri. Scenariile în care sunt rezultate 1, 2 și 3 triunghiuri pot fi observate în imaginea de mai jos. | ||
- | {{ :ppbg:laboratoare:clip.png?400 |}} | + | Formula pentru realizarea procesului de modificare a scării este: |
- | Cele 1, 2 sau 3 triunghiuri, rezultate după procesul de decupare, sunt utilizate în procesul de rasterizare. Exemplificarea din imagine este pentru o decupare 2D, dar ea se poate extinde la volumul unui cub, în care un triunghi se decupează la limitele volumului, în spațiul 3D. | + | $$ |
+ | x'=s_x \cdot x\\ | ||
+ | y'=s_y \cdot y | ||
+ | $$ | ||
- | Mai există un scenariu suplimentar, ce nu este acoperit în imagine, anume situația în care nicio parte din suprafața triunghiului nu se regăsește în interiorul volumului. În acest scenariu, nu este transmisă nicio primitivă în procesul de rasterizare. | + | ==== Transformarea de rotație ==== |
- | <note> | + | Ultima transformare des intalnită în grafica pe calculator este rotația unui model. Pentru realizarea acestui proces, pentru spații 2D, vom utiliza un aparat matematic care se aplică în felul următor: //rotația unui triunghi se realizeaza prin rotația tuturor vârfurilor, în sens trigonometric, față de originea axelor de coordonate//. |
- | Datorită faptului că acest proces de decupare are loc în spațiul finit descris mai sus, determinat de un cub de latură 2, centrat în originea axelor de coordonate, acest spațiu poartă numele de **spațiu de decupare**. El este cunoscut în limba engleză sub numele de **clip space**. | + | |
- | </note> | + | |
- | ===== Transformarea de proiecție perspectivă ===== | + | Un exemplu pentru această transformare se poate vedea în imaginea de mai jos, unde pătratul este rotit cu 45 de grade, în sens trigonometric, față de punctul v0, care este în originea axelor de coordonate. |
- | Definirea unui spațiu finit pe care să îl normalizăm ulterior în grila de pixeli ne oferă o flexibilitate foarte mare. Dezavantajul aplicării directe a acestei abordări este că geometria obiectelor nu se regăsește întotdeauna în interiorul volumului de decupare. De fapt, de cele mai multe ori, obiectele nu se află în acest volum. Astfel, trebuie să aducem noi geometria în acesta printr-o transformare suplimentară. Această transformare poate să fie o transformare de proiecție perspectivă pentru a simula procesul de transport al luminii de pe suprafețele scenei la observator. Tot ce "vede" ochiul uman este lumina, astfel că procesul de desenare a suprafețelor unui obiect pe ecran, simulează procesul de achiziție a luminii care ajunge de pe suprafețele obiectului la ochiul uman :) . Pentru simplitate, vom considera un singur punct de convergență pentru simularea razelor de lumină. Astfel, putem să folosim o transformare perspectivă a coordonatelor vârfurilor pentru a aduce geometria în spațiul de decupare și ulterior pentru a o desena pe ecran. | + | {{ :ppbg:laboratoare:rotation1.png?600 |}} |
- | Volumul proiecției perspectivă este un trunchi de piramidă, frustum. Standard, acest volum este descris cu vârful în originea axelor de coordonate și cu baza orientată de-alungul axei Z, în sens negativ. Acest volum se normalizează în volumul spațiului de decupare. O reprezentare vizuală a lui se găsește în imaginea de mai jos. | + | Formula pentru această transformare este: |
- | {{ :ppbg:laboratoare:perspective.png?500 |}} | + | $$ |
+ | x'=x \cdot cos(\theta)-y \cdot sin(\theta)\\ | ||
+ | y'=x \cdot sin(\theta)+y \cdot cos(\theta) | ||
+ | $$ | ||
- | Avem mai multe posibilități de a descrie forma acestui volum, dar în continuare va fi prezentată cea care apare uzual în grafica pe calculator. Pentru descrierea frustumului folosim: | + | <note> |
- | * Distanța până la un plan apropiat, pe care se va normaliza fața z=-1 a spațiului de decupare (**near**) | + | Această formula reiese din următorul fapt. Conform imaginii de mai jos, avem punctul V, pe care dorim sa îl rotim cu unghiul B, în sens trigonometric, față de originea axelor de coordonate pentru a obține punctul V'. |
- | * Distanța până la un plan îndepartat, pe care se va normaliza fața z=1 a spațiului de decupare (**far**) | + | |
- | * Un unghi pentru deschiderea verticală a piramidei (**fovy**) | + | |
- | * Un raport de aspect al porții de afișare, lățime / înălțime, cu ajutorul căruia se poate obține unghiul de deschidere orizontală a piramidei (**aspect**) | + | |
- | Formula de calcul a proiecției perspective este: | ||
+ | {{ :ppbg:laboratoare:rotation2.png?200 |}} | ||
+ | Componentele x și y ale coordonatei lui V se pot scrie și sub forma: | ||
$$ | $$ | ||
- | x' = \frac{x}{ -z \cdot tan(\frac{fovy}{2}\cdot aspect)}\\ | + | x=r \cdot cos(\alpha)\\ |
- | y' = \frac{y}{ -z \cdot tan(\frac{fovy}{2})}\\ | + | y=r \cdot sin(\alpha) |
- | z' = \frac{c2\cdot z-c1}{-z}\\ c1=\frac{(-2) \cdot far \cdot near}{far- near}\\ c2=\frac{(-1)\cdot(far+near)}{far - near} | + | |
$$ | $$ | ||
+ | |||
+ | De asemenea, componentele x' și y' ale coordonatei lui V' se pot scrie sub forma: | ||
- | Această formula nu poate fi scrisă sub formă matriceală, deoarece este un sistem de ecuații neliniare. După cum vedem, în calcularea componentelor (x', y', z') ale coordonatei obținute în urma transformării de proiecție perspectivă, se utilizează valoarea componentei z a coordonatei pentru care se aplică transformarea. Din acest motiv, este necesar să realizam acest proces în 2 pași: | ||
- | - Se creează o matrice pentru tranformarea de proiecție perspectivă prin care se aplică formula de mai sus, fără împărțirea componentelor coordonatei rezultate în urma transformării la valoarea componentei z a coordonatei pentru care s-a realizat transformarea. Se utilizează această matrice pentru transformarea de proiecție perspectivă $$ | ||
- | \begin{bmatrix} | ||
- | {x}'\\ | ||
- | {y}'\\ | ||
- | {z}'\\ | ||
- | {w}' | ||
- | \end{bmatrix} = \begin{bmatrix} | ||
- | \frac{1}{tan(\frac{fovy}{2}\cdot aspect)} & 0 & 0 & 0 \\ | ||
- | 0 & \frac{1}{tan(\frac{fovy}{2})} & 0 & 0 \\ | ||
- | 0 & 0 & \frac{(-1)\cdot (far+near)}{far - near} & \frac{(-2) \cdot far \cdot near}{far - near} \\ | ||
- | 0 & 0 & -1 & 0 | ||
- | \end{bmatrix} | ||
- | \begin{bmatrix} | ||
- | x\\ | ||
- | y\\ | ||
- | z\\ | ||
- | 1 | ||
- | \end{bmatrix} | ||
$$ | $$ | ||
- | - Împărțirea componentelor (x', y', z') cu valoarea componentei z a coordonatei vârfului pentru care s-a aplicat transformarea | + | x'=r \cdot cos(\alpha + \beta)\\ |
+ | y'=r \cdot sin(\alpha + \beta)\\ | ||
- | |||
- | |||
- | $$ | ||
- | x'' = \frac{x'}{-z}\\ | ||
- | y'' = \frac{y'}{-z}\\ | ||
- | z'' = \frac{z'}{-z} | ||
$$ | $$ | ||
- | Pentru a nu fi nevoie să se rețină apriori valoarea componentei z, care poate fi obținută în urma aplicării unui lanț de transformări, astfel că transformarea de proiecție perspectivă se poate afla în interiorul unei matrici compuse dintr-un lanț de transformări, se utilizează un artificiu. Se poate observa că matricea de mai sus este construită astfel încât să păstreze în componenta w', valoarea componentei z, negativă: | + | Continuăm prin înlocuirea sumei din funcțiile trigonometrice cu: |
$$ | $$ | ||
- | w'=0\cdot x + 0\cdot y + (-1) \cdot z + 0 \cdot 0 | + | x'=r \cdot cos(\alpha) \cdot cos(\beta)-r \cdot sin(\alpha) \cdot sin(\beta)\\ |
+ | y'=r \cdot cos(\alpha) \cdot sin(\beta)+ r\cdot sin(\alpha) \cdot cos(\beta)\\ | ||
$$ | $$ | ||
- | Din acest motiv, cel de-al doilea pas de mai sus devine: | + | În final, înlocuim cu x și y în rezultatul anterior, conform primei formule din această notă și obținem: |
$$ | $$ | ||
- | x'' = \frac{x'}{w'}\\ | + | x'=x \cdot cos(\beta)-y \cdot sin(\beta)\\ |
- | y'' = \frac{y'}{w'}\\ | + | y'=x \cdot sin(\beta)+y \cdot cos(\beta) |
- | z'' = \frac{z'}{w'} | + | |
$$ | $$ | ||
- | <note> | ||
- | Acest al doilea pas este cunoscut sub numele de **împărțire perspectivă** și este implementat nativ în banda grafică a procesorului. Observăm că această transformare este ultima care se aplică inainte de transformarea coordonatelor din vârfuri în spațiul de decupare. Din acest motiv, înainte de decuparea propriu-zisă, procesorul grafic realizează împărțirea perspectivă automat, hardware sau software în driver-ul companion al procesorului grafic. | ||
- | </note> | ||
- | <note tip> | + | |
- | Spațiul finit determinat de volumul trunchiului de piramidă ce are vârful în originea axelor de coordonate și baza orientata de-alungul axei Z, în sens negativ, poartă numele de **spațiu de vizualizare**. În limba engleză, acest spațiu se regăsește sub numele de **view space**. | + | |
</note> | </note> | ||
- | <note> | ||
- | Formula de calculare a proiecției perspective pentru coordonata unui vârf, pe planul din apropiere a trunchiului de piramidă, se obține din următoarea observație: conform imaginii de mai jos, se poate vedea că triunghiul determinat de vectorii marcați cu near și y' este asemenea cu cel determinat de vectorii marcați cu -z și y. | ||
- | {{ :ppbg:laboratoare:perspective2.png?600 |}} | + | ===== Compunerea transformărilor ===== |
- | Astfel, conform teoremei lui Thales, rezulta că: | + | Transformarile de bază, prezentate mai sus, nu sunt suficient de flexibile pentru a obține orice tip de animații prin utilizarea individuală a unui anume tip. Un exemplu este rotația față de //propriul centru// al unui pătrat de latură 1 ce a fost definit cu colțul stânga-jos în originea axelor de coordonate. O aplicare directă a transformării de rotație rezultă în rotația pătratului față de colțul stânga-jos. Din acest motiv, este necesar să obținem rezultatul dorit prin compunerea mai multor transformări. Lanțul de transformări este vizibil în imaginea de mai jos. |
- | $$ | + | {{ :ppbg:laboratoare:rotation3.png?600 |}} |
- | \frac{y'}{near} = \frac{y}{-z}\\ | + | |
- | $$ | + | Transformarea compusă este creată după cum urmează: |
+ | - Primul pas este translația pătratului, astfel încat centrul lui să se afle în originea axelor de coordonate; | ||
+ | - În acest moment, putem roti vârfurile pătratului față de centrul lui; | ||
+ | - După rotație, pătratul rămâne cu centrul în originea axelor de coordonate, astfel că aplicăm transformarea inversă de la punctul 1 pentru a readuce pătratul cu centrul în poziția lui originală. | ||
+ | . | ||
+ | <note tip> | ||
+ | Același proces se poate aplica și pentru transformarea de modificare a scării, pentru a face modificarea de scară din centrul pătratului :) . | ||
+ | </note> | ||
+ | ===== Forma matriceală a transformărilor ===== | ||
+ | Formula finală obținută în urma compunerii unui lanț de transformări poate fi complexă. De exemplu, formula finală pentru compunerea de mai sus, în care rotim un pătrat față de propriul centru, este: | ||
$$ | $$ | ||
- | + | x'=(x-0.5) \cdot cos(45)-(y-0.5) \cdot sin(45) + 0.5\\ | |
- | y'=\frac{near\cdot y}{-z}\\ | + | y'=(x-0.5) \cdot sin(45)+(y-0.5) \cdot cos(45) + 0.5 |
$$ | $$ | ||
+ | Pentru a simplifica și optimiza procesul de calcul, se folosește forma matriceală a transformărilor. Pentru acest lucru, vectorul pentru care se aplică transformarea se scrie, de asemenea, în formă matriceală. În această situație, avem 2 posibilități: | ||
+ | * Vectorul se scrie sub forma unei matrici cu **o linie și mai multe coloane**, denumit //vector linie//. | ||
+ | * Vectorul se scrie sub forma unei matrici cu **mai multe linii și o singură coloană**, denumit //vector coloană//. | ||
+ | Ambele reprezentări sunt practice, dar atrag după sine forme matriceale diferite pentru transformări. În continuare, vom lua pe rând ambele forme pentru a vedea reprezentarea lor. | ||
- | Considerăm că valoarea componentei z este negativă, deoarece o tratăm pe post de distanță și orientarea bazei trunchiului de piramidă este din constructie de-alungul axei Z, în sens negativ. | + | ==== Vector linie ==== |
- | Suplimentar, presupunem că avem distanța până la limita de jos, denumită **bottom** și distanța până la limita de sus, denumtiă **top**, a feței din apropiere a frustumului, după cum se poate vedea în imaginea de mai sus. Dorim să normalizăm componenta y din intervalul [bottom, top] în [-1, 1]. Aceasta este o transformare fereastră-poartă. Împreună cu formula anterioara pentru y', obținem că y' este: | + | Pentru fiecare din cele 3 transformări de bază de mai sus, în situația în care utilizăm un vector linie, forma matriceală este: |
- | |||
- | $$ | ||
- | y'=\frac{2\cdot near\cdot y}{-z \cdot (top-bottom)}\\ | ||
$$ | $$ | ||
+ | \begin{bmatrix} | ||
+ | {x+t_x} & {y+t_y} & 1 | ||
+ | \end{bmatrix} = | ||
+ | \begin{bmatrix} | ||
+ | x & y & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | 1 & 0 & 0\\ | ||
+ | 0 & 1 & 0\\ | ||
+ | t_x & t_y & 1 | ||
+ | \end{bmatrix} | ||
- | Din construcție avem un singur unghi de deschidere verticală a trunchiului de piramidă, astfel că avem aceeași valoare pentru limitele bottom și top: | ||
+ | $$ | ||
$$ | $$ | ||
- | bottom= -top\\ | + | \begin{bmatrix} |
- | y'=\frac{2\cdot near\cdot y}{-z \cdot 2 \cdot top}=\frac{near\cdot y}{-z \cdot top}\\ | + | {s_x \cdot x} & {s_y \cdot y} & 1 |
- | $$ | + | \end{bmatrix} = |
+ | \begin{bmatrix} | ||
+ | x & y & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | s_x & 0 & 0\\ | ||
+ | 0 & s_y & 0\\ | ||
+ | 0 & 0 & 1 | ||
+ | \end{bmatrix} | ||
- | Se poate observa că: | ||
- | |||
- | $$ | ||
- | \frac{top}{near}=tan(\frac{fovy}{2}) | ||
$$ | $$ | ||
- | Astfel, avem pentru y': | ||
- | $$ | ||
- | y' = \frac{y}{ -z \cdot tan(\frac{fovy}{2})}\\ | ||
$$ | $$ | ||
- | + | \begin{bmatrix} | |
- | Pentru simplitate și un control ridicat, în loc să se descrie volumul frustumului prin 2 valori, una care descrie unghiul de deschidere verticală și una pentru unghiul de deschidere orizontală, se utilizează raportul de aspect al ecranului: | + | {x \cdot cos(\theta)-y \cdot sin(\theta)} & {x \cdot sin(\theta)+y \cdot cos(\theta)} & 1 |
+ | \end{bmatrix} = | ||
+ | \begin{bmatrix} | ||
+ | x & y & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | cos(\theta) & sin(\theta) & 0\\ | ||
+ | -sin(\theta) & cos(\theta) & 0\\ | ||
+ | 0 & 0 & 1 | ||
+ | \end{bmatrix} | ||
$$ | $$ | ||
- | aspect = \frac{V_{w}}{V_h}=\frac{fovx}{fovy}\\ | + | <note> |
- | fovx=aspect \cdot fovy\\ | + | Se poate observa că doar transformarea de translație necesită o matrice de dimensiune 3x3, iar pentru celelalte 2 transformări sunt necesare matrici de dimensiune 2x2. Sunt 2 motive principale pentru care se utilizează matrici de 3x3 pentru toate transformările: |
- | x' = \frac{x}{ -z \cdot tan(\frac{fovy}{2}\cdot aspect)}\\ | + | * Pentru a realiza transformări compuse, operația de înmulțire între matrici trebuie să fie posibilă, astfel că se utilizează aceeași dimensiune pentru toate tipurile de matrici de transformare. Mai exact, se alege dimensiunea maximă necesară dintre dimensiunile matricelor celor 3 transformări de bază, respectiv 3x3, necesară pentru translație. Astfel, se completează celelalte 2 matrici cu încă o linie și o coloană în a căror celule se scrie 0, cu excepția celulei (3,3), în care se scrie 1. În plus, la reprezentarea matriceală a vectorului se mai adaugă o celulă cu valoarea 1. |
- | $$ | + | * În procesul de transformare perspectivă, ce va fi utilizat în laboratorul următor, se utilizează coordonate într-un spatiu omogen, ceea ce necesită o informație scalară suplimentară. Vom discuta mai multe detalii în legatură cu acest aspect în laboratorul următor :) . |
+ | </note> | ||
- | Daca formula pentru (x, y) reiese din proiectia coordonatelor varfului pe planul din apropiere al trunchiului de piramida, formula pentru componenta z este artificiala si reiese exclusiv din dorinta de a creea o normalizare **neliniara** intre distanta planului din apropiere si distanta planului indepartat. Se doreste ca pentru obiectele din apropiere de planul apropiat, z=-near, sa fie alocat un interval mult mai mare in spatiul de decupare, decat pentru obiectele apropiate de planul z=-far. Din acest motiv, formula standard aleasa initial este: | + | Compunerea transformărilor se poate realiza prin înmulțirea matricilor corespunzătoare fiecărei transformări. Astfel, pentru exemplul de mai sus, în care se rotește un pătrat în jurul propriului centru, lanțul de transformări este următorul: |
$$ | $$ | ||
+ | \begin{bmatrix} | ||
+ | x' & y' & 1 | ||
+ | \end{bmatrix} = | ||
+ | \begin{bmatrix} | ||
+ | x & y & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | 1 & 0 & 0\\ | ||
+ | 0 & 1 & 0\\ | ||
+ | -0.5 & -0.5 & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | cos(45) & sin(45) & 0\\ | ||
+ | -sin(45) & cos(45) & 0\\ | ||
+ | 0 & 0 & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | 1 & 0 & 0\\ | ||
+ | 0 & 1 & 0\\ | ||
+ | 0.5 & 0.5 & 1 | ||
+ | \end{bmatrix} | ||
+ | |||
- | z'=\frac{c1}{-z}+c2 | ||
$$ | $$ | ||
- | Parametrii c1 si c2 sunt cei din formula originala. Problema acestei formule este ca nu se imparte la valoarea z, ceea ce inseamna ca pentru z' nu s-ar aplica impartirea perspectiva. Pentru a face uniform procesul de impartire perspectiva, se modifica formula si obtinem versiunea finala: | ||
+ | ==== Vector coloană ==== | ||
+ | Pentru a obține matricile de transformare, în situația în care utilizăm un vector coloană, putem pleca de la forma anterioară, în care era utilizat un vector linie. Astfel, dacă vrem sa obținem un rezultat transpus celui anterior pentru a aduce forma linie a vectorului la forma coloană, avem: | ||
$$ | $$ | ||
+ | \begin{bmatrix} | ||
+ | x+t_x & y+t_y & 1 | ||
+ | \end{bmatrix} ^t =( | ||
- | z'=\frac{c2\cdot z-c1}{-z} | + | \begin{bmatrix} |
+ | x& | ||
+ | y& | ||
+ | 1 | ||
+ | \end{bmatrix} \begin{bmatrix} | ||
+ | 1 & 0 & 0\\ | ||
+ | 0 & 1 & 0\\ | ||
+ | t_x & t_y & 1 | ||
+ | \end{bmatrix})^t | ||
$$ | $$ | ||
+ | Deoarece, conform următoarei proprietăți a matricilor: | ||
- | </note> | ||
- | ===== Transformarea de vizualizare ===== | ||
- | Prin transformarea de proiecție perspectivă, descrisă mai sus, putem modifica coordonatele vârfurilor rețelei de triunghiuri pentru a le așeza în spațiul de decupare și de acolo putem desena triunghiurile pe ecran. Cu toate acestea, coordonatele obiectelor noastre nu se regăsesc întotdeauna în spațiul de vizualizare, reprezentat, cum s-a menționat mai sus, de volumul unui trunchi de piramidă cu vârful în originea axelor de coordonate și cu baza orientată de-alungul axei Z, în sens negativ. În situația în care dorim să desenăm scena dintr-un alt punct de vedere, trebuie să definim conceptul de observator. Proprietățile care definesc un observator sunt: | + | $$ |
- | * O poziție P în spatiu, de unde "privește" obiectele din scenă | + | (M_{0} \cdot M_{1} \cdot ... \cdot M_{n-1} \cdot M_{n})^{t} = M_{n}^{t} \cdot M_{n-1}^{t} \cdot ... \cdot M_{1}^{t}\cdot M_{0}^{t} |
- | * O direcție F în care "privește" obiectele. Companion acestei direcții, mai este necesar un vector R ce descrie direcția dreapta a observatorului, daca iși rotește direcția în care priveste scena cu 90 de grade față de axa OY și un vector U ce descrie direcția sus a observatorului. Cei 3 vectori sunt ortogonali, mai exact, unghiul dintre oricare 2 vectori din cei 3 este de 90 de grade. | + | $$ |
- | + | ||
- | Pe baza acestor informații, putem să creăm o transformare care modifică obiectele din scena, din spațiul în care se află, într-un spațiu în care observatorul are poziția în originea axelor de coordonate și "privește" scena de-alungul axei Z, în sens negativ. Peste acest spațiu se poate suprapune volumul de vizualizare, utilizat pentru transformarea proiecției perspective. | + | |
- | + | ||
- | Transformarea de vizualizare arată în felul următor: | + | |
+ | Rezultă că forma matricei pentru transformarea de translație este: | ||
$$ | $$ | ||
\begin{bmatrix} | \begin{bmatrix} | ||
- | {x}'\\ | + | x+t_x \\ y + t_y \\ 1 |
- | {y}'\\ | + | \end{bmatrix} = |
- | {z}'\\ | + | |
+ | \begin{bmatrix} | ||
+ | 1 & 0 & 0\\ | ||
+ | 0 & 1 & 0\\ | ||
+ | t_x & t_y & 1 | ||
+ | \end{bmatrix}^t | ||
+ | \begin{bmatrix} | ||
+ | x& | ||
+ | y& | ||
1 | 1 | ||
- | \end{bmatrix} = \begin{bmatrix} | + | \end{bmatrix} ^t= |
- | R_x & R_y & R_z & 0 \\ | + | |
- | U_x & U_y & U_z & 0 \\ | + | |
- | F_x & F_y & F_z & 0 \\ | + | |
- | 0 & 0 & 0 & 1 | + | |
- | \end{bmatrix} | + | |
\begin{bmatrix} | \begin{bmatrix} | ||
- | 1 & 0 & 0 & -P_x \\ | + | 1 & 0 & t_x\\ |
- | 0 & 1 & 0 & -P_y \\ | + | 0 & 1 & t_y\\ |
- | 0 & 0 & 1 & -P_z \\ | + | 0 & 0 & 1 |
- | 0 & 0 & 0 & 1 | + | |
\end{bmatrix} | \end{bmatrix} | ||
Line 285: | Line 291: | ||
x\\ | x\\ | ||
y\\ | y\\ | ||
- | z\\ | ||
1 | 1 | ||
\end{bmatrix} | \end{bmatrix} | ||
$$ | $$ | ||
- | + | Analog pentru matricile celorlalte 2 transformări: | |
- | Se poate observa prima transformare aplicată, ultima în lanțul de înmulțiri de matrici, este o translație inversă a coordonatelor poziției observatorului în spațiul 3D, similară cu cea discutată în laboratorul anterior pentru spațiul 2D. A doua transformare aplicată este o rotație. Pentru construcția acestei matrici s-a folosit [[https://ro.wikipedia.org/wiki/Procedeul_Gram%E2%80%93Schmidt | procedeul Gram–Schmidt]]. | + | |
- | + | ||
- | <note tip> | + | |
- | Spațiul în care se regăsesc: poziția observatorului, vectorii ce descriu direcția de "privire", direcția dreapta și sus, împreună cu coordonatele tuturor obiectelor "privite" de către observator, poartă numele de **spațiu al lumii**. În limba engleză, se întâlnește denumirea de **world space**. | + | |
- | </note> | + | |
- | + | ||
- | ===== Transformarea de modelare ===== | + | |
- | + | ||
- | Coordonatele vârfurilor din rețeaua de triunghiuri ce descrie suprafața unui obiect se declară inițial într-un spațiu convenabil creării acelui obiect. De exemplu, din laborato. | + | |
- | + | ||
- | Pentru a modifica obiectul și a-l așeza sub forma dorită în punctul final din scenă, se folosesc transformările de translație, de modificare a scării și de rotație, discutate în laboratorul anterior, adaptate pentru un spațiu 3D. | + | |
- | + | ||
- | ==== Transformarea de translație ==== | + | |
- | + | ||
- | Forma matriceală a transformărilor de translație și de modificare a scării este similară cu cea a transformărilor utilizate într-un spațiu 2D. Fiecare din cele două matrici se modifică doar prin adăugarea unei noi linii și a unei noi coloane pentru a adapta cea de-a treia dimensiune ce apare într-un spațiu 3D. | + | |
$$ | $$ | ||
\begin{bmatrix} | \begin{bmatrix} | ||
- | {x}'\\ | + | s_x \cdot x \\ s_y \cdot y \\ 1 |
- | {y}'\\ | + | \end{bmatrix} = |
- | {z}'\\ | + | \begin{bmatrix} |
- | 1 | + | s_x & 0 & 0\\ |
- | \end{bmatrix} = \begin{bmatrix} | + | 0 & s_y & 0\\ |
- | 1 & 0 & 0 & t_x\\ | + | 0 & 0 & 1 |
- | 0 & 1 & 0 & t_y\\ | + | |
- | 0 & 0 & 1 & t_z\\ | + | |
- | 0 & 0 & 0 &1 | + | |
\end{bmatrix} | \end{bmatrix} | ||
Line 325: | Line 311: | ||
x\\ | x\\ | ||
y\\ | y\\ | ||
- | z\\ | ||
1 | 1 | ||
\end{bmatrix} | \end{bmatrix} | ||
$$ | $$ | ||
- | |||
- | ==== Transformarea de modificare a scării ==== | ||
$$ | $$ | ||
\begin{bmatrix} | \begin{bmatrix} | ||
- | {x}'\\ | + | x \cdot cos(\theta)-y \cdot sin(\theta) \\ x \cdot sin(\theta)+y \cdot cos(\theta) \\ 1 |
- | {y}'\\ | + | \end{bmatrix} = |
- | {z}'\\ | + | \begin{bmatrix} |
- | 1 | + | cos(\theta) & -sin(\theta) & 0\\ |
- | \end{bmatrix} = \begin{bmatrix} | + | sin(\theta) & cos(\theta) & 0\\ |
- | s_x & 0 & 0 &0 \\ | + | 0 & 0 & 1 |
- | 0 & s_y & 0 &0 \\ | + | |
- | 0 & 0 & s_z &0 \\ | + | |
- | 0 & 0 & 0 &1 | + | |
\end{bmatrix} | \end{bmatrix} | ||
Line 350: | Line 330: | ||
x\\ | x\\ | ||
y\\ | y\\ | ||
- | z\\ | ||
1 | 1 | ||
\end{bmatrix} | \end{bmatrix} | ||
$$ | $$ | ||
+ | Pentru transformarea compusă dată exemplu mai devreme, vom avea: | ||
- | ==== Transformarea de rotație ==== | ||
- | |||
- | Mecanismul de rotație, studiat în laboratorul trecut, rotește o coordonată a unui punct într-un spațiu 2D cu un unghi a, //în sens trigonometric față de originea axelor de coordonate//. Acest mecanism NU poate fi adaptat direct la un spațiu 3D. | ||
- | |||
- | Astfel, transformarea de rotație dintr-un spațiu 2D este utilizată într-un spațiu 3D pentru a roti o coordonată într-un singur plan din spațiul 3D. Mai exact într-un plan paralel cu unul din cele 3 planuri ce trec prin originea axelor de coordonate. Există câte o matrice de transformare diferită pentru fiecare din cele 3 planuri. În situația în care dorim sa creăm o transformare de rotație într-un plan oarecare, trebuie să o obținem prin compunerea din mai multe transformari de bază. | ||
- | |||
- | Astfel, avem transformarea de rotație într-un plan paralel cu planul XOY: | ||
$$ | $$ | ||
\begin{bmatrix} | \begin{bmatrix} | ||
- | {x}'\\ | + | x' \\ y' \\ 1 |
- | {y}'\\ | + | \end{bmatrix} = |
- | {z}'\\ | + | \begin{bmatrix} |
- | 1 | + | 1 & 0 & 0.5\\ |
- | \end{bmatrix} = \begin{bmatrix} | + | 0 & 1 & 0.5\\ |
- | cos(u) & -sin(u) & 0 & 0\\ | + | 0 & 0 & 1 |
- | sin(u) & cos(u) & 0 & 0\\ | + | \end{bmatrix} |
- | 0 & 0 & 1 & 0 \\ | + | \begin{bmatrix} |
- | 0 & 0 & 0 & 1 | + | cos(45) & -sin(45) & 0\\ |
+ | sin(45) & cos(45) & 0\\ | ||
+ | 0 & 0 & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | 1 & 0 & -0.5\\ | ||
+ | 0 & 1 & -0.5\\ | ||
+ | 0 & 0 & 1 | ||
\end{bmatrix} | \end{bmatrix} | ||
\begin{bmatrix} | \begin{bmatrix} | ||
- | x\\ | + | x \\ y \\ 1 |
- | y\\ | + | |
- | z\\ | + | |
- | 1 | + | |
\end{bmatrix} | \end{bmatrix} | ||
+ | |||
$$ | $$ | ||
+ | <note tip> | ||
+ | Observăm că, în situația în care utilizăm un vector coloană, ordinea de aplicare a transformărilor este **de la ultima matrice la prima**. În plus, vectorul pentru care se aplică lanțul de transformări este întotdeauna la final. | ||
+ | </note> | ||
- | Putem să considerăm că această transformare este față de axa OZ. | + | <note> |
+ | În cadrul laboratoarelor de la această materie, până la finalul semestrului, vom utiliza reprezentarea unui vector în formă coloană. Ambele reprezentări ale vectorilor sunt practice și compatibile cu procesorul grafic. | ||
+ | </note> | ||
+ | ==== Biblioteca glm ==== | ||
- | Transformarea de rotație într-un plan paralel cu planul XOZ, sau față de axa OY este: | + | În cadrul laboratoarelor de la această materie, vom utiliza biblioteca glm pentru gestionarea matricilor și a operațiilor cu matrici. |
+ | La bază, biblioteca glm folosește matrici column-major, mai precis, matrici care au informația transpusă în memorie. Astfel, în constructorul tipului de date ''glm::mat3'', trebuie transmisă forma transpusă a matricei pe care dorim sa o reținem. | ||
+ | De exemplu, matricea pentru transformarea de translație, utilizată pentru inmulțirea cu un **vector coloană**, trebuie inițializată astfel: | ||
+ | <code cpp> | ||
+ | glm::mat3 Translate(float tx, float ty) | ||
+ | { | ||
+ | return glm::mat3( | ||
+ | 1, 0, 0, // coloana 1 in memorie | ||
+ | 0, 1, 0, // coloana 2 in memorie | ||
+ | tx, ty, 1); // coloana 3 in memorie | ||
+ | |||
+ | } | ||
+ | </code> | ||
- | $$ | + | De asemenea, avem opțiunea să inițializăm matricea în formă netranspusă și să aplicăm ''glm::transpose'' ulterior: |
- | \begin{bmatrix} | + | |
- | {x}'\\ | + | |
- | {y}'\\ | + | |
- | {z}'\\ | + | |
- | 1 | + | |
- | \end{bmatrix} = \begin{bmatrix} | + | |
- | cos(u) & 0 & sin(u) & 0\\ | + | |
- | 0 & 1 & 0 & 0 \\ | + | |
- | -sin(u) & 0 & cos(u) & 0\\ | + | |
- | 0 & 0 & 0 & 1 | + | |
- | \end{bmatrix} | + | |
- | \begin{bmatrix} | + | <code cpp> |
- | x\\ | + | glm::mat3 Translate(float tx, float ty) |
- | y\\ | + | { |
- | z\\ | + | return glm::transpose( |
- | 1 | + | glm::mat3( 1, 0, tx, |
- | \end{bmatrix} | + | 0, 1, ty, |
- | $$ | + | 0, 0, 1) |
+ | ); | ||
+ | } | ||
+ | </code> | ||
+ | ===== Transformarea fereastră-poartă ===== | ||
+ | În situatia în care dorim ca aplicația grafică proiectată de noi să nu depindă de rezoluția ferestrei și astfel să poată funcționa la rezoluții diferite, trebuie să nu mai definim coordonatele vârfurilor în grila de pixeli a ecranului. Pentru acest proces, vom defini un spațiu special, finit, denumit spațiu logic, în care vom declara coordonatele vârfurilor. Acest spațiu este o fereastră peste spațiul 2D și din acest motiv, transformarea are numele de transformare fereastră-poartă, respectiv transformare din fereastra peste spațiul 2D în poarta de vizualizare, reprezentată de ecran. | ||
+ | În laborator, a fost definit spațiul logic, după cum urmează: | ||
- | Transformarea de rotație într-un plan paralel cu planul YOZ, sau față de axa OX este: | + | <code cpp> |
+ | struct LogicSpace | ||
+ | { | ||
+ | float x; | ||
+ | float y; | ||
+ | float width; | ||
+ | float height; | ||
+ | }; | ||
+ | </code> | ||
- | $$ | + | Se poate observa ca acest spațiu este definit de coordonatele calțului stânga-jos pentru fereastra și de o lățime și o înălțime a acesteia. |
- | \begin{bmatrix} | + | |
- | {x}'\\ | + | |
- | {y}'\\ | + | |
- | {z}'\\ | + | |
- | 1 | + | |
- | \end{bmatrix} = \begin{bmatrix} | + | |
- | 1 & 0 & 0 & 0 \\ | + | |
- | 0 & cos(u) & -sin(u) & 0 \\ | + | |
- | 0 & sin(u) & cos(u) & 0 \\ | + | |
- | 0 & 0 & 0 & 1 | + | |
- | \end{bmatrix} | + | |
- | \begin{bmatrix} | + | Analog, realizăm o structură de date pentru poarta de vizualizare, cunoscută în limba engleza sub numele de viewport: |
- | x\\ | + | |
- | y\\ | + | |
- | z\\ | + | |
- | 1 | + | |
- | \end{bmatrix} | + | |
- | $$ | + | |
+ | <code cpp> | ||
+ | struct ViewportSpace | ||
+ | { | ||
+ | int x; | ||
+ | int y; | ||
+ | int width; | ||
+ | int height; | ||
+ | }; | ||
+ | </code> | ||
- | <note tip> | + | De exemplu, pentru a transforma obiectele definite în spatiul logic ce are colțul stânga-jos la coordonatele (1, 1) și rezoluția de 3x2, astfel încât să fie puse pe întreg ecranul, de rezoluție 1280x720, se pot defini spațiile în felul următor. |
- | Spațiul în care sunt definite inițial coordonatele vârfurilor poartă numele de **spațiu al obiectului**, sau în limba engleză, poate fi întâlnit cu denumirea de **object space**. | + | |
- | </note> | + | |
- | ===== Eliminarea din procesul de rasterizare a triunghiurilor obturate ===== | + | <code cpp> |
+ | ViewportSpace viewport_space = { 0, 0, 1280, 720 }; | ||
+ | LogicSpace logic_space = { 1, 1, 3, 2 }; | ||
+ | </code> | ||
- | O optimizare suplimentară, pe care o putem realiza în spațiul de decupare, pe lângă cea de decupare propriu-zisă, este să excludem din procesul de rasterizare triunghiurile care sunt complet obturate de altă geometrie. Pentru a nu face o procesare avansată la nivel de rețea de triunghiuri, putem să folosim urmatorul artificiu: | + | Transformarea se poate urmări vizual în imaginea de mai jos. |
- | În situția în care desenăm un model 3D etanș, care nu conține nicio gaură în suprafața lui, avem proprietatea că din orice punct am privi geometria, nu îi vom putea vedea niciodată interiorul. Astfel, avem următoarea formă de definire a unui triunghi: pe baza descrierii cu indici din ''vertices'', utilizată în laboratoarele anterioare, sensul în care sunt afișate vârfurile, pe baza ordinii din indici, ne determină noua faptul că privim fațeta față sau fațeta spate a triunghiului. | + | {{ :ppbg:laboratoare:viewport.png?600 |}} |
- | Mai exact, dacă avem descrisă urmatoarea geometrie: | + | Lanțul de transformări necesar acestui proces este: |
- | <code cpp> | ||
- | vector<VertexFormat> vertices | ||
- | { | ||
- | VertexFormat(glm::vec3(0, 2, 0)), | ||
- | VertexFormat(glm::vec3(-1, 0, 0)), | ||
- | VertexFormat(glm::vec3(1, 0, 0)), | ||
- | } | ||
- | vector<unsigned int> indices1 | ||
- | { | ||
- | 0, 1, 2, | ||
- | } | ||
- | vector<unsigned int> indices2 | + | $$ |
- | { | + | \begin{bmatrix} |
- | 0, 2, 1, | + | x' \\ y' \\ 1 |
- | } | + | \end{bmatrix} = |
+ | \begin{bmatrix} | ||
+ | 1 & 0 & V_{x}\\ | ||
+ | 0 & 1 & V_{y}\\ | ||
+ | 0 & 0 & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | V_{w}/F_{w} & 0 & 0\\ | ||
+ | 0 & V_{h}/F_{h} & 0\\ | ||
+ | 0 & 0 & 1 | ||
+ | \end{bmatrix} | ||
+ | \begin{bmatrix} | ||
+ | 1 & 0 & -F_x\\ | ||
+ | 0 & 1 & -F_y\\ | ||
+ | 0 & 0 & 1 | ||
+ | \end{bmatrix} | ||
- | </code> | + | \begin{bmatrix} |
+ | x \\ y \\ 1 | ||
+ | \end{bmatrix} | ||
- | În momentul în care geometria se află în spațiul de decupare, după aplicarea tuturor transformărilor, se observă sensul dat de coordonatele vârfurilor, în ordinea în care au fost definiți indicii. În situația în care sensul pe care îl fac coordonatele, conform imaginii de mai jos, este trigonometric, considerăm că ne uităm la fațeta față a triunghiului. | + | $$ |
- | {{ :ppbg:laboratoare:cull.png?400 |}} | + | Componentele Fx, Fy, Fw și Fh reprezintă coordonatele (x, y) pentru colțul stânga-jos al ferestrei spațiului 2D, în care sunt definite coordonatele vâfurilor din aplicația grafică, respectiv lățimea și înălțimea ferestrei. Componentele Vx, Vy, Vw și Vh reprezintă coordonatele (x, y) pentru colțul stânga-jos al porții de vizualizare, respectiv lățimea și înălțimea ei. |
- | Prin acest proces, în situația în care desenăm suprafața unui model 3D etanș, putem exclude din procesul de rasterizare toate triunghiurile pentru care afișăm fațetele spate, deoarece avem garanția că ele sunt obturate de restul geometriei modelului. | + | ===== Cerințe laborator ===== |
- | <note tip> | + | - 0.1p - Completați fișierul ''transform2D.h'' cu cele 4 transformări descrise mai sus. |
- | Acest proces se întâlnește în limba engleză sub numele de **face culling**, adică tăierea de la desenare a anumitor triunghiuri, pe baza fațetei pe care o vedem. Avem opțiunea de a tăia de la desenare triunghiurile pentru care afișăm fațetele față sau pe cele pentru care afișăm fațetele spate. | + | - 0.05p - Aplicați transformările necesare pentru a modifica pătratele de pe linia din partea de sus, conform rezultatului din imaginea de mai jos. Consultați comentariile din cod pentru a primi mai multe detalii despre fiecare transformare. |
- | </note> | + | - 0.1p - Aplicați transformările necesare pentru a modifica pătratele de pe linia din partea de jos, conform rezultatului din imaginea de mai jos. Consultați comentariile din cod pentru a primi mai multe detalii despre fiecare transformare. \\ Pâna în acest punct, rezultatul pe care ar trebui să îl obțineti este următorul: {{ :ppbg:laboratoare:transformations1.png?600 |}} |
+ | - 0.05p - Împărțiți ecranul în 4 cadrane și desenați formele geometrice de mai sus de 4 ori, câte o dată în fiecare cadran. Modificați spațiul porții de vizualizare, coordonatele colțului din stânga jos, respectiv, lățimea și înălțimea. | ||
- | ===== Privire de ansamblu ===== | + | Rezultatul final ar trebui să fie urmatorul: |
- | O privire de ansamblu a întrgului proces se poate regăsi în imaginea următoare: | + | {{ :ppbg:laboratoare:transformations2.png?600 |}} |
- | + | ||
- | {{ :ppbg:laboratoare:overview.png?600 |}} | + | |
- | + | ||
- | Din spațiul obiectului, prin transformarea de modelare, ce conține un lanț de transformări de translație, de modificare a scării și de rotație, obiectele ajung în spațiul lumii. Din acest spațiu, prin transformarea de vizualizare, conform proprietăților observatorului, obiectele ajung în spațiul de vizualizare, peste care se aplică volumul de proiecție perspectivă, reprezentat de un trunchi de piramidă, centrat în originea axelor de coordonate, cu baza orientată de-alungul axei Z, în sens negativ. Din acest spațiu, prin transformarea de proiecție perspectivă, obiectele ajung în spațiul de decupare, reprezentat de volumul unui cub, cu latura de dimensiune 2, centrat în originea axelor de coordonate. După procesul de decupare și de eliminare a triunghiurilor obturate, în situația în care dorim acest al doilea proces, prin transformarea coordonatelor din volumul de decupare în poarta de afișare, triunghiurile se transmit la procesul de rasterizare, prin care se desenează suprafețele triunghiurilor în grila de pixeli :) . | + | |
<note tip> | <note tip> | ||
- | Felicitări :) ! Daca ați înțeles acest proces, ați înțeles standardul care stă la baza graficii pe calculator în timp real. Toate procesoarele grafice implementează acest standard, hardware sau software în driver-ul companion procesorului. Acest fapt este valabil și pentru arhitecturile ce implementează hardware procesul de ray-tracing. Aplicațiile grafice ce utilizează această arhitectură folosesc o abordare hibridă ce combină banda grafică de rasterizare cu banda grafică de ray-tracing. | + | Utilizați tastele **sus**, **jos**, **stânga** și **dreapta** pentru a controla interactiv pozitia colțului din stânga-jos a spațiului logic. |
</note> | </note> | ||
- | ===== Cerințe laborator ===== | + | Bonus: Realizați razele unei stele prin desenarea multiplă a unui triunghi rotit la unghiuri diferite. Este necesar să construiți o nouă geometrie pentru triunghiul ce reprezintă o rază. Un exemplu vizual ar putea fi: |
- | - 0.1p - Completați fișierul ''transform3D.h'' cu transformările de modelare descrise mai sus. | + | {{ :ppbg:laboratoare:transformations3.png?600 |}} |
- | - 0.05p - Completați fișierul ''transform3D.h'' cu transformarea de proiecție perspectivă descrisă mai sus. | + | |
- | - 0.05p - Aplicați procesul de împărțire perspectivă a coordonatei obținute în urma aplicării tuturor transformărilor din lanț. | + | |
- | - 0.05p - Completați fișierul ''transform3D.h'' cu transformarea de vizualizare descrisă mai sus. | + | |
- | * După acest pas, cât țineți apăsat butonul dreapta de la mouse, puteți modifica direcția de vizualizare a observatorului prin deplasarea poziției mouse-ului și vă puteți deplasa prin scena 3D cu tastele **W**, **A**, **S**, **D**, **E** și **Q**. Până în acest punct, rezultatul pe care ar trebui să îl obțineti este următorul: {{ :ppbg:laboratoare:cube1.png?600 |}} | + | |
- | - 0.05p - Completați metoda ''DetermineTriangleFace()'' pentru a identifica corect care din cele două fațete ale triunghiului, față sau spate, este afișat. | + | |
- | * După acest pas, puteți utiliza tasta **F** pentru a schimba între desenarea triunghiurilor pentru care se afișeaza fațetele față sau fațetele spate. Dacă alegeți opțiunea să fie afișate doar fațetele spate, ar trebui să puteți vedea interiorul cubului :) : {{ :ppbg:laboratoare:cube2.png?600 |}} | + | |
- | Bonus: Construiți și desenați un tetraedru care să aibă indicii fiecărui triunghiuri orientați în sens trigonometric, când triunghiul este privit din exterior. Asociați culori diferite fiecărui vârf pentru vedea mai ușor detaliile tetraedrului. | + | <note tip> |
+ | * Aveți în vedere că, pentru simplitate, triunghiul ce reprezintă raza, poate fi creat direct cu proprietatea de a fi isoscel :) . | ||
+ | * Razele **se pot** suprapune între ele. | ||
+ | </note> | ||