This shows you the differences between two versions of the page.
egc:laboratoare:06 [2019/11/02 10:49] andrei.lambru |
egc:laboratoare:06 [2021/11/19 13:08] (current) victor.asavei [Cerinte laborator] |
||
---|---|---|---|
Line 1: | Line 1: | ||
===== Laboratorul 06 ===== | ===== Laboratorul 06 ===== | ||
- | ==== Banda Grafică ==== | + | **Video Laborator 6**: https://youtu.be/f7q2TGCRly0 \\ |
+ | **Autor**: [[maria_anca.balutoiu@upb.ro | Anca Băluțoiu]] | ||
+ | ==== Banda Grafica ==== | ||
- | Banda Grafică este un lanț de operații executate de procesoarele GPU. Unele dintre aceste operații sunt descrise în programe numite **shadere** (eng. **//shaders//**), care sunt scrise de programator și transmise la GPU pentru a fi executate de procesoarele acestuia. Pentru a le deosebi de alte operații executate în banda grafică, pe care programatorul nu le poate modifica, **shaderele** sunt numite „etape programabile”. Ele dau o mare flexibilitate în crearea de imagini statice sau dinamice cu efecte complexe redate în timp real (de ex. generarea de apă, nori, foc etc prin funcții matematice). | + | Banda Grafica este un lant de operatii executate de procesoarele GPU. Unele dintre aceste operatii sunt descrise in programe numite **shadere** (eng. **//shaders//**), care sunt scrise de programator si transmise la GPU pentru a fi executate de procesoarele acestuia. Pentru a le deosebi de alte operatii executate in banda grafica, pe care programatorul nu le poate modifica, **shaderele** sunt numite „etape programabile”. Ele dau o mare flexibilitate in crearea de imagini statice sau dinamice cu efecte complexe redate in timp real (de ex. generarea de apa, nori, foc etc prin functii matematice). |
- | Folosind OpenGL sunt transmise la **GPU**: coordonatele vârfurilor, matricile de transformare ale varfurilor (M: modelare, V: vizualizare, P: proiecție, MV: modelare-vizualizare, MVP: modelare-vizualizare-proiecție), topologia primitivelor, texturi și ale date. | + | Folosind OpenGL sunt transmise la **GPU**: coordonatele varfurilor, matricile de transformare a varfurilor (M: modelare, V: vizualizare, P: proiectie, MV: modelare-vizualizare, MVP: modelare-vizualizare-proiectie), topologia primitivelor, texturi si ale date. |
{{ :egc:laboratoare:banda_grafica.png?nolink&500 |}} | {{ :egc:laboratoare:banda_grafica.png?nolink&500 |}} | ||
- | 1. În **etapa programabilă VERTEX SHADER** se transformă coordonatele unui vârf, folosind matricea MVP, din coordonate obiect în coordonate de decupare (eng. //clip coordinates//). De asemenea, pot fi efectuate și calcule de iluminare la nivel de vârf. Programul VERTEX SHADER este executat în paralel pentru un număr foarte mare de vârfuri. | + | 1. In **etapa programabila VERTEX SHADER** se transforma coordonatele unui varf, folosind matricea MVP, din coordonate obiect in coordonate de decupare (eng. //clip coordinates//). De asemenea, pot fi efectuate si calcule de iluminare la nivel de varf. Programul VERTEX SHADER este executat in paralel pentru un numar foarte mare de varfuri. |
- | 2. Urmează o **etapă fixă**, în care sunt efectuate următoarele operații: | + | 2. Urmeaza o **etapa fixa**, in care sunt efectuate urmatoarele operatii: |
- | * asamblarea primitivelor folosind vârfurile transformate în vertex shader și topologia primitivelor; | + | * asamblarea primitivelor folosind varfurile transformate in vertex shader si topologia primitivelor; |
- | * eliminarea fețelor nevizibile; | + | * eliminarea fetelor nevizibile; |
- | * decuparea primitivelor la frontiera volumului canonic de vizualizare ([[https://gamedev.stackexchange.com/q/6279|ce înseamnă?]]); | + | * decuparea primitivelor la frontiera volumului canonic de vizualizare ([[https://gamedev.stackexchange.com/q/6279|ce inseamna?]]); |
- | * împărțirea perspectivă, prin care se calculează coordonatele dispozitiv normalizate ale vârfurilor: xd = xc/w; yd = yc/w;zd = zc/w, unde [xc,yc,zc,w] reprezintă coordonatele unui vârf în sistemul coordonatelor de decupare; | + | * impartirea perspectiva, prin care se calculeaza coordonatele dispozitiv normalizate ale varfurilor: xd = xc/w; yd = yc/w;zd = zc/w, unde [xc,yc,zc,w] reprezinta coordonatele unui varf in sistemul coordonatelor de decupare; |
- | * transformarea fereastră–poartă: din fereastra (-1, -1) – (1, 1) în viewport-ul definit de programator. | + | * transformarea fereastra–poarta: din fereastra (-1, -1) – (1, 1) in viewport-ul definit de programator. |
- | 3. Următoarea etapă este **Rasterizarea**. Aceasta include: | + | 3. Urmatoarea etapa este **Rasterizarea**. Aceasta include: |
- | * calculul adreselor pixelilor în care se afișează fragmentele primitivelor (bucățele de primitive de dimensiune egală cu a unui pixel); | + | * calculul adreselor pixelilor in care se afiseaza fragmentele primitivelor (bucatele de primitive de dimensiune egala cu a unui pixel); |
- | * calculul culorii fiecărui fragment, pentru care este apelat programul **FRAGMENT SHADER** | + | * calculul culorii fiecarui fragment, pentru care este apelat programul **FRAGMENT SHADER** |
- | * în etapa programabilă **FRAGMENT SHADER** se calculează culoarea unui fragment pe baza geometriei și a texturilor; programul **FRAGMENT SHADER** este executat în paralel pentru un număr mare de fragmente. | + | * in etapa programabila **FRAGMENT SHADER** se calculeaza culoarea unui fragment pe baza geometriei si a texturilor; programul **FRAGMENT SHADER** este executat in paralel pentru un numar mare de fragmente. |
* testul de vizibilitate la nivel de fragment (algoritmul z-buffer); | * testul de vizibilitate la nivel de fragment (algoritmul z-buffer); | ||
- | * operații raster, de exemplu pentru combinarea culorii fragmentului cu aceea existentă pentru pixelul în care se afișează fragmentul. | + | * operatii raster, de exemplu pentru combinarea culorii fragmentului cu aceea existenta pentru pixelul in care se afiseaza fragmentul. |
- | Rezultatul etapei de rasterizare este o **imagine** memorată într-un tablou de pixeli ce va fi afișat pe ecran, numit //^^frame buffer^^//. | + | Rezultatul etapei de rasterizare este o **imagine** memorata intr-un tablou de pixeli ce va fi afisat pe ecran, numit //^^frame buffer^^//. |
- | <note>Începând cu [[https://en.wikipedia.org/wiki/List_of_Intel_graphics_processing_units#Fifth_generation|a cincea generație]] de procesoare grafice integrate și OpenGL 3.x, între etapele 2 și 3 există încă o etapă programabilă, numită //**Geometry shader**//.</note> | + | <note>Incepand cu [[https://en.wikipedia.org/wiki/List_of_Intel_graphics_processing_units#Fifth_generation|a cincea generatie]] de procesoare video integrate si OpenGL 3.x, intre etapele 2 si 3 exista inca o etapa programabila, numita //**Geometry shader**//.</note> |
==== Shader OpenGL ==== | ==== Shader OpenGL ==== | ||
- | __Pentru implementarea de programe SHADER în OpenGL se folosește limbajul dedicat GLSL (GL Shading Language).__ | + | __Pentru implementarea de programe SHADER in OpenGL se foloseste limbajul dedicat GLSL (GL Shading Language).__ |
- | Legarea unui shader la programul care folosețte OpenGL este o operație complicată, de aceea vă este oferit codul prin care se încarcă un shader. | + | Legarea unui shader la programul care foloseste OpenGL este o operatie complicata, de aceea va este oferit codul prin care se incarca un shader. |
- | Un __**VERTEX SHADER**__ e un program care se execută pentru __**FIECARE**__ vertex trimis către banda grafică. Rezultatul transformărilor, care reprezintă coordonata post-proiecție a vertexului procesat, trebuie scris în variabila standard **[[https://www.opengl.org/wiki/Built-in_Variable_(GLSL)#Vertex_shader_outputs | gl_Position ]]** care e folosită apoi de banda grafică. Un vertex shader are tot timpul o funcție numită main. Un exemplu de vertex shader: | + | Un __**VERTEX SHADER**__ e un program care se executa pentru __**FIECARE**__ vertex trimis catre banda grafica. Rezultatul transformarilor, care reprezinta coordonata post-proiectie a vertexului procesat, trebuie scris in variabila standard **[[https://www.opengl.org/wiki/Built-in_Variable_(GLSL)#Vertex_shader_outputs | gl_Position ]]** care e folosita apoi de banda grafica. Un vertex shader are tot timpul o functie numita main. Un exemplu de vertex shader: |
<code glsl> | <code glsl> | ||
Line 54: | Line 56: | ||
</code> | </code> | ||
- | Un __**FRAGMENT SHADER**__ e un program ce este executat pentru __**FIECARE**__ fragment generat în urma operației de rasterizare ([[https://graphicdesign.stackexchange.com/q/260|ce înseamnă?]]). Fragment shader are în mod obligatoriu o funcție numită main. Un exemplu de fragment shader: | + | Un __**FRAGMENT SHADER**__ e un program ce este executat pentru __**FIECARE**__ fragment generat in urma operatiei de rasterizare ([[https://graphicdesign.stackexchange.com/q/260|ce inseamna?]]). Fragment shader are in mod obligatoriu o functie numita main. Un exemplu de fragment shader: |
<code glsl> | <code glsl> | ||
Line 68: | Line 70: | ||
- | ==== Cum legăm un obiect geometric la shader? ==== | + | ==== Cum legam un obiect geometric la shader? ==== |
- | Legarea între obiecte (mesh, linii etc.) și shadere se face prin atribute. Datorită multelor versiuni de OpenGL există multe metode prin care se poate face această legare. În laborator vom învăța metoda specifică OpenGL 3.3 și OpenGL 4.1. Metodele mai vechi nu mai sunt utilizate decât atunci când hardware-ul utilizat impune restricții de API. | + | Legarea intre obiecte (mesh, linii etc.) si shadere se face prin atribute. Datorita multelor versiuni de OpenGL exista multe metode prin care se poate face aceasta legare. In laborator vom invata metoda specifica OpenGL 3.3 si OpenGL 4.1. Metodele mai vechi nu mai sunt utilizate decat in atunci cand hardware-ul utilizat impune restrictii de API. |
- | API-ul OpenGL modern (3.3+) utilizează metoda de legare bazată pe [[https://www.opengl.org/wiki/Layout_Qualifier_(GLSL)|layout-uri]]. În această metodă se folosesc pipe-uri ce leagă un atribut din OpenGL de un nume de atribut în shader. | + | API-ul OpenGL modern (3.3+) utilizeaza metoda de legare bazata pe [[https://www.opengl.org/wiki/Layout_Qualifier_(GLSL)|layout-uri]]. In aceasta metoda se folosesc pipe-uri ce leaga un atribut din OpenGL de un nume de atribut in shader. |
<code cpp> | <code cpp> | ||
Line 79: | Line 81: | ||
</code> | </code> | ||
- | Prima comandă setează pipe-ul cu numărul 2 ca fiind utilizat. | + | Prima comanda seteaza pipe-ul cu numarul 2 ca fiind utilizat. |
- | A doua comandă descrie structura datelor în cadrul VBO-ului astfel: | + | A doua comanda descrie structura datelor in cadrul VBO-ului astfel: |
- | * pe pipe-ul **2** se trimit la shader 3 float-uri (argument 3) pe care nu le normalizăm (argument 4) | + | * pe pipe-ul **2** se trimit la shader 3 float-uri (argument 3) pe care nu le normalizam (argument 4) |
- | * argumentul 5 numit și **stride**, identifică pasul de citire (în bytes) în cadrul VBO-ului pentru a obține următorul atribut; cu alte cuvinte, din câți în câți octeți sărim când vrem să găsim un nou grup de câte 3 float-uri care reprezintă același lucru | + | * argumentul 5 numit si **stride**, identifica pasul de citire (in bytes) in cadrul VBO-ului pentru a obtine urmatorul atribut; cu alte cuvinte, din cati in cati octeti sarim cand vrem sa gasim un nou grup de cate 3 float-uri care reprezinta acelasi lucru |
- | * argumentul 6 identifică offsetul inițial din cadrul buffer-ului legat la GL_ARRAY_BUFFER (VBO); cu alte cuvinte, de unde plecăm prima oară | + | * argumentul 6 identifica offsetul inital din cadrul buffer-ul legat la GL_ARRAY_BUFFER (VBO); cu alte cuvinte, de unde plecam prima oara. |
- | În __Vertex Shader__ vom primi atributul respectiv pe pipe-ul cu indexul specificat la legare, astfel: | + | In __Vertex Shader__ vom primi atributul respectiv pe pipe-ul cu indexul specificat la legare, astfel: |
<code glsl> | <code glsl> | ||
Line 91: | Line 93: | ||
</code> | </code> | ||
- | Mai multe informații se pot găsi pe pagina de documentație [[https://www.opengl.org/wiki/Layout_Qualifier_(GLSL)#Vertex_shader_attribute_index | Vertex Shader attribute index]]. | + | Mai multe informatii se pot gasi pe pagina de documentatie [[https://www.opengl.org/wiki/Layout_Qualifier_(GLSL)#Vertex_shader_attribute_index | Vertex Shader attribute index]]. |
- | <note tip>Pentru mai multe detalii puteți accesa: | + | <note tip>Pentru mai multe detalii puteti accesa: |
* API-ul de OpenGL aici: https://www.opengl.org/sdk/docs/man/ | * API-ul de OpenGL aici: https://www.opengl.org/sdk/docs/man/ | ||
* API-ul pentru GLSL aici: https://www.opengl.org/sdk/docs/manglsl/ | * API-ul pentru GLSL aici: https://www.opengl.org/sdk/docs/manglsl/ | ||
</note> | </note> | ||
- | <note tip> Un articol despre istoria complicată a OpenGL și competiția cu Direct3D/DirectX poate fi citit [[https://softwareengineering.stackexchange.com/q/60544|aici]]. | + | <note tip> Un articol despre istoria complicata a OpenGL si competitia cu Direct3D/DirectX poate fi citit [[https://softwareengineering.stackexchange.com/q/60544|aici]]. |
</note> | </note> | ||
==== Cum trimitem date generale la un shader? ==== | ==== Cum trimitem date generale la un shader? ==== | ||
- | La un shader putem trimite date de la CPU prin variabile uniforme. Se numesc uniforme pentru că __nu variază pe durata executiei shader-ului__. Ca să putem trimite date la o variabilă din shader trebuie să obținem locația variabilei în programul shader cu funcția [[https://www.opengl.org/sdk/docs/man4/html/glGetUniformLocation.xhtml | glGetUniformLocation]]: | + | La un shader putem trimite date de la CPU prin variabile uniforme. Se numesc uniforme pentru ca __nu variaza pe durata executiei shader-ului__. Ca sa putem trimite date la o variabila din shader trebuie sa obtinem locatia variabilei in programul shader cu functia [[https://www.opengl.org/sdk/docs/man4/html/glGetUniformLocation.xhtml | glGetUniformLocation]]: |
<code cpp> | <code cpp> | ||
Line 110: | Line 112: | ||
</code> | </code> | ||
- | * **shader_program** reprezintă ID-ul programului shader compilat pe procesorul grafic | + | * **shader_program** reprezinta ID-ul programului shader compilat pe placa video |
- | * în cadrul framework-ului de laborator ID-ul se poate obține apelând funcția ''shader->GetProgramID()'' sau direct accesând vriabila membru ''shader->program'' | + | * in cadrul framework-ului de laborator ID-ul se poate obtine apeland functia ''shader->GetProgramID()'' sau direct accesand variabila membru ''shader->program'' |
Line 194: | Line 196: | ||
</note> | </note> | ||
- | - Descarcati [[https://github.com/UPB-Graphics/Framework-EGC/archive/master.zip|framework-ul de laborator]] | + | - Descarcati [[https://github.com/UPB-Graphics/gfx-framework/archive/master.zip|framework-ul de laborator]] |
- Completati functia ''RenderSimpleMesh'' astfel inca sa trimiteti corect valorile uniform catre Shader | - Completati functia ''RenderSimpleMesh'' astfel inca sa trimiteti corect valorile uniform catre Shader | ||
* Se interogeaza locatia uniformelor "Model", "View" si "Projection" | * Se interogeaza locatia uniformelor "Model", "View" si "Projection" | ||
Line 200: | Line 202: | ||
* Daca ati completat corect functia, si ati completat gl_Position in vertex shader, ar trebui sa vedeti un cub pe centrul ecranului rottit 45 grade in jurul lui Y si colorat variat | * Daca ati completat corect functia, si ati completat gl_Position in vertex shader, ar trebui sa vedeti un cub pe centrul ecranului rottit 45 grade in jurul lui Y si colorat variat | ||
- Completati Vertex Shaderul | - Completati Vertex Shaderul | ||
- | - Se de clara atributele de intrare pentru ''Vertex Shader'' folosind layout location <code glsl> | + | - Se declara atributele de intrare pentru ''Vertex Shader'' folosind layout location <code glsl> |
layout(location = 0) in vec3 v_position; | layout(location = 0) in vec3 v_position; | ||
// same for the rest of the attributes ( check Lab6.cpp CreateMesh() ); | // same for the rest of the attributes ( check Lab6.cpp CreateMesh() ); |