This shows you the differences between two versions of the page.
spg:laboratoare:01 [2023/10/03 14:20] anca.morar [Geometry Shader] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laboratorul 01 ====== | ||
- | |||
- | |||
- | |||
- | ===== Framework laborator ===== | ||
- | 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 [[:spg:recapitulare]]. | ||
- | |||
- | Framework-ul de laborator se găsește pe [[https://github.com/UPB-Graphics/gfx-framework | Github]] \\ | ||
- | Puteți să descărcați direct arhiva accesând [[https://github.com/UPB-Graphics/gfx-framework/archive/refs/heads/master.zip | acest link ]] | ||
- | |||
- | ===== Pipeline-ul grafic in OpenGL ===== | ||
- | |||
- | {{ :spg:laboratoare:spg_banda_grafica.png?nolink&600 |}} | ||
- | |||
- | ===== Geometry Shader ===== | ||
- | |||
- | __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: | ||
- | |||
- | * Un exemplu de vertex shader: <code glsl> | ||
- | #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; | ||
- | } | ||
- | </code> | ||
- | |||
- | * Un exemplu de geometry shader: <code glsl> | ||
- | #version 330 | ||
- | |||
- | layout(triangles) in; | ||
- | //intrarea este un triunghi | ||
- | |||
- | layout(triangle_strip, max_vertices = 4) out; | ||
- | //ieșirea este un triangle strip cu maxim 4 vârfuri (2 triunghiuri) | ||
- | |||
- | 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 varf se obține din translația primului vârf cu un offset | ||
- | geom_texcoord = vert_texcoord[0]; | ||
- | EmitVertex(); | ||
- | |||
- | |||
- | EndPrimitive(); | ||
- | |||
- | } | ||
- | </code> | ||
- | |||
- | ==== Input si Output ==== | ||
- | |||
- | * Trebuie specificat tipul geometriei de la intrare: <code glsl> | ||
- | layout(triangles) in; | ||
- | </code> Trebuie să fie unul dintre: ''points'', ''lines'', ''lines_adjacency'', ''triangles'', ''triangles_adjacency'' | ||
- | |||
- | * Trebuie specificat tipul geometriei de la ieșire <code glsl> | ||
- | layout(triangle_strip, max_vertices = 5) out; | ||
- | </code> Trebuie să fie unul dintre: ''points'', ''line_strip'', ''triangle_strip'' | ||
- | |||
- | * Se primesc coordonatele de textura de la toată primitiva (triunghiul). Astfel că intrarea va fi un vector de 3 valori //vec2//. <code glsl> | ||
- | layout(location = 0) in vec2 vert_texcoord[3]; | ||
- | </code> | ||
- | * Nu este necesar să se dea dimensiunea vectorului. Astfel, codul de mai sus se poate scrie: <code glsl> | ||
- | layout(location = 0) in vec2 vert_texcoord[]; | ||
- | </code> | ||
- | |||
- | * De asemenea există și intrare implicită la geometry shader, numită ''gl_in'', din care ne interesează ''gl_Position'': <code glsl> | ||
- | in gl_PerVertex | ||
- | { | ||
- | vec4 gl_Position; | ||
- | ... | ||
- | } gl_in[]; | ||
- | </code> | ||
- | |||
- | * Ieșirea lui geometry shader va fi descrisă în secțiunea următoare: <code glsl> | ||
- | layout(location = 0) out vec2 geom_texcoord; | ||
- | </code> | ||
- | |||
- | ==== Emiterea de primitive ==== | ||
- | |||
- | 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()'': | ||
- | |||
- | <code glsl> | ||
- | gl_Position = gl_in[0].gl_Position; | ||
- | geom_texcoord = vert_texcoord[0]; | ||
- | EmitVertex(); | ||
- | </code> | ||
- | |||
- | ==== Cerințe laborator ==== | ||
- | |||
- | <note tip> | ||
- | |||
- | 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. | ||
- | |||
- | </note> | ||
- | |||
- | - Descărcați [[https://github.com/UPB-Graphics/gfx-framework|framework-ul de laborator]] | ||
- | - Adăugați în fragment shader codul pentru aplicarea texturii pe obiect. | ||
- | - Creați mai multe instanțe ale obiectului în geometry shader astfel încât să existe câte 4 bambuși pe o coloană, și cel puțin 2 coloane. Numărul de instanțe se poate controla de la tastatură (folosind funcția ''OnKeyPress()''). | ||
- | - Aplicați vârfurilor fiecărui triunghi o scalare față de centrul său. Factorul de scalare trebuie controlat de la tastatură în funcția ''OnInputUpdate()'' (și ar trebui limitat astfel încât efectele scalării să nu devină vizual neplăcute). | ||
- | |||
- | |||
- | {{:spg:laboratoare:bambusi_pe_coloane.jpg?500| }} | ||
- | {{:spg:laboratoare:shrink.png?500| }} | ||