This shows you the differences between two versions of the page.
egc:teme:2019:10 [2019/12/05 00:22] andrei.lambru |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Tema 3 - Worms 3D ====== | ||
- | |||
- | * **Responsabili:** Cristian Lambru | ||
- | * **Lansare:** 6 decembrie | ||
- | * **Termen de predare:** 12 ianuarie 2020, ora 23:55 | ||
- | * **Notă: Orice informație ce nu a fost acoperită în acest document este la latitudinea voastră!** | ||
- | |||
- | În cadrul temei 2 trebuie să implementați un joc în care sunteți un aviator ce nu trebuie să se lovească de obstacole și nici să rămână fără combustibil pentru avion. | ||
- | |||
- | ====== Construcția terenului ====== | ||
- | |||
- | ===== Harta de inălțimi ===== | ||
- | |||
- | Definim o suprafață de baleiere descrisă de funcția: | ||
- | |||
- | $$ | ||
- | f(x,z) = y | ||
- | $$ | ||
- | |||
- | Datorită construcției, o astfel de suprafață poate fi determinată direct de conținutul unei texturi în următorul mod: | ||
- | |||
- | $$ | ||
- | f(x,z) = texture2D(unitTexture,vec2 (u,v)).r | ||
- | $$ | ||
- | |||
- | unde $\{u, v\}$ reprezintă coordonatele de textură asociate coordonatelor spațiale $\{x,z\}$. | ||
- | |||
- | Aceste tipuri de texturi, care descriu suprafețe de baleiere, se numesc hărți de inalțime sau **height maps**. Ele conțin în fiecare pixel o singură informație în $[0,255]$ (normalizată $[0,1]$), pe un singur canal, ce reprezintă înălțimea zonei acoperite de pixelul respectiv. Un exemplu de astfel de textură se poate vedea mai jos. | ||
- | |||
- | {{ :egc:teme:2019:heightmap.png?nolink&200 |}} | ||
- | |||
- | ===== Geometria suport ===== | ||
- | |||
- | Pentru a putea crea o suprafață definită de înălțimea datî de textură este necesară o geometrie suport care să cuprindă toate coordonatele $\{x,z\}$ finale și toate coordonatele $y = 0$. De asemenea, fiecărui vertex trebuie să i se asocieze o coordonată de textură, $\{u,v\} \in [0, 1]$, normalizată între limitele geometriei pe $x$ și pe $y$. În mod particular, geometria din imaginea de mai jos a fost generată cu $100$ de linii și $100$ de coloane, pe o suprafață de $5$x$5$ unități. | ||
- | |||
- | {{ :egc:teme:2019:terrain1.png?nolink&600 |}} | ||
- | |||
- | Geometria suport se desenează cu un shader special, care la pasul de vertex shader accesează textura în care se află înălțimile. Prin interogarea texturii se obține înălțimea de la coordonatele $\{u,v\} \in [0,1]$, asociate vertexului. Această valoare se poate asocia direct coordonatei $y$ a vertexului sau se poate scala pentru un impact mai mare al terenului. Rezultatul în urma desenării geometriei suport descrise anterior, cu textura de inălțimi de mai sus, pe care s-a aplicat un factor de scalare al inălțimilor de $2$ se poate observa mai jos. | ||
- | |||
- | {{ :egc:teme:2019:terrain2.png?nolink&600 |}} | ||
- | |||
- | ===== Calculul normalelor ===== | ||
- | |||
- | Pentru a putea lumina terenul este necesară informația de normale. Tehnica pe care o vom folosi se numește "aproximare prin diferențe finite" și utilizeaza informația vecinilor pixelului din care s-a interogat înălțimea vertexului curent. | ||
- | |||
- | * Se obține înălțimea de la poziția curentă, de la poziția din dreapta și din față (axa z). | ||
- | |||
- | $$ | ||
- | height = texture2D(heightMap,vec2(u,v)).r \\ | ||
- | texelSize = vec2 (1.0/heightMapSize.x, 1.0/heightMapSize.y) \\ | ||
- | heightRight = texture2D(heightMap,vec2(u+texelSize.x,v)).r \\ | ||
- | heightUp = texture2D(heightMap,vec2(u,v+texelSize.y)).r | ||
- | $$ | ||
- | |||
- | * Se calculează diferențele pe $x$ și pe $z$. | ||
- | |||
- | $$ | ||
- | H_x = height - heightRight \\ | ||
- | H_z = height - heightUp \\ | ||
- | $$ | ||
- | |||
- | * Normala este reprezentată de vectorul unitate determinat de cele două diferențe finite pe $x$ și pe $z$. | ||
- | |||
- | $$ | ||
- | normal = normalize(vec3(H_x, 1, H_z)) | ||
- | $$ | ||
- | |||
- | <note tip> | ||
- | Deoarece diferențele dintre height și vecini pot fi destul de mici, este recomandat să folosiți un factor de scalare pentru $H_x$ și $H_z$. | ||
- | </note> | ||
- | |||
- | Rezultatul dupa calcularea normalelor si adaugarea in scena a unei lumini in centrul terenului: | ||
- | |||
- | {{ :egc:teme:2019:terrain3.png?nolink&600 |}} | ||
- | |||
- | Pentru adaugarea unei texturi de desenare a terenului (de exemplu pamant), se poate crea o coordonata de textura suplimentara doar pentru ea sau folosirea coordonatelor de la harta de inaltime cu o scalare. Rezultatul final in urma aplicarii luminii si a texturii se poate observa mai jos. | ||
- | |||
- | {{ :egc:teme:2019:terrain4.png?nolink&600 |}} | ||
- | |||
- | ====== Deformarea terenului ====== | ||
- | |||
- | ===== Buffer-ul hartii de inaltimi ===== | ||
- | |||
- | Pentru a avea acces la buffer-ul de pixeli al imaginii este necesar sa o incarcam cu o alta metoda: | ||
- | |||
- | <code cpp>#include <stb/stb_image.h> | ||
- | |||
- | ... | ||
- | |||
- | int width, height, chn; | ||
- | heightPixels = stbi_load((textureLoc + "heightmap.png").c_str (), &width, &height, &chn, 0); | ||
- | |||
- | Texture2D* texture = new Texture2D(); | ||
- | texture->Create(heightPixels, width, height, chn); | ||
- | mapTextures["height"] = texture; | ||
- | </code> | ||
- | |||
- | Buffer-ul ''heightPixels'' pastreaza toata informatia imaginii ca zona continua de memorie in care prima data se gaseste prima linie de pixeli (fiecare pixel are ''chn'' canale de culoare, bytes), urmata de a doua linie samd. Pentru a modifica textura, pur si simplu se modifica o zona de pixeli din imagine, in interiorul acestui buffer si se reincarca buffer-ul la procesorul grafic. | ||
- | |||
- | <code cpp>texture->UploadNewData(heightPixels); | ||
- | </code> | ||
- | |||
- | <note tip> | ||
- | Framework-ul nu stie sa incarce imagini cu un singur canal de culoare, astfel ca toate hartile de inaltimi trebuie sa contina rgb+a canale. | ||
- | </note> | ||
- | |||
- | === Notare (150p) === | ||
- | * Construcția terenului (50p) | ||
- | * Deformarea terenului (50p) | ||
- | * Camera third person + lansare proiectil (20p) | ||
- | * Deplasare proiectil + camera observatie (20p) | ||
- | * Lumini spot deasupra celor doua personaje (10p) | ||
- | |||
- | === Arhivarea proiectului === | ||
- | |||
- | <note> | ||
- | * Î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 dat clean la proiect | ||
- | * Click dreapta pe proiect în **Solution Explorer** -> **Clean Solution**, sau | ||
- | * Ștergeți folderul __**/Visual Studio/obj**__ | ||
- | * Ștergeți fișierul __**/Visual Studio/Framework_EGC.sdf**__ (în caz că există) | ||
- | * Ștergeți fișierul __**/Visual Studio/Framework_EGC.VC.db**__ (în caz că există) | ||
- | * Ștergeți folderul __**/.vs**__ (în caz că există) | ||
- | * Ștergeți folderul __**/x64**__ sau __**/x86**__ (în caz că există) | ||
- | * Executabilul final este generat în folderul __**/x86**__ sau __**/x64**__ la finalul link-editării în funcție de arhitectura aleasă la compilare (32/64 biți) | ||
- | * În cazul în care arhiva tot depășește limita de 20MB (nu ar trebui), puteți să ștergeți și folderul __**/libs**__ sau __**/Resources**__ î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. | ||
- | </note> | ||