This is an old revision of the document!
lab_list.h
, linia #include “lab/lab8/lab8.h”
.
In acest laborator, se introduce un alt tip de program de tip shader ce are rolul de a prelucra geometrie, precum triunghiuri. Acest tip de program are scopul de a oferi control dezvoltatorilor asupra geometriei desenate. In banda grafica, el apare dupa pasul de executie a programelor de tip vertex shader si dupa asamblarea informatiilor varfurilor, obtinute de la aceste programe, sub forma de triunghiuri, pe baza indicilor specificati in IBO. Acest proces poate fi vizualizat in imaginea de mai jos.
Pentru fiecare triunghi rezultat in urma procesului de asamblare pe baza indicilor din IBO, se apeleaza o singura instanta de program de tip geometry shader.
Un exemplu de vertex shader:
#version 330 layout(location = 0) in vec3 v_position; layout(location = 1) in vec2 v_texcoord; uniform mat4 Model; uniform mat4 View; uniform mat4 Projection; // coordonatele de textură ale vârfului // atributele de iesire ale unui program de tip vertex shader // sunt atribute de intrare pentru un program de tip geometry shader out vec2 vert_texcoord; void main() { gl_Position = Projection * View * Model * vec4(v_position, 1.0); vert_texcoord = v_texcoord; }
Un exemplu de geometry shader:
#version 330 // geometria primita la intrare este formata dintr-un triunghi layout(triangles) in; // geometria transmisa la iesire layout(triangle_strip, max_vertices = 3) out; // atribut de intrare - coordonatele de textură ale vârfurilor unui triunghi layout(location = 0) in vec2 vert_texcoord[3]; // atribut de iesire - coordonatele textură asociate fiecărui vârf emis layout(location = 0) out vec2 geom_texcoord; void main() { gl_Position = gl_in[0].gl_Position; geom_texcoord = vert_texcoord[0]; EmitVertex(); gl_Position = gl_in[1].gl_Position; geom_texcoord = vert_texcoord[1]; EmitVertex(); gl_Position = gl_in[2].gl_Position; geom_texcoord = vert_texcoord[2]; EmitVertex(); EndPrimitive(); //directiva aceasta încheie primitiva }
layout(triangles) in;
Trebuie să fie unul dintre: points
, lines
, lines_adjacency
, triangles
, triangles_adjacency
. Aceste tipuri de date sunt descrise intr-o sectiune urmatoare.
layout(triangle_strip, max_vertices = 5) out;
Trebuie să fie unul dintre: points
, line_strip
, triangle_strip
. Aceste tipuri de date sunt descrise intr-o sectiune urmatoare.
vec2
. layout(location = 0) in vec2 vert_texcoord[3];
layout(location = 0) in vec2 vert_texcoord[];
gl_in
, din care ne interesează gl_Position
: in gl_PerVertex { vec4 gl_Position; ... } gl_in[];
layout(location = 0) out vec2 geom_texcoord;
Pentru fiecare vârf emis dintr-un program de tip geometry shader, se poate asocia informație despre coordonata de textură, vectorul normal, culoarea și orice alt tip de informație asociată vârfului (specificate înainte de fiecare apel EmitVertex()
).
Acestea trebuie declarate ca variabile de ieșire.
După cum se poate observa, valoarea lui geom_texcoord
este actualizată înainte de fiecare apel EmitVertex()
:
gl_Position = gl_in[0].gl_Position; geom_texcoord = vert_texcoord[0]; EmitVertex();
Într-un geometry shader, se pot emite mai multe primitive (comanda EmitVertex()
se poate da o dată sau de mai multe ori).
La iesirea unui program de tip geometry shader, se permit doar 3 tipuri de date, cum a fost mentionat mai sus: points
, line_strip
si triangle_strip
. Descrierea topologiei pentru fiecare tip de date este dupa cum urmeaza:
points
: se deseneaza un singur pixel, la pozitia din poarta de afisare in care se regaseste fiecare varf emis de un program de tip geometry shader. Un astfel de exemplu este reprezentat vizual in imaginea de mai jos.line_strip
: se deseneaza linii intre fiecare pereche consecutiva de varfuri emise de un program de tip geometry shader. Dupa cum se poate urmari in panoul din mijloc al imaginii de mai jos, pentru o lista de 6 varfuri emise in ordinea { v0, v1, v2, v3, v4, v5 }, se creeaza o linie intre varfurile { v0, v1 }, { v1, v2 }, { v2, v3 }, { v3, v4 } si { v4, v5 }.triangle_strip
: se deseneaza triunghiuri pentru toate tripletele consecutive de varfuri emise de un program de tip geometry shader. Dupa cum se poate urmari in panoul din dreapta al imaginii de mai jos, pentru o lista de 7 varfuri emise in ordinea { v0, v1, v2, v3, v4, v5, v6 }, se creeaza un triunghi cu varfurile { v0, v1, v2 }, { v1, v2, v3 }, { v2, v3, v4 }, { v3, v4, v5 } si { v4, v5, v6 }.
La intrarea unui program de tip geometry shader se permit 5 tipuri de date, cum a fost mentionat mai sus: points
, lines
, lines_adjacency
, triangles
, triangles_adjacency
. Pentru toate tipurile de date se primeste de fapt o singura instanta din acel tip la executia unei instante de program de tip geometry shader. Diferenta principala intre aceste tipuri este data de numarul de atribute de intrare primite in gl_in
si in cele proprii programelor de tip shader. Mai exact:
points
: se primeste exact un singur element in atributele de intrare.lines
: se primesc doua elemente in atributele de intrare.lines_ajacency
: se primesc 4 elemente in atributele de intrare.triangles
: se primesc 3 elemente in atributele de intrare.triangles_adjacency
: se primesc 6 elemente in atributele de intrare.Printre prelucrarile frecvente asupra unui triunghi, se numara calcularea unui centru si a vectorului perpendicular pe planul triunghiului.
Se poate calcula centroidul unui triunghi cu urmatoarea abordare:
vec3 p1 = gl_in[0].gl_Position.xyz; vec3 p2 = gl_in[1].gl_Position.xyz; vec3 p3 = gl_in[2].gl_Position.xyz; vec3 center = (p1 + p2 + p3) / 3;
Se poate calcula vectorul perpendicular pe planul triunghiului cu abordarea:
vec3 p1 = gl_in[0].gl_Position.xyz; vec3 p2 = gl_in[1].gl_Position.xyz; vec3 p3 = gl_in[2].gl_Position.xyz; vec3 v12 = normalize(p2 - p1); vec3 v13 = normalize(p3 - p1); // produs vectorial vec3 normal = cross(v12, v13);
LabShader.GS.glsl
pentru a desena obiectul pentru care se utilizeaza de cel putin 5 ori, la pozitii diferite in scena. Poate fi aliniat pe aceeasi linie.Triangle.GS.glsl
si Color.FS.glsl
pentru a obtine urmatorul rezultat vizual:
Bonus: Creati un alt program de tip geometry shader cu care sa realizati un efect de explozie in care geometria este afectata de gravitatie, similar cu cea din imaginea de mai jos:
Utilizati ecuatia miscarii:
$$ P = P_0 + V \cdot t + \frac{1}{2} \cdot a \cdot t^2 $$
unde V este o directie de miscare specifica fiecarui triunghi :), iar a este vec3(0, -1, 0). Puteti utiliza si alte valori pentru acceleratia gravitatilonala. t este timpul animatiei. Aveti in vedere ca triunghiurile nu coboara sub valoare 0 pentru componenta y. Animatia se reseteaza dupa un anumit timp.