Table of Contents

Laboratorul 08

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 :) .

Pentru rezolvarea cerințelor din cadrul acestui labroator:

  1. Descărcați framwork-ul de laborator și copiați, din arhiva descărcată, directorul Lab8, în interiorul directorului gfx-framework-ppbg\src\lab din versiunea voastră de proiect.
  2. Adăugați în fișierul lab_list.h, linia #include “lab/lab8/lab8.h”.
  3. 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 pagina dedicată acestui lucru.

Programe de tip shader pentru prelucrarea geometriei

În acest laborator, se introduce un nou tip de program de tip shader ce are rolul de a prelucra geometria modelelor 3D, precum triunghiurile dintr-o rețea de triunghiuri prin care este definit un astfel de model. Acest tip de program de tip shader este cunoscut în limba engleză sub numele de geometry shader și are scopul de a oferi control asupra geometriei desenate. În banda grafică, el apare după pasul de asamblare a triunghiurilor, pe baza indicilor specificati în IBO. O privire de ansamblu a benzii grafice, ce cuprinde și programele de tip geometry shader, poate fi vizualizată în imaginea de mai jos.

Pentru fiecare triunghi rezultat în urma procesului de asamblare pe baza indicilor din IBO, se apelează o singură instanță de program de tip geometry shader.

Sintaxa limbajului GLSL

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 textura ale varfului
// 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 textura ale varfurilor unui triunghi
in vec2 vert_texcoord[3];
 
// atribut de iesire - coordonatele textura asociate fiecarui varf emis
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 incheie primitiva 
}

Atribute de intrare și de iesire

Emiterea de primitive

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

Tipuri de primitive

La ieșirea unui program de tip geometry shader, se permit doar 3 tipuri de date, cum a fost menționat mai sus: points, line_strip și triangle_strip. Descrierea topologiei pentru fiecare tip de date este după cum urmează:

La intrarea unui program de tip geometry shader se permit 5 tipuri de date, cum a fost menționat mai sus: points, lines, lines_adjacency, triangles, triangles_adjacency. Pentru toate tipurile de date se primește exact o singură instanță din tipul de date specificat la execuția unei instanțe de program de tip geometry shader. Diferența principală între aceste tipuri de date este numărul de elemente primite în atributele de intrare gl_in și în atributele proprii programelor de tip shader. Mai exact:

Prelucrări la nivel de triunghi

Printre prelucrările frecvente asupra unui triunghi, se numără calcularea unui centru și a vectorului perpendicular pe planul triunghiului.

Se poate calcula centroidul unui triunghi cu următoarea 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);

Cerințe laborator

  1. 0.05p - Completați fișierele LabShader.GS.glsl și Texture.FS.glsl pentru a desena geometria arcașei pe baza texturii. După acest pas, rezultatul vizual ar trebui să fie urmatorul:
  2. 0.05p - Modificați programul de tip geometry shader din fișierul LabShader.GS.glsl pentru a desena obiectele pentru care se utilizează acest program de tip shader de cel puțin 5 ori, la poziții diferite în scenă. Desenările se pot realiza pe aceeași linie, la intervale regulate între ele.
  3. 0.1p - Completați fișierele Triangle.GS.glsl și Color.FS.glsl pentru a obține următorul rezultat vizual:
    • Utilizați programul de tip shader pentru desenarea triunghiului din centru.
    • Pentru a obține rezultatul vizual din imagine, la ieșire trebuie transmise mai multe triunghiuri :) .
  4. 0.05p - Creați un alt program de tip geometry shader cu care să realizați o animație de “explozie” a geometriei, similară cu cea din imaginea următoare:
    • Aveți în vedere că animația de “explozie” se resetează după un interval de timp. Hint: utilizați timpul aplicației și informația vectorilor normali.
  5. 0.05p - Creați un alt program de tip geometry shader cu care să desenați marcaje liniare ce specifică direcția vectorului normal în fiecare vârf al rețelei de triunghiuri ce formează geometria.
    • Desenați de două ori geometria: odată se utilizează un program de tip shader care desenează triunghiurile peste care se aplică textura și o a doua oară în care se utilizează un program de tip geometry shader cu care se desenează liniile ce reprezintă vectorii normali.
    • Specificați tipul geometriei transmise la ieșire în programul de tip geometry shader la line_strip.
    • Trebuie desenată o linie pentru fiecare vârf, cu care se specifică direcția vectorului normal din informația vârfului.
    • Rezultatul vizual ar trebui să fie similar cu cel din imaginea de mai jos:

Bonus: Creați un alt program de tip geometry shader cu care să realizați un efect de explozie în care geometria este afectată de gravitație, similar cu cea din imaginea de mai jos:

Utilizați ecuația mișcării:

$$ P = P_0 + V \cdot t + \frac{1}{2} \cdot a \cdot t^2 $$

unde V este o direcție de mișcare specifică fiecărui triunghi :), iar a este vec3(0, -1, 0). Puteți utiliza și alte valori pentru acceleratia gravitațională. t este timpul animației. Aveți în vedere că triunghiurile nu coboară sub valoarea 0 pentru componenta y. Animația se resetează după un anumit timp.