This is an old revision of the document!


Laboratorul 02

OpenGL – Date

Daca am incerca sa reducem intregul API de OpenGL la mari concepte acestea ar fi:

  • date
  • stari
  • shadere

Shaderele vor fi introduse pe parcursul cursului.
Starile reprezinta un concept mai larg, OpenGL fiind de fapt un mare automat finit cu o multime de stari si posibilitati de a trece dintr-o stare in alta. De-a lungul laboratoarelor o parte din aceste stari vor fi folosite pentru a obține efectele dorite.
Datele contin informatiile ce definesc scena, precum:

  • obiecte tridimensionale
  • proprietati de material ale obiectelor (plastic, sticla, etc)
  • pozitiile, orientarile si dimensiunile obiectelor lor in scena
  • orice alte informatii necesare ce descriu proprietati de obiecte sau de scena

De exemplu pentru o scena cu un singur patrat avem urmatoarele date:

  • varfurile patratului - 4 vectori tridimensionali ce definesc pozitia fiecarui varf in spatiu
  • caracteristicile varfurilor
    • daca singura caracteristica a unui varf in afara de pozitie ar fi culoarea am avea inca 4 vectori tridimensionali(RGB)
  • topologia patratului, adica metoda prin care legam aceste varfuri

OpenGL este este un API de grafica tridimensionala, adica, toate obiectele care pot fi definite sunt raportate la un sistem de coordonate carteziene tridimensional. Cu toate acestea putem utiliza API-ul pentru a afisa obiecte bi-dimensionale chiar daca acestea sunt definite prin coordonate (x,y,z) prin plasarea tuturor datelor intr-un singur plan si utilizarea unei proiectii corespunzatoare.
In cadrul laboratorului vom utiliza coordonata Z = 0. Astfel orice punct tridimensional va deveni P(x,y,0)

Topologie

Primitiva de baza in OpenGL este triunghiul. Astfel asa cum se poate observa si in imaginea de sus pentru a desena un obiect acesta trebuie specificat prin triunghiuri.

Cubul descris mai sus este specificat prin lista celor 8 coordonate de varfuri si o lista de 12 triunghiuri care descrie modul in care trebuie unite varfurile specificate in lista precedenta pentru a forma fețele cubului. Folosind varfuri si indici putem descrie in mod discret orice obiect tridimensional.

Mai jos regasiti principalele primitive acceptate de standardul OpenGL 3.3+.

Dupa cum se poate observa exista mai multe metode prin care geometria poate fi specificata:

  • GL_LINES si GL_TRIANGLES sunt cele mai des utilizate primitive pentru definirea geometriei
  • GL_POINTS este des utilizat pentru a crea sistemele de particule
  • Celelalte modele reprezinta doar niste optimizari ale celor 3 primitive de baza, atat din perspectiva memoriei dar si a usurintei in a specifica anumite topologii insa utilitatea lor este deseori limitata intrucat obiectele mai complexe nu pot fi specificate decat prin utilizarea primitivelor simple

In cadrul framework-ului puteti seta tipul de primitiva utilizat de catre un obiect la randare prin intermediul functiei Mesh::SetDrawMode(GLenum primitive) unde primitive poate fi oricare dintre primitivele mentionate in imaginea de mai sus.

Ordinea specificarii varfurilor

O observatie importanta legata de topologie este ordinea varfurilor intr-o primitiva solida (nu linie, nu punct) cu mai mult de 2 varfuri. Aceasta ordine poate fi in sensul acelor de ceas sau in sens invers.

Face Culling

API-ul OpenGL ofera posibilitatea de a testa orientarea aperenta pe ecran a fiecarui triunghi inainte ca acesta sa fie redat si sa il ignore in functie de stare de discard setata: GL_FRONT sau GL_BACK. Acesta functionalitatea poarta numele de Face Culling si este foarte importanta deoarece reduce costul de procesare total.

Exemplu: pentru un cub maxim 3 fete pot fi vizibile la un moment dat, din cele 6 existente. In acest caz maxim 6 triunghiuri vor fi procesate pentru afisarea pe ecran in loc de 12.

In mod normal face-culling este dezactivat. Acesta poate fi activat folosind comanda glEnable:

glEnable(GL_CULL_FACE);

Pentru a dezactiva face-culling se foloseste comanda glDisable:

glDisable(GL_CULL_FACE);

Pentru a specifica ce orientare a fetelor sa fie ignorata se foloseste comanda glCullFace

// GL_FRONT, GL_BACK, and GL_FRONT_AND_BACK are accepted.
// The initial value is GL_BACK.
glCullFace(GL_BACK);

Meshe

Un „mesh” este un obiect tridimensional definit prin varfuri si indici. In laborator aveti posibilitatea sa incarcati meshe in aproape orice format posibil prin intermediul clasei Mesh.

Vertex Buffer Object (VBO)

Un vertex buffer object reprezinta un container in care stocam date ce tin de continutul varfurilor precum:

  • pozitie
  • normala
  • culoarea
  • coordonate de texturare
  • etc…

Un vertex buffer object se poatea crea prin comanda OpenGL glGenBuffers:

	GLuint 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

Asa cum se poate vedea si din explicatia API-ului, functia glGenBuffers primeste numarul de buffere ce trebuie generate cat si locatia din memorie unde vor fi salvate referintele (ID-urile) generate.
In exemplu de mai sus este general doar 1 singur buffer iar ID-ul este salvat in variabila VBO_ID.

Pentru a distruge un VBO si astfel sa eliberam memoria de pe GPU se foloseste comanda glDeleteBuffers:

glDeleteBuffers(1, &VBO_ID);

Pentru a putea pune date intr-un buffer trebuie intai sa legam acest buffer la un „target”. Pentru un vertex buffer acest „binding point” se numeste GL_ARRAY_BUFFER, si se poate specifica prin comanda glBindBuffer:

glBindBuffer(GL_ARRAY_BUFFER, VBO_ID);

In acest moment putem sa facem upload de date din memoria CPU catre GPU prin intermediul comenzii glBufferData:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
  • Comanda citeste de la adresa specificata, in exemplul de sus fiind adresa primului varf &vertices[0], si copiaza in memoria video dimensiunea specificata prin parametrul al 2-lea.
  • GL_STATIC_DRAW reprezinta un hint pentru driverul video in ceea ce priveste metoda de utilizare a bufferului. Acest simbol poate avea mai multe valori dar in cadrul laboratorului este de ajuns specificarea prezentata. Mai multe informatii gasiti pe pagina de manual a functiei glBufferData

Pentru a intelege mai bine API-ul OpenGL va rocomandam sa cititi documentatia indicata pentru fiecare comanda prezentata. Atunci cand se prezinta o noua comanda, daca apasati click pe numele acesteia veti fi redirectionati catre pagina de manual a comenzii respective.
De asemenea, documentatia oficiala si completa a API-ului OpenGL poate fi gasita pe pagina OpenGL 4 Reference Pages

Index Buffer Object (IBO)

Un index buffer object (numit si element buffer object) reprezinta un container in care stocam indicii vertex-ilor. Cum VBO si IBO sunt buffere, ele sunt extrem de similare in constructie, incarcare de date si destructie.

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);

La fel ca la VBO, creem un IBO si apoi il legam la un punct de legatura, doar ca de data aceasta punctul de legatura este GL_ELEMENT_ARRAY_BUFFER. Datele sunt trimise catre bufferul mapat la acest punct de legatura. In cazul indicilor toti vor fi de dimensiunea unui singur intreg.

Vertex Array Object (VAO)

Intr-un vertex array object putem stoca toata informatia legata de starea geometriei desenate. Putem folosi un numar mare de buffere pentru a stoca fiecare din diferitele atribute („separate buffers”). Putem stoca mai multe(sau toate) atribute intr-un singur buffer („interleaved” buffers). In mod normal inainte de fiecare comanda de desenare trebuie specificate toate comenzile de „binding” pentru buffere sau atribute ce descriu datele ce doresc a fi randate. Pentru a simplifica acesta operatie se foloseste un vertex array object care tine minte toate aceste legaturi.

Un vertex array object este folosind comanda glGenVertexArrays:

unsigned int VAO;
glGenVertexArrays(1, &VAO);

Este legat cu glBindVertexArray:

glBindVertexArray(VAO);

Inainte de a crea VBO-urile si IBO-ul necesar pentru un obiect se va leaga VAO-ul obiectului si acesta va tine minte automat toate legaturile specificate ulterior.

Dupa ce toate legaturile au fost specificate este recomandat sa dea comanda glBindVertexArray(0) pentru a dezactiva legatura catre VAO-ul curent, deoarece altfel riscam ca alte comenzi ulterioare OpenGL sa fie legate la acelasi VAO si astfel sa introducem foarte usor erori in program.

Inainte de comanda de desenare este suficient sa legam doar VAO-ul ca OpenGL sa stie toate legaturile create la constructia obiectului.

Laborator 2

Descriere laborator

In cadrul laboratorului vom invata sa folosim VAO, VBO, IBO si astfel sa generam si incarcam geometrie simpla.
Laboratorul pune la dispozitie structura VertexFormat ce va fi utilizata ca baza pentru a crea geometria.

struct VertexFormat
{
	// position of the vertex
	glm::vec3 position;		
 
	// vertex normal
	glm::vec3 normal;
 
	// vertex texture coordinate
	glm::uvec2 text_coord;
 
	// vertex color
	glm::vec3 color;
};

Clasa Mesh pune la dispozitie posibilitatea de a incarca geometrie simpla folosind diverse metode:

// Initializes the mesh object using a VAO GPU buffer that contains the specified number of indices
bool InitFromBuffer(unsigned int VAO, unsigned short nrIndices);
 
// Initializes the mesh object and upload data to GPU using the provided data buffers
bool InitFromData(std::vector<VertexFormat> vertices,
		std::vector<unsigned short>& indices);
 
// Initializes the mesh object and upload data to GPU using the provided data buffers
bool InitFromData(std::vector<glm::vec3>& positions,
		std::vector<glm::vec3>& normals,
		std::vector<unsigned short>& indices);

Taste de control pentru camera

  • W, A, S, D, Q, E - miscare fata, stanga, spate, dreapta, jos, sus
  • MOUSE RIGHT + MOUSE MOVE - rotatie camera

F3 - afisează/ascunde gridul din scena
Space - deseneaza primitivele doar prin puncte sau linii(wireframe) sau geometrie opaca

Cerinte laborator

Toate cerintele ce tin de incarcare de geomterie trebuie rezolvate prin intermediul functiei Laborator2::CreateMesh dar puteti folosi metodele Mesh::InitFromData() pentru a verifica validitatea geometriei.

  1. (20p) Completati geometria si topologia unui cub: vectorii de vertecsi si indecsi din initializare. VertexFormat este o structura pentru vertext cu 2 parametri (pozitie, culoare).
  2. (20p) Completati functia Laborator2::CreateMesh astfel incat sa incarcati geometria pe GPU
    • creati un VAO
    • creati un VBO si adaugati date in el
    • create un IBO si adaugati date in el
    • comentati functiile InitFromData (ex: meshes[“cube1”]→InitFromData(vertices, indices);)
    • adaugati la lista de meshe (meshes[]) si desenati obiectul creat cu CreateMesh (“cube3”)
  3. (20p) Creati o noua forma geometrica simpla, de exemplu un tetraedru si desenati-l in scena
  4. (20p) Atunci cand se apasa tasta F2 faceti toggle intre modul de culling GL_BACK si GL_FRONT
    • nu uitati sa activati si sa dezactivati face culling folosind glEnable() / glDisable()
  5. (20p) Creati un patrat format din 2 triunghi-uri astfel incat fiecare triunghi sa fie vizibil doar dintr-o parte
    • in orice moment de timp nu trebuie sa se vada decat 1 triunghi

Total: 100p + Bonus

egc/laboratoare/02.1539079603.txt.gz · Last modified: 2018/10/09 13:06 by alexandru.gradinaru
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