This is an old revision of the document!


Laboratorul 03

Obiecte de tip framebuffer si umbre

Introducere

In acest laborator vom introduce atat elemente noi de OpenGL, cat si o abordare pentru calcularea umbrelor facute de iluminarea unei surse de lumina de tip spot. Metoda prezentata aici se numeste metoda “maparii umbrelor”, intalnita in engleza sub numele de “Shadow Mapping”, ce a fost prezentata in cadrul cursului de EGC din anul III. O recomandare este sa revizualizati sectiunea despre texturi din pagina de Recapitulare EGC. Aceasta recomandare revine mai jos in pagina, acolo unde notiunile din cursul anterior sunt explicit necesare.

Prima parte a laboratorului se concentreaza doar pe descrierea obiectelor de tip framebuffer. Partea a doua reia sumar Metoda “maparii umbrelor” si ofera mai multe detalii doar despre pasii tehnicii, ce tin de utilizarea obiectelor de tip framebuffer.

Obiecte de tip framebuffer

Redarea scenei in fereastra de desenare se realizeaza, de fapt prin redarea scenei intr-o textura speciala, ce este afisata ulterior in fereastra. OpenGL nu permite desenarea direct intr-o textura, ci impune utilizarea unui obiect suplimentar, numit buffer de cadru sau framebuffer. Acest obiect contine:

  • Texturile cu format de culoare in care se deseneaza scena. Pot sa fie mai multe texturi pe care se deseneaza, pana la un numar limita dat de procesorul grafic, care este in general 8. In laboratorul 6 o sa vedem aplicatii pentru care este necesara desearea in mai multe texturi. Putem sa ne gandim la o textura ca la o structura de date in care pastram informatie oarecare, nu doar culoare. De exemplu: putem pastra pozitia in spatiul lume a fragmentului, obtinuta prin interpolare de la vertecsi, sau vectorul normal in spatiul lume a fragmentului, obtinut prin acelasi proces de interpolare.
  • Textura in care se pastreaza informatia de adancime a fragmentelor desenate in texturile anterioare. Aceasta informatie este utilizata in pasul de test de adancime din procesul de rasterizare.

Pentru a crea un obiect de tip framebuffer, putem folosi directiva OpenGL:

unsigned int framebuffer_object;

glGenFramebuffers(1, &framebuffer_object);

Fereastra de desenare detine un framebuffer implicit, ce este creat automat in framework-ul de laborator prin intermediul librariei GLFW. Astfel, orice redare a scenei se realizeaza initial in texturile acestui framebuffer. Pentru a desena in texturile obiectului de tip framebuffer creat de noi mai sus sau pentru a modifica obiectul, este necesara legarea acestuia dupa cum urmeaza:

glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);

In momentul de fata avem un framebuffer nou, gol, ce nu contine nicio textura de culoare sau de adancime, dar care este legat la banda grafica. Putem lega texturi la framebuffer si atunci cand vom reda o scena si obiectul de tip framebuffer va fi legat la banda grafica, procesul de desenare va scrie rezultatele in texturile obiectului legat de noi.

Reamintim ca pentru a crea o textura cu format de culoare, folosim urmatoarele directive:

unsigned int color_texture;

glGenTextures(1, &color_texture);
glBindTexture(GL_TEXTURE_2D, color_texture);

// Pixelii din interiorul texturii au formatul RGB
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

  • Pentru a revizualiza mai multe detalii despre gestionarea texturilor in API-ul grafic OpenGL, puteti consulta sectiunea despre texturi din pagina de Recapitulare EGC.

Pentru a atasa textura cu format de culoare (R, RG, RGB, RGBA), creata mai sus, la framebuffer folosim:

glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+pct_atasare, color_texture, 0);

Astfel, atasam textura color_texture la obiectul de tip framebuffer legat la banda grafica pe punctul de atasare pct_atasare. Valoarea 0 de la final ne spune ca atasam primul nivel din mipmap (rezolutia maxima). Dupa cum se poate observa, obiectele de tip framebuffer au puncte de atasare, foarte similare ca si concept cu ideea de pipe folosita la definirea informatiei la nivel de vertecsi. In API-ul grafic OpenGL, acest tip de proiectare este foarte des folosit. Daca atasam o textura la un punct de legare pe care deja este legata o alta textura, legatura veche se va pierde si va ramane doar cea noua.

Este important sa observam mai sus ca punctul de atasare este de tip GL_COLOR_ATTACHMENT. Mai exista un alt tip de punct de atasare, cu un singur punct (unic!) folosit pentru textura de adancime, numit GL_DEPTH_ATTACHEMENT. Pentru a lega o textura de adancime (cu format intern GL_DEPTH_COMPONENT) putem folosi comanda:

glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture, 0);

Crearea unei texturi ce contine informatie de adancime este similara cu cea care contine informatie de culoare, descrisa mai sus, cu exceptia formatului definit in directiva glTexImage2D:

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);

Pentru a putea folosi obiectul de tip framebuffer creat mai sunt inca doua etapa de efectuat: setarea texturile cu format de culoare pe care se deseneaza si verificarea statusului de creare a obiectului.

Pentru a seta texturile de desenare folosim:

std::vector<GLenum> draw_textures;

draw_textures.push_back(GL_COLOR_ATTACHMENT0+attachment_index_color_texture);

glDrawBuffers(drawbuffers.size(),&draw_textures[0]);

Pratic, cu directiva glDrawBuffers, setam care sunt texturile in care se deseneaza. In exemplul de mai sus, avem o singura textura atasata pe atasamentul de culoare cu numarul 0, pe care o adaugam intr-un vector pe pozitia 0.  Daca avem obiectul de tip framebuffer in cauza legat la banda grafica si in fragment shader-ul utilizat pentru desenarea in acest framebuffer avem codul de mai jos, deoarece in out_color scriem un pixel rosu, toti pixelii texturii de culoare vor fi rosii.

layout(location = 0) out vec4 out_color;

void main()
{
    out_color = vec4(1, 0, 0, 0);
}

Dupa cum s-a mentionat mai sus, putem avea mai multe texturi cu format de culoare atasate unui framebuffer. Acest mecanim va fi prezentat mai in detaliu in laboratorul 6. Dar, ca o previzualizare a informatiei din acel laborator, codul de mai jos scrie in 4 texturi diferite, de tipuri diferite si se poate observa ca textura din atasamentul de culoare numarul 0 este complet rosie, iar cea din atasamentul de culoare numarul 1 este complet albastra.

layout(location = 0) out vec4 out_color;
layout(location = 1) out vec3 color2;
layout(location = 2) out int int_texture;
layout(location = 3) out float float_texture;

void main()
{
    out_color = vec4 (1, 0, 0, 0);
    color2 = vec3(0, 0, 1);
    int_texture = 1;
    float_texture = 3.14;
}

In acest exemplu, pe atasamentul de culoare numarul 0 merge ce e scris in out_color, pe atasamentul de culoare cu numarul 1 merge ce este scris in color2, pe atasamentul de culoare cu numarul 2 merge ce este scris in some_int_buffer iar pe atasamentul de culoare cu numarul 3 merge ce este scris in some_float_buffer. Dupa cum se poate observa bufferele pot avea tipuri de date diferite.

Ultima etapa necesara inainte de folosirea obiectului de tip framebuffer este testarea corectitudinii crearii sale:

glCheckFramebufferStatus(GL_FRAMEBUFFER);

In momentul in care se doreste din nou redarea scenei in texturile obiectului de tip framebuffer implicit, putem folosi:

glBindFramebuffer(GL_FRAMEBUFFER, 0);

Metoda maparii umbrelor

Noi vom utiliza metoda maparii umbrelor pentru a obtine efectul de umbre ale iluminarii realizate de catre o sursa de lumina de tip spot. Pentru a revizualiza mai multe detalii, va rugam sa consultati sectiunea aferenta acestui tip de sursa de lumina din Recapitulare EGC.

Metoda contine 2 pasi:

  1. Redarea scenei intr-un framebuffer nou. Aceasta redare se realizeaza din pozitia sursei de lumina, pe directia de iluminare a sursei, specifica tipului de sursa spot. Practic, dorim sa vedem ceea ce “vede” sursa de lumina. Pentru simplitate, in laboratorul, sursa va avea un unghi de iluminare de 90 de grade, motiv pentru care se va folosi o proiectie perspectiva cu un unghi de vizualizare atat vertical cat si orizontal de 90 de grade. Obiectul de tip framebuffer obtinut in urma desenarii contine in texturile lui toate punctele din scena iluminate de catre sursa de lumina.
  2. Redarea scenei in texturile obiectului de tip framebuffer implicit din perspectiva observatorului. In aceasta redare, se foloseste textura cu format de adancime obtinuta la pasul anterior. In fragment shader, fiecare fragment se verifica daca este iluminat de catre sursa de lumina sau nu. Daca pozitia in spatiul lume a fragmentului, obtinuta prin interpolare de la vertecsi, “apare” in texturile de culoare ale obiectului de tip framebuffer obtinut prin desenarea scenei de la pasul anterior, inseamna ca este iluminat si pentru acel fragment trebuie sa se calculeze intensitatea iluminarii. Cum este Acest “apare” este descris putin mai in detaliu mai jos.

Pentru a verifica daca pentru un fragment obtinut prin redarea scenei din perspectiva observatorului trebuie sa se calculeze intensitatea iluminarii sau se afla in umbra, putem folosi textura cu format de adancime din obiectul de tip framebuffer obtinut la pasul 1. Se verifica daca distanta dintre pozitia in spatiul lume a fragmentului este aceeasi cu cea din textura cu format de adancime de la pasul 1, cand pozitia fragmentului este proiectata in aceasta textura. Un exemplu poate fi vazut in figura de mai jos, unde pixelul marcat cu rosu in panoul a) este proiectat in pixelul marcat cu rosu din textura de adancime din panoul b). In situatia in care distanta este mai mare decat cea din textura cu format de adancime, inseamna ca in aceasta textura este desenat un obiect ce se afla mai aproape de sursa de lumina si astfel umbreste fragmentul pentru care calculam intensitatea iluminarii. Acest exemplu este chiar in figura de mai jos, unde pozitia fragmentului din panoul a), de pe teren, este mai departe de sursa de lumina fata de fragmentul ce se regaseste la pozitia proiectiei lui in textura cu format de adancime, unde se afla un fragment din frunza bambusului. O observatie importanta de care trebuie sa se tina cont este ca cele doua distante sa se compare in acelasi spatiu.

spg/laboratoare/03.1695945383.txt.gz · Last modified: 2023/09/29 02:56 by andrei.lambru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0