Framework-ul de laborator este cel de la EGC, îmbogățit cu noi funcționalități. Pentru cei care doresc, conținutul laboratoarelor de EGC se poate găsi în Recapitulare EGC.
Framework-ul de laborator se găsește pe Github
Puteți să descărcați direct arhiva accesând acest link
Pentru implementarea de programe SHADER în OpenGL se folosește limbajul dedicat GLSL (GL Shading Language).
Codul pentru încărcarea unui shader este oferit în funcția init()
din cadrul laboratorului.
Un GEOMETRY SHADER e un program care se execută pentru FIECARE primitivă trimisă către banda grafică. Pe scurt, acest shader primește ca intrare primitive grafice (puncte, linii și triunghiuri) și oferă ca ieșire tot primitive grafice. În banda grafică, așa cum se poate vedea în imaginea de mai sus, se află între Vertex Shader și Fragment Shader. Mai exact, ieșirea de la vertex shader devine intrare pentru geometry shader și ieșirea de la acesta devine intrare pentru fragment shader (după alți câțiva pași ficși).
În continuare vom analiza un geometry shader simplu, precum și comunicarea dintre vertex shader și geometry 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; out vec2 vert_texcoord; //coordonatele textură ale vârfului //ieșirea lui vertex shader este intrare pentru geometry shader void main() { gl_Position = Projection * View * Model * vec4(v_position, 1.0); vert_texcoord = v_texcoord; }
#version 330 layout(triangles) in; //intrarea este un triunghi layout(triangle_strip, max_vertices = 4) out; //ieșirea este un triangle strip. Se vor genera maxim 4 vârfuri layout(location = 0) in vec2 vert_texcoord[3]; //intrarea - coordonatele textură ale vârfurilor unui triunghi layout(location = 0) out vec2 geom_texcoord; //coordonatele textură asociate fiecărui vârf emis 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(); vec3 offset = vec3(1,0,0); gl_Position = gl_in[0].gl_Position + offset; //al patrulea vârf se obține prin translația primului vârf cu un offset geom_texcoord = vert_texcoord[0]; EmitVertex(); EndPrimitive(); //directiva aceasta încheie primitiva //în acest exemplu, primitiva este un triangle_strip cu 4 vârfuri //acesta este echivalent cu două triunghiuri cu indicii 0-1-2 și 1-2-3 }
layout(triangles) in;
Trebuie să fie unul dintre: points
, lines
, lines_adjacency
, triangles
, triangles_adjacency
layout(triangle_strip, max_vertices = 5) out;
Trebuie să fie unul dintre: points
, line_strip
, triangle_strip
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 din geometry shader se pot asocia coordonate textură, normală, culoare, asociate vârfului (setate î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).
Tasta F5 - reîncarcă shaderele în timpul rulării aplicației. Nu este nevoie să opriți aplicația întrucât shaderele sunt compilate și rulate de către procesorul grafic și nu au legătură cu codul sursă C++ propriu zis.
OnKeyPress()
).OnInputUpdate()
(și ar trebui limitat astfel încât efectele scalării să nu devină vizual neplăcute).