This is an old revision of the document!
Î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.
Definim o suprafata de baleiere descrisa de functia:
$$ f(x,z) = y $$
Datorita constructiei, o astfel de suprafata poate fi determinata direct de continutul unei texturi in urmatorul mod:
$$ f(x,z) = texture2D(unitTexture,vec2 (u,v)).r $$
unde $\{u, v\}$ reprezinta coordonatele de textura asociate coordonatelor spatiale $\{x,z\}$.
Aceste tipuri de texturi care descriu suprafete de baleiere se numesc harti de inaltime sau height maps. Ele contin in fiecare pixel o singura informatie in $[0,255]$ (normalizat $[0,1]$), pe un singur canal, ce reprezinta inaltimea zonei acoperite de pixelul respectiv. Un astfel de exemplu de textura se poate vedea mai jos.
Pentru a putea crea o suprafata definita de inaltimea data de textura este necesara o geometrie suport care sa cuprinda toate coordonatele $\{x,z\}$ finale si toate coordonatele y egale cu 0. De asemenea, fiecarui vertex trebuie sa i se asocieze o coordonata de textura, $\{u,v\} \in [0, 1]$, normalizata intre limitele geometriei pe $x$ si pe $y$. In mod particular, geometria din imaginea de mai jos a fost generata cu $100$ de linii si $100$ de coloane, pe o suprafata de $5$x$5$ unitati.
Geometria suport se deseneaza cu un shader special, care la pasul de vertex shader acceseaza textura in care se afla inaltimile. Prin interogarea texturii se obtine inaltimea de la coordonatele $\{u,v\} \in [0,1]$, asociate vertexului. Aceasta valoare se poate asocia direct coordonatei $y$ a vertexului sau se poate scala pentru un impact mai mare al terenului. Rezultatul in urma desenarii geometriei suport descrise anterior, cu textura de inaltimi de mai sus, pe care s-a aplicat un factor de scalare al inaltimilor de $2$ se poate observa mai jos.
Pentru a putea lumina terenul este necesara informatia de normale. Tehnica pe care o vom folosi se numeste “diferente finite” si utilizeaza informatia vecinilor pixelului din care s-a interogat inaltimea vertexului curent.
Se obtine inaltimea de la pozitia curenta, de la pozitia din dreapta si din fata (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 $$
Calculam diferentele pe $x$ si pe $z$.
$$ H_x = height - heightRight \\ H_z = height - heightUp \\ $$
Normala va fi reprezentata de vectorul unitate determinat de cele doua diferente finite pe $x$ si pe $z$.
$$ normal = normalize(vec3(H_x, 1, H_z)) $$
Rezultatul dupa calcularea normalelor si adaugarea in scena a unei lumini in centrul terenului:
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.
Pentru a avea acces la buffer-ul de pixeli al imaginii este necesar sa o incarcam cu o alta metoda:
#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;
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.
texture->UploadNewData(heightPixels);