This shows you the differences between two versions of the page.
ppbg:laboratoare:04 [2023/10/30 21:58] andrei.lambru |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laboratorul 04 ====== | ||
- | |||
- | <note tip> | ||
- | Pentru rezolvarea cerințelor din acest laborator, aveți nevoie de codul utilizat în rezolvarea cerințelor din cadrul laboratorului 3. În situatia în care nu ați rezolvat acest [[:ppbg:laboratoare:03|laboratorul 3]], va trebui să le 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 tip> | ||
- | Pentru rezolvarea cerințelor din cadrul acestui labroator: | ||
- | - [[https://github.com/UPB-Graphics/gfx-framework-ppbg | Descărcați]] framwork-ul de laborator și copiați, din arhiva descărcată, directorul **Lab4**, î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/lab4/lab4.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> | ||
- | |||
- | ===== Aplicatiile grafice in timp real ===== | ||
- | |||
- | ===== API-ul grafic OpenGL ===== | ||
- | |||
- | ==== Stergerea ecranului ==== | ||
- | |||
- | ==== Poarta de afisare ==== | ||
- | |||
- | ==== Modele 3D ==== | ||
- | |||
- | Un model 3D, cunoscut in limba engleza sub numele de **3D mesh**, este un obiect tridimensional definit prin vârfuri și indici. În laborator aveți posibilitatea să încărcați modele 3D în aproape orice format posibil prin intermediul clasei [[https://github.com/UPB-Graphics/gfx-framework/blob/master/src/core/gpu/mesh.h#L48|Mesh]]. | ||
- | |||
- | |||
- | === Vertex Buffer Object (VBO) === | ||
- | |||
- | Un vertex buffer object reprezintă un container în care stocăm date ce țin de conținutul vârfurilor precum: | ||
- | * poziție | ||
- | * normală | ||
- | * culoare | ||
- | * coordonate de texturare | ||
- | * etc... | ||
- | |||
- | Un vertex buffer object se poate crea prin comanda OpenGL **[[https://www.opengl.org/sdk/docs/man/html/glGenBuffers.xhtml|glGenBuffers]]**: | ||
- | <code cpp> | ||
- | unsigned int VBO_ID; // ID-ul (nume sau referinta) buffer-ului ce va fi cerut de la GPU | ||
- | glGenBuffers(1, &VBO_ID); // se genereaza ID-ul (numele) bufferului | ||
- | </code> | ||
- | |||
- | <note> | ||
- | Așa cum se poate vedea și din explicația API-ului, funcția [[https://www.opengl.org/sdk/docs/man/html/glGenBuffers.xhtml|glGenBuffers]] primește numărul de buffere ce trebuie generate cât și locația din memorie unde vor fi salvate referințele (ID-urile) generate.\\ | ||
- | În exemplul de mai sus este generat doar 1 singur buffer iar ID-ul este salvat în variabila ''VBO_ID''. | ||
- | </note> | ||
- | |||
- | Pentru a distruge un VBO și astfel să eliberăm memoria de pe **GPU** se folosește comanda **[[https://www.opengl.org/sdk/docs/man4/html/glDeleteBuffers.xhtml|glDeleteBuffers]]**: | ||
- | <code cpp> | ||
- | glDeleteBuffers(1, &VBO_ID); | ||
- | </code> | ||
- | |||
- | Pentru a putea pune date într-un buffer trebuie întâi să legăm acest buffer la un „target”. Pentru un vertex buffer acest „binding point” se numește **GL_ARRAY_BUFFER** și se poate specifica prin comanda **[[https://www.khronos.org/opengles/sdk/1.1/docs/man/glBindBuffer.xml|glBindBuffer]]**: | ||
- | |||
- | <code cpp> | ||
- | glBindBuffer(GL_ARRAY_BUFFER, VBO_ID); | ||
- | </code> | ||
- | |||
- | În acest moment putem să facem upload de date din memoria **CPU** către **GPU** prin intermediul comenzii **[[https://www.opengl.org/sdk/docs/man4/html/glBufferData.xhtml|glBufferData]]**: | ||
- | |||
- | <code cpp> | ||
- | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), &vertices[0], GL_STATIC_DRAW); | ||
- | </code> | ||
- | |||
- | * Comanda citește de la adresa specificată, în exemplul de sus fiind adresa primului vârf ''&vertices[0]'', și copiază în memoria video dimensiunea specificată prin parametrul al 2-lea. | ||
- | * **GL_STATIC_DRAW** reprezintă un hint pentru driver-ul video în ceea ce privește metoda de utilizare a bufferului. Acest simbol poate avea mai multe valori dar în cadrul laboratorului este de ajuns specificarea prezentată. Mai multe informații găsiți pe pagina de manual a funcției [[https://www.opengl.org/sdk/docs/man4/html/glBufferData.xhtml|glBufferData]] | ||
- | |||
- | |||
- | <note tip> | ||
- | Pentru a înțelege mai bine API-ul OpenGL vă recomandăm să citiți documentația indicată pentru fiecare comandă prezentată. Atunci când se prezintă o nouă comandă, dacă apăsați click pe numele acesteia veți fi redirecționați către pagina de manual a comenzii respective.\\ | ||
- | De asemenea, documentația oficială și completă a API-ului OpenGL poate fi gasită pe pagina **[[https://www.opengl.org/sdk/docs/man/|OpenGL 4 Reference Pages]]** | ||
- | </note> | ||
- | |||
- | === Index Buffer Object (IBO) === | ||
- | |||
- | Un index buffer object (numit și element buffer object) reprezintă un container în care stocăm indicii vertecșilor. Cum **VBO** si **IBO** sunt buffere, ele sunt extrem de similare în construcție, încărcare de date și ștergere. | ||
- | |||
- | <code cpp> | ||
- | glGenBuffers(1, &IBO_ID); | ||
- | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO_ID); | ||
- | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), &indices[0], GL_STATIC_DRAW); | ||
- | </code> | ||
- | |||
- | La fel ca la VBO, creăm un IBO și apoi îl legăm la un punct de legatură, doar că de data aceasta punctul de legatură este **GL_ELEMENT_ARRAY_BUFFER**. Datele sunt trimise către bufferul mapat la acest punct de legatură. În cazul indicilor toți vor fi de dimensiunea unui singur întreg. | ||
- | |||
- | === Vertex Array Object (VAO) === | ||
- | |||
- | Într-un vertex array object putem stoca toată informația legată de starea geometriei desenate. Putem folosi un număr mare de buffere pentru a stoca fiecare din diferitele atribute („separate buffers”). Putem stoca mai multe (sau toate) atribute într-un singur buffer („interleaved” buffers). În mod normal înainte de fiecare comandă de desenare trebuie specificate toate comenzile de „binding” pentru buffere sau atribute ce descriu datele ce doresc a fi randate. Pentru a simplifica această operație se folosește un vertex array object care ține minte toate aceste legături. | ||
- | |||
- | Un vertex array object este creat folosind comanda **[[https://www.opengl.org/sdk/docs/man4/html/glGenVertexArrays.xhtml|glGenVertexArrays]]**: | ||
- | |||
- | <code cpp> | ||
- | unsigned int VAO; | ||
- | glGenVertexArrays(1, &VAO); | ||
- | </code> | ||
- | |||
- | Este legat cu **[[https://www.opengl.org/sdk/docs/man4/html/glBindVertexArray.xhtml|glBindVertexArray]]**: | ||
- | |||
- | <code cpp>glBindVertexArray(VAO);</code> | ||
- | <hidden> | ||
- | Și este distrus cu **[[https://www.opengl.org/sdk/docs/man4/html/glDeleteVertexArrays.xhtml|glDeleteVertexArrays]]**: | ||
- | <code cpp>glDeleteVertexArrays(1, &VAO);</code> | ||
- | </hidden> | ||
- | <note tip> | ||
- | Înainte de a crea VBO-urile și IBO-ul necesar pentru un obiect se va lega VAO-ul obiectului și acesta va ține minte automat toate legăturile specificate ulterior. | ||
- | |||
- | După ce toate legăturile au fost specificate este recomandat să se dea comanda ''glBindVertexArray(0)'' pentru a dezactiva legătura către VAO-ul curent, deoarece altfel riscăm ca alte comenzi OpenGL ulterioare să fie legate la același VAO și astfel să introducem foarte ușor erori în program. | ||
- | </note> | ||
- | |||
- | Înainte de comanda de desenare este suficient să legăm doar VAO-ul ca OpenGL să știe toate legatările create la construcția obiectului. | ||
- | |||
- | ==== Optiunea de optimizare Face Culling==== | ||
- | |||
- | API-ul OpenGL oferă posibilitatea de a testa orientarea aparentă pe ecran a fiecărui triunghi înainte ca acesta să fie redat și să îl ignore în funcție de starea de discard setată: **GL_FRONT** sau **GL_BACK**. Acestă funcționalitate poartă numele de **[[https://www.opengl.org/wiki/Face_Culling|Face Culling]]** și este foarte importantă deoarece reduce costul de procesare total. | ||
- | |||
- | Modul cum este considerată o față ca fiind **GL_FRONT** sau **GL_BACK** poate fi schimbat folosind comanda [[https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glFrontFace.xhtml|glFrontFace]] (valoarea inițială pentru o față **GL_FRONT** este considerată ca având ordinea specificării vârfurilor în sens trigonometric / counter clockwise): | ||
- | <code cpp> | ||
- | // mode can be GL_CW (clockwise) or GL_CCW (counterclockwise) | ||
- | // the initial value is GL_CCW | ||
- | void glFrontFace(GLenum mode); | ||
- | </code> | ||
- | |||
- | <note> | ||
- | Exemplu: pentru un **cub** maxim 3 fețe pot fi vizibile la un moment dat din cele 6 existente. În acest caz maxim 6 triunghiuri vor fi procesate pentru afișarea pe ecran în loc de 12. | ||
- | </note> | ||
- | |||
- | În mod normal face-culling este dezactivat. Acesta poate fi activat folosind comanda [[https://www.opengl.org/sdk/docs/man4/html/glEnable.xhtml|glEnable]]: | ||
- | <code cpp> | ||
- | glEnable(GL_CULL_FACE); | ||
- | </code> | ||
- | |||
- | Pentru a dezactiva face-culling se folosește comanda [[https://www.opengl.org/sdk/docs/man4/html/glEnable.xhtml|glDisable]]: | ||
- | <code cpp> | ||
- | glDisable(GL_CULL_FACE); | ||
- | </code> | ||
- | |||
- | Pentru a specifica ce orientare a fețelor să fie ignorată se folosește comanda **[[https://www.opengl.org/wiki/GLAPI/glCullFace|glCullFace]]** | ||
- | <code cpp> | ||
- | // GL_FRONT, GL_BACK, and GL_FRONT_AND_BACK are accepted. | ||
- | // The initial value is GL_BACK. | ||
- | glCullFace(GL_BACK); | ||
- | </code> | ||
- | |||
- | {{ :egc:laboratoare:lab02:cull_face.png?450 |}} | ||
- | |||
- | |||
- | ===== Cerinte laborator ===== | ||