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 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.
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.
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.
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 utilizează informația vecinilor pixelului din care s-a interogat înălțimea vertexului curent.
$$ 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 $$
$$ H_x = height - heightRight \\ H_z = height - heightUp \\ $$
$$ normal = normalize(vec3(H_x, 1, H_z)) $$
Rezultatul după calcularea normalelor și adăugarea în scenă a unei lumini în centrul terenului:
Pentru adăugarea unei texturi de colorare a terenului (de exemplu pamant), se poate crea o coordonată de textură suplimentară doar pentru aceasta sau se pot folosi coordonatele de la harta de înălțimi cu o scalare. Rezultatul final în urma aplicării luminii și a texturii se poate observa mai jos.
Pentru a avea acces la buffer-ul de pixeli al imaginii este necesar să fie încărcată direct cu librăria stb_image. Această librărie se află deja în framework și cu ajutorul ei se poate încărca în memorie întreaga matrice de pixeli a unui fișier de tip imagine.
#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(); glTexImage2D(targetType, 0, GL_RGB, width, height, 0, GL_R, GL_UNSIGNED_BYTE, (void*)img); mapTextures["height"] = texture;
Buffer-ul heightPixels
păstrează toată informația imaginii într-o zonă continuă de memorie în care prima dată se regăsește prima linie de pixeli (fiecare pixel are chn
canale de culoare, bytes), urmată de a doua linie ș.a.m.d. Pentru a modifica textura, pur și simplu se modifică o zonă de pixeli din imagine, în interiorul acestui buffer și se reîncarcă buffer-ul în procesorul grafic.
texture->UploadNewData(heightPixels);