This is an old revision of the document!
Tema 2 - Bokeh Blur
Responsabili: Mihnea-Petruț-Ilie Mitrache, Andrei-Daniel Voicu, Maria Anca Baluțoiu
Lansare: 12.12.2025
Termen de predare: 18.01.2026
-
Notă: Orice informație ce nu a fost acoperită în acest document este la latitudinea voastră!
Descriere generală
Scopul acestei teme va fi implementarea unui efect de blur de profunzime (Depth of Field / Bokeh Blur) aplicat unei imagini 2D, în care zona de focus va fi controlabilă interactiv de către utilizator.
Efectul urmărit este inspirat din tehnicile folosite în motoare grafice moderne (de exemplu, Frostbite), unde zonele din afara planului de focus sunt estompate folosind kernel-uri de blur gaussian (sau combinații de mai multe gaussiene), pentru a simula comportamentul unei lentile reale.
În cadrul temei trebuie:
Să implementați un blur gaussian separabil (orizontal + vertical);
Să controlați dinamic raza de blur în funcție de distanța față de un punct de focus;
Să realizați o interfață grafică interactivă în care utilizatorul poate muta punctul de focus cu mouse-ul și poate modifica raza de focus de la tastatură;
Să evidențiați vizual zona de focus (de exemplu prin desenarea unor cercuri concentrice în jurul cursorului).
Efectul final trebuie să arate ca un blur radial: zona din jurul cursorului este clară, iar blurul crește progresiv odată cu distanța față de aceasta.
Arhitectura generală
Pentru a obține efectul dorit se vor folosi două treceri (2 pass-uri) de procesare pe GPU, pe un quad randat pe tot ecranul, astfel:
Primul pass: blur gaussian orizontal și salvarea valorii de blur;
Al doilea pass: blur gaussian vertical și compunerea rezultatului final.
În plus, se va folosi un shader simplu pentru afișarea texturii procesate și pentru desenarea zonelor de focus (cercurile concentrice).
Pașii principali ai algoritmului sunt următorii:
Se încărcă imaginea inițială ca textură.
Primul pass:
Se calculează, pentru fiecare pixel, distanța până la punctul de focus;
Se determină „cantitatea de blur” (blurAmount) pe baza acestei distanțe;
Se aplică un blur gaussian orizontal, cu o rază care depinde de blurAmount;
Se scrie în două texturi:
Al doilea pass:
Se citește blurAmount din canalul alfa al texturii cu culoarea originală;
Se calculează o nouă rază de blur în funcție de blurAmount;
Se aplică un blur gaussian vertical peste rezultatul orizontal;
Se scrie rezultatul final într-o textură de output.
Afișare:
Se afișează fie imaginea originală, fie un rezultat intermediar, fie imaginea procesată;
Se desenează cercuri concentrice în jurul punctului de focus, pentru a marca vizual zona clară a imaginii.
Calculul cantității de blur
Punctul de focus este dat de poziția cursorului (mousePos) în coordonate ecran. Pentru un pixel cu poziția $(x, y)$, convertită în coordonate ecran, se calculează distanța:
$$
dist = \left\| (x, y) - mousePos \right\|
$$
Se definește un parametru focusRadius:
Un model simplu pentru calculul blurAmount ar putea fi:
$$
normalizedDist = \frac{dist - focusRadius}{focusRadius \cdot 2.0}
$$
$$
blurAmount = clamp(normalizedDist, 0.0, 1.0)
$$
Raza efectivă a blurului este:
$$
dynamicBlurRadius = int(MAX\_BLUR\_RADIUS \cdot blurAmount)
$$
unde MAX_BLUR_RADIUS este o constantă (de exemplu, 40).
Filtru de netezire separabil (blur gaussian)
Pentru blur se folosește un filtru gaussian separabil:
Aceasta reduce complexitatea de la $O(N^2)$ la $O(2N)$ pentru un kernel de dimensiune $N$.
Exemplu de kernel gaussian 1D:
$$
G(x) = \frac{exp\left(-0.5 \cdot \frac{x^2}{\sigma^2}\right)}{\sqrt{2\pi} \cdot \sigma}
$$
Raza blurului și $\sigma$ se pot raporta la blurAmount:
În implementare se poate folosi un singur kernel gaussian sau o combinație de mai multe gaussiene cu $\sigma$ diferite și ponderi diferite, pentru un efect de bokeh mai interesant (de exemplu: 3 gaussiene cu $\sigma$ mic, mediu și mare).
Model de bokeh / blur radial
Pentru a obține un efect de bokeh / blur radial:
cantitatea de blur depinde strict de distanța față de punctul de focus;
zonele apropiate de focus rămân clare;
zonele îndepărtate sunt estompate din ce în ce mai mult.
Opțional, se poate implementa combinarea mai multor gaussiene pentru a simula forme de kernel mai complexe, inspirate de tehnici de tip Circular Separable Convolution Depth of Field utilizate în industria jocurilor (de exemplu, Frostbite).
Interacțiune cu utilizatorul
Poziția mouse-ului definește centrul zonei de focus.
Raza zonei de focus poate fi modificată din tastatură.
La apăsarea unui buton de mouse se poate comuta între:
Pentru a vizualiza mai ușor zona de focus, se desenează cercuri concentrice în jurul mouse-ului, în shaderul de afișare:
se consideră pixelul curent în coordonate de ecran;
se testează dacă pixelul se află la o distanță „aproape egală” cu o rază dată (ex: $r$, $r/2$, $r/4$);
dacă testul este adevărat, acel pixel este colorat alb (sau altă culoare), obținându-se cercuri de ghidaj.
Prezentare rezultat
Aplicația trebuie să permită vizualizarea rezultatelor în mai multe moduri, folosind tastele de pe tastatură:
Tasta 0 – Vizualizare imagine originală;
Tasta 1 – Vizualizare rezultat după primul pass (blur gaussian orizontal + stocarea blurAmount);
Tasta 2 – Vizualizare rezultat final după al doilea pass (blur gaussian vertical);
Tasta 3 – Vizualizare rezultat final + desenarea zonelor de focus (cercuri concentrice);
Tasta 4 – Vizualizare mod interactiv complet (mutarea mouse-ului, modificarea focusRadius, blur actualizat dinamic).
În plus:
Tasta + – creșterea razei de focus (focusRadius);
Tasta - – scăderea razei de focus (focusRadius);
Click stânga – comutare între imaginea originală și imaginea blurată (sau declanșarea procesării blurului).
Implicit, aplicația va porni în modul interactiv complet (tasta 4).
Implementare și restricții
Tema trebuie implementată în C/C++ pentru partea de aplicație și GLSL pentru shadere.
NU este permisă utilizarea de biblioteci de procesare de imagine pentru implementarea efectului de blur. Efectul trebuie implementat în shaderele voastre (GLSL).
Se pot folosi biblioteci pentru:
încărcarea imaginilor (texturi);
managementul ferestrei și contextului OpenGL;
dialoguri de selectare a fișierelor etc.
Comportamentul interactiv (citirea input-ului de mouse/tastatură) se va realiza în C++ și se vor trimite datele relevante (mousePos, focusRadius etc.) în GLSL ca variabile uniforme.
Notare (200p)
Implementare blur gaussian separabil (50p)
Orizontal (25p)
Vertical (25p)
Calcul dinamic al cantității de blur în funcție de distanța față de punctul de focus (40p)
Integrare completă a celor două pass-uri și afișarea corectă a rezultatului final (40p)
Interfață grafică interactivă (30p)
Mutarea punctului de focus cu mouse-ul (10p)
Modificarea razei de focus din tastatură (10p)
Comutare între imagine originală / imagine blurată / rezultate intermediare (10p)
Vizualizarea zonei de focus prin cercuri concentrice (sau alt overlay clar) (40p)
Bonusuri posibile
Utilizarea unei combinații de mai multe gaussiene pentru kernel (mixtură de gaussiene) pentru un efect de bokeh mai realist (10-20p)
Optimizări suplimentare inspirate din tehnici de tip Circular Separable Convolution Depth of Field (10-20p)
Interfață îmbunătățită (de exemplu: afișarea numerică a focusRadius, moduri de vizualizare suplimentare) (10p)
Indicații suplimentare
Este indicat să folosiți framework-ul laboratorului și Visual Studio.
Pentru implementarea temei, în folderul src/lab_m2 puteți crea un nou folder, de exemplu Tema2Bokeh, cu fișierele Tema2Bokeh.cpp și Tema2Bokeh.h (pentru implementare POO, este indicat să aveți și alte fișiere).
Pentru a vedea fișierele nou create în Visual Studio în Solution Explorer:
click dreapta pe filtrul lab_m2 și selectați Add → New Filter;
creați un nou filtru, de exemplu Tema2Bokeh;
click dreapta pe noul filtru și selectați Add → Existing Item;
adăugați toate fișierele din folderul nou creat.
În fișierul lab_list.h trebuie adăugată și calea către header-ul temei, de exemplu:
Arhivarea proiectului
În mod normal arhiva trebuie să conțină toate resursele necesare compilării și rulării.
Înainte de a face arhiva asigurați-vă că ați curățat proiectul Visual Studio:
click dreapta pe proiect în Solution Explorer → Clean Solution
și ștergeți folderul /build/.vs (dacă nu îl vedeți, este posibil să fie ascuns)
SAU ștergeți complet folderul /build.
În cazul în care arhiva tot depășește limita de 50MB, puteți să ștergeți și folderele /deps sau /assets, întrucât se pot adăuga la testare. Nu este recomandat să faceți acest lucru întrucât îngreunează mult testarea în cazul în care versiunea curentă a bibliotecilor/resurselor diferă de versiunea utilizată la momentul scrierii temei.