În cadrul temei 3 veți avea de implementat o aplicație grafică bazată pe conceptele de iluminare și texturare - în acest sens, propunem crearea unei scene virtuale ce are ca tematică principală un far (lighthouse), precum și o serie de elemente vizuale menite să sporească realismul scenei - bărcuțe, lună, insulă, etc.
Puteți studia în următorul videoclip o posibilă implementare a cerințelor.
Scena va fi compusă dintr-o serie de modele 3D, anume:
Următoarea imagine prezintă un exemplu de construcție al acestor modele.
Scena virtuală trebuie configurată astfel încât să se poată vizualiza în mod ușor toate elementele de interes. Vă recomandăm o configurație similară cu cea prezentată în demo.
Instanțiere și construcție: În scenă vom avem un număr fix de bărcuțe, minim 4. Bărcuțele trebuie să fie modelate a.î. să se poată identifica direcția lor de deplasare. În demo, direcția este indicată de velă.
Dinamică: Fiecare bărcuță se va deplasa pe un cerc de rază aleatorie, centrat în poziția farului. Punctul de start pe cerc, definit de unghiul de parcurgere a acestuia, este arbitrar. Viteza unghiulară de deplasare și sensul de rotație se modelează de asemenea aleatoriu.
Camera va fi de tip perspectivă și trebuie poziționată astfel încât să fie surprinse în același timp toate elementele de interes din scenă (apa, insula, farul, luna, bărcuțele). Nu este obligatoriu să controlați poziția/rotația camerei în timpul rulării aplicației, aceasta poate să rămână statică.
Este obligatorie texturarea fiecărui element de geometrie prezentat în secțiunea Scena Virtuală, cu excepția mesh-ului corespunzător reflectorului din far.
Pe mesh-ul corespunzător apei va trebui aplicată o textură care se repetă. Acest lucru se poate obține prin oricare dintre următoarele 2 moduri:
wrapping_mode
-ului texturii cu GL_REPEAT
.
De asemenea, vă recomandăm utilizarea unei texturi de tip “seamless” pentru acest task.
Textura apei va trebui modificată în mod continuu pentru a crea un efect de mișcare al acesteia. Pentru a obține acest efect este nevoie de translatarea în funcție de timp a coordonatelor de texturare.
Este obligatorie implementarea acestei cerințe în shader - un efect similar se poate obține prin simpla translatare a mesh-ului în mod continuu, ceea ce este nepermis.
Engine::GetElapsedTime()
pentru a obține timpul scurs de la pornirea aplicației.
Pentru a reda un efect de valuri, textura aplicată apei va trebui alterată în mod continuu în fragment shader. Rezultatul implementării voastre nu trebuie să replice în mod direct exemplul din demo, dar este necesar să se supună următoarelor reguli:
Pentru a înțelege mai bine conceptul puteți studia următorul snippet de cod - acesta colorează mesh-ul de apă în funcție de poziția în spațiul lume a fragmentelor. Observați faptul că aceeste coordonate (s-a considerat numai coordonata X a acestora) sunt modulate folosind o funcție trigonometrică.
// GLSL code // sin() outputs in range [-1;1]. Adding 1 and multiplying with 0.5 remaps result to [0;1] range (for rendering purposes). vec2 modulated_coords = (vec2(sin(world_position.x * 10)) + 1) * 0.5; out_color = vec4(modulated_coords.x, modulated_coords.x, modulated_coords.x, 1);
În imaginea de mai jos puteți observa efectul obținut:
În GIF-ul de mai jos puteți observa în partea stângă textura apei care suferă doar efectul de translație, iar în partea dreaptă un exemplu pentru translație + efectul de valuri.
Iluminarea scenei se va implementa folosind 3 tipuri de surse de lumină: punctiformă, direcțională și spotlight. Fiecare sursă de lumină (indiferent de tipul acesteia) o să aibă o culoare specifică și trebuie să se țină cont de această culoare pentru iluminare.
Lumina punctiformă: acest tip de sursă de lumină este cel prezentat la laborator. Este necesar să se folosească acest tip de lumină pentru:
În următoarea imagine au fost activate numai luminile punctiforme:
Lumina direcțională: aceasta va ilumina toate obiectele din scenă cu aceeași intensitate. Specific luminii de tip direcțional este faptul că vectorul luminii incidente $L$ nu depinde de poziția luminii sau a fragmentului care trebuie iluminat (precum în cazul luminilor de tip point și spot). Așadar, pentru fiecare fragment, iluminarea va fi calculată folosind același vector $L$ (corespunzător direcției luminii). Astfel, pentru o sursă de lumină de tip direcțional este nevoie să se definească direcția acesteia și culoarea luminii emise. În cadrul acestei teme vom considera luna ca `sursa` acestei lumini direcționale, așadar, va trebui să setați direcția acestei lumini în mod corespunzător.
În următoarea imagine a fost activată numai lumina direcțională - observați iluminarea pe partea stângă a farului, corespunzătoare direcției cerute.
Lumina de tip spotlight: acest tip de sursă de lumină este cel prezentat la laborator. Este necesar să se folosească 2 surse de acest tip pentru far, poziționate în partea superioară a acestuia, care să se rotească în jurul farului în mod continuu. Între direcțiile celor 2 surse spotlight trebuie să fie un defazaj de 180°. De asemenea, luminile spotlight trebuie să fie colorate (detalii în secțiunea Interfața cu utilizatorul)
În următorul GIF puteți observa un exemplu de implementare pentru comportamentul acestor spotlight-uri.
Mesh-ul reflector al farului nu trebuie iluminat - în schimb, acesta trebuie randat folosind numai componenta emisivă - efectul dorit este ca acest mesh să aibă aparența unei zone care emite lumină. Culoarea va fi setată corespunzător culorii luminilor implementate pe far (point și spotlight).
Mesh-ul lunii trebuie texturat cu o imagine a lunii. Pentru a oferi o strălucire lunii este necesar ca randarea acesteia să includă și o componentă emisivă de culoare albă.
Interfața cu utilizatorul constă în implementarea a 3 slider-e, ce au scopul de a controla culoarea luminilor emise de către far (point și spotlight), precum și culoarea mesh-ului reflector. Fiecare slider va controla contribuția unei componete de culoare (R, G, B), iar culoarea finală va fi calculată corespunzător acestor contribuții.
Construcție: Slider-ele pot fi construite din pătrate scalate. Este necesar ca fiecare slider să fie construit din 2 astfel de pătrate - unul pentru componenta statică a slider-ului (background-ul), celălalt pentru componenta interactivă (care se poate scala). Componenta interactivă trebuie colorată corespunzător canalului de culoare pe care o controlează.
Interacțiune: Aceasta se va realiza prin intermediul a 6 taste - pentru fiecare slider se vor folosi câte 2 taste, una pentru a crește valoarea contribuției, cealaltă pentru scăderea acesteia. Partea interactivă a slider-elor se va scala corespunzător valorii contribuției. Această interacțiune trebuie să aibă loc în fiecare frame în care tastele sunt ținute apăsate.
Pentru randarea slider-ului vă recomandăm următoarele (nu sunt cerințe impuse):
Pentru întrebări vom folosi forumurile de pe Moodle. Orice nu este menționat în temă este la latitudinea fiecărui student!
Baremul este orientativ. Fiecare asistent are o anumită libertate în evaluarea temelor (de exemplu, să dea punctaj parțial pentru implementarea incompletă a unei funcționalități sau să scadă pentru hard coding). Același lucru este valabil atât pentru funcționalitățile obligatorii, cât și pentru bonusuri.
Tema va fi implementată în OpenGL și C++. Este indicat să folosiți framework-ul și Visual Studio.