7. Textúrázás¶
A megjelenítendő alakzatainkat a korábban bemutatott módszerekkel már gyakorlatilag tetszőleges pontossággal le tudnánk írni. A megjelenítés minősége szempontjából textúrákat nem feltétlenül lenne szükséges, viszont számos érv szól a használatuk mellett.
A megjelenítés hatékonyságát lényegesen javítja, hogy ha egy bizonyos részletességi szintet már csak képként veszünk számításba.
A kétdimenziós képek tárigénye kisebb, mint ha a geometriát, a színeket és az anyagjellemzőket egyidejűleg tárolnánk.
A mintázatokat gyakran két dimenziós képként (például lefényképezve) tudjuk legegyszerűbben digitalizálni. Textúraként azok (minimális átalakítással) használhatók.
Gyakran előfordul, hogy azonos modelleket különböző mintázatokkal szeretnénk megjeleníteni. Ilyen esetben a modelltől függetlenül tudjuk kezelni a mintázatát.
A mintázat szerkesztését két dimenzióban lényegesen egyszerűbb elvégezni, mint háromban.
A textúrázás segítséget jelent, hogy ha különböző részletességi szinteket (Level of Details) szeretnénk használni.
A textúrázás folyamata¶
Ahhoz, hogy textúrákat használjunk, az alábbi részproblémák megoldására van szükségünk.
Be kell töltenünk a textúrához tartozó képeket egy (jellemzően ismert képformátumú) fájlból.
Be kell kapcsolnunk a textúrázást.
Létre kell hoznunk OpenGL-ben egy textúra objektumoat, amelyre azt követően az OpenGL-től visszakapott azonosítóval tudunk hivatkozni.
Meg kell adnunk azt a leképzést, amellyel a mintázatot az adott modellre „feszítjük”.
Megjegyzés
Az említett lépések közben további számos beállítási lehetőségünk van, és az esetleges hibákat kezelni kell!
Képformátumok¶
A képformátumokat jellemzően a kiterjesztésük szerint nevezzük. A következőkben néhány elterjedt képformátumot tekintünk át.
A formátumokat különféle szempontok alapján tudjuk csoportosítani, például:
Vektorgrafikusak vagy raszteresek?
Binárisak vagy szövegesek?
Veszteségesek vagy veszteségmentesek?
Tömörítettek vagy tömörítetlenek?
Támogatják a palettás színmegadást?
Mennyi színt képesek kezelni (összesen és egyidejűleg)?
Lehet-e bennük animációt tárolni?
Támogatják az átlátszóságot?
Támogatják az interlacing-et?
Milyen a licenszük?
Mennyire támogatottak?
Megjegyzés
Általában bináris formátumokat használnak, de szöveges formátumként is találkozhatunk például a PPM-mel.
BMP¶
Bitmap (BitMaP)
Egyszerű, tömörítetlen formátum
A Microsoft dolgozta ki.
Egy fejléc részt követően a képpontok színei kerülnek benne felsorolásra.
GIF¶
Graphics Interchange Format
Aránylag egyszerű, kevés színből álló képekhez dolgozták ki.
Támogatja a palettás színtárolást.
Támogatja az átlátszóságot.
Animációk tárolására is alkalmas.
Támogatja az interlacing-et.
LZW, veszteségmentes tömörítést használ.
JPG, JPEG¶
Joint Photographic Expert Group
Főként fénykép jellegű képek tárolására használják.
Veszteséges, tömörített formátum (általában).
PNG¶
Portable Network Graphics
Veszteségmentes, tömörített formátum (általában).
Támogatja az átlátszóságot.
Támogatja az interlacing-et.
Animált változata az MNG és az APNG.
A kezdetektől nyílt szabvány.
WebP¶
WebP (Web Picture), WebM (Web Media)
A Google fejlesztette a GIF, JPG és a PNG leváltása céljából.
Támogatja a tömörítetlen és a tömörített tárolást, az átlátszóságot és az animációt.
Áttekintés¶
Textúra betöltés¶
SDL2 részről¶
SDL2-höz tartozik egy SDL Image nevű kiegészítő library:
A következő include szükséges hozzá:
#include <SDL2/SDL_image.h>
A programon belül inicializálni kell:
int inited = IMG_Init(IMG_INIT_PNG);
Kép betöltése:
SDL_Surface* surface = IMG_Load(path);
A képet (mint Surface
struktúrát) fel is kell szabadítanunk, ha már nem használjuk:
SDL_FreeSurface(surface);
OpenGL részről¶
GLuint texture_name;
glGenTextures(1, &texture_name);
A textúra neve, az gyakorlatilag az egyedi azonosítója.
Ki tudjuk választani az aktuális textúrát:
glBindTexture(GL_TEXTURE_2D, texture_name);
Az aktuális textúrához hozzá tudjuk rendelni a pixeltömböt:
typedef GLubyte Pixel[3];
// ...
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
surface->w,
surface->h,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
(Pixel*)(surface->pixels)
);
Paraméterezése:
void glTexImage2D(
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const void* data
);
Referencia:
Figyelem
Az OpenGL a kettő hatványnak megfelelő felbontású (többségében négyzetes) textúrákat preferálja.
Textúra leképzés¶
A textúrák terét egy két dimenziós térnek tekintjük, melyekben a képpontokat \((u, v)\) koordinátákkal adjuk meg. A textúraként használt képet ezen belül is a \([0, 1]^2\) egységnégyzeten belül rögzítjük.
A megjelenítésnél a megjelenítendő képpontokhoz meg kell határoznunk, hogy milyen \((u, v)\) koordináták tartoznak.
Egy felületi pontot két paraméterrel szoktunk megadni. A leképzés központi problémája az, hogy ezen paraméterekhez hogyan rendeljük hozzá a megfelelő \((u, v)\) értékeket. A hozzárendelés módja alakzatonként változó.
A Föld térképének készítésénél és csomagolásnál is hasonló problémák merülnek fel. A leképzés
nem feltétlenül tartja meg a távolságokat, arányokat,
a leképzés nem feltétlenül invertálható.
Egységnégyzet¶
Tegyük fel, hogy a textúrázandó alakzatunk egy egységnyi oldalhosszúságú négyzet. Az ehhez tartozó felületi pontokhoz használjuk az \((x, y)\) koordinátákat. Ekkor a leképzés egyszerűen az \((u, v) = (x, y)\) alakban írható föl.
\(\rhd\) Hogyan képezhetjük le egy téglalap pontjait?
Háromszög¶
Tegyük fel, hogy adott egy háromszög. A csúcsaihoz a textúra térben az \((u_1, v_1)\), \((u_2, v_2)\) és \((u_3, v_3)\) pontokat rendeljük. A képtérben meghatározzuk a megjelenítendő felületi ponthoz tartozó \((s, t)\) koordinátákat, majd ezek alapján kiszámítjuk a keresett \((u, v)\) koordinátákat.
Henger¶
A henger palástjának felületi pontjait jellemezzük a \((\varphi, h)\) koordinátákkal, ahol \(\varphi \in [0, 2\pi)\) és \(h \in [0, 1]\). Egy jellemző textúra leképzési mód:
A henger tengelyétől való távolságot jelöljük \(r \in [0, 1]\) értékkel! A henger körlapjaira a textúrát (polár koordináták alapján leképezve) például az alábbi formában adhatjuk meg:
\(\rhd\) Hogyan képezhetjük le egy kúp felületének pontjait?
Gömb¶
A megjelenítendő gömb felületi pontjait adjuk meg a \((\varphi, \vartheta)\) gömbi koordinátákkal, ahol \(\varphi \in [0, 2\pi)\) és \(\vartheta \in [-\pi, \pi]\)! A leképzés definiálható például az alábbi formában:
Modellek textúrázása¶
A textúrázáshoz a poligon modelljeinket ki kell teríteni a síkba.
Unwrapping
Ez egy komplikált topológiai, gráfelméleti, optimalizálási probléma.
Több lehetséges megoldási mód is adódik.
Általában „kézzel”, modellszerkesztő használatával lehet végrehajtani.
\(\rhd\) Vizsgáljuk meg konkrét modellek esetében, hogy hogyan oldották meg az UV leképzést!
Mintavételezés¶
A képtér felbontása általában nem ugyanakkora, mint a textúratér felbontása. Emiatt előfordulhat, hogy
a textúrákat nagyítani kell (valamelyik tengely szerint), de az is, hogy
kicsinyíteni kell (valamilyen tengely szerint).
\(\rhd\) Mutassunk példát olyan esetre, amelynél egyik tengely szerint nagyítunk, a másik szerint kicsinyítünk!
A textúra nagyításánál a textúratér belső pontjait mintavételezni kell.
Választhatjuk a legközelebbi képpont színét (
GL_NEAREST
), vagybilineáris interpolációval közelíthetjük a színt (
GL_LINEAR
).
\(\rhd\) Vizsgáljuk meg, hogy milyen hatása van az említett paramétereknek a kép minőségére!
Kicsinyítés esetén a környező képpontok intenzitásait kell átlagolni.
Ez egy számításigényes művelet, ezért előre ki szokták számolni a kisebb felbontású textúrákat.
Ezeket textúra piramisokba (MIP-maps, texture pyramids) szervezik.
Átlátszóság kezelése¶
Blending
A már megjelenítendő képpont színét módosítja.
A color buffer itt destination buffer-ként fordul elő.
Hogy ha nem adunk meg alfa értéket, akkor az alapértelmezés szerint 1.
A blending-et a következőképpen írhatjuk le:
ahol
\(C_f\): az eredményként kapott szín (final),
\(S \in [0, 1]\): az új szín skálázási tényezője,
\(C_s\): az újonnan megjelenő szín (source),
\(D \in [0, 1]\): az aktuális szín skálázási tényezője,
\(C_d\): az aktuális szín (destination).
Megjegyzés
Ez csak egy egyszerűbb egyenlet a beállíthatók közül!
A blending-et OpenGL-ben a fényekhez és textúrákhoz hasonlóan lehet bekapcsolni:
glEnable(GL_BLEND);
Az átlátszóság beállításához általában az alábbi paraméterek megadása szükséges:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
A függvény paraméterezése:
void glBlendFunc(
GLenum sfactor,
GLenum dfactor
);
Ez tehát azt jelenti, hogy
Példa
Tegyük fel, hogy egy képpont \((0.2, 0.8, 0.1)\) színű. Milyen lesz az eredményként kapott szín, hogy ha erre egy \((1, 0, 0.3)\) színnel, \(\alpha = 0.5\) értékkel rajzolunk?
A kapott szín: \((0.6, 0.8, 0.2)\).
Kérdések¶
Miért van szükség textúrákra? Meg tudnánk-e jeleníteni ugyanazt a virtuális teret texturák nélkül is?
Hogyan tudjuk felhasználni ugyanazon texturát több modell esetében is?
Praktikusan milyen méretezésűnek kell lenni egy textúrának?
Melyek az elterjedt tömörített és tömörítetlen képformátumok?
Melyek az elterjedt veszteséges és veszteségmentes képformátumok?
Mit jelent a bilineáris transzformáció textúrázás esetében? Miért van rá szükség?
Mi alapján tudunk egy texturát hivatkozni egy OpenGL programban?
Milyen szempontok alapján tudjuk csoportosítani a képformátumokat?
Milyen előnyei és hátrányai vannak a veszteséges képformátumoknak?
Mit jelent a palettás színkezelés a képformátumok esetében?
Soroljon fel legalább 3 olyan képformátumot (rövidítéssel és teljes névvel), amelyik támogatja az átlátszóságot!
Egy 1 megapixeles fényképet letárolunk BMP, PNG és JPG formátumban. Milyen sorrendben következnek a fájlformátumok a fájl feltételezett mérete alapján? Mi ennek az oka?
Számítási feladatok¶
Egy egység magas, egységnyi sugarú körökkel adott henger palástjának \(30^{\circ}\)-hoz és 0.2 egység magasságához tartozó pontjának színét szeretnénk meghatározni. Milyen \((u, v)\) koordináták tartoznak hozzá?
Határozzuk meg egy gömbfelület \(\varphi = 15^{\circ}\) és \(\vartheta = 100^{\circ}\) paramétereihez tartozó \((u, v)\) koordinátákat!
Bilineáris interpolációval mintavételezni szeretnénk egy textúrát. A legközelebbi ismert pontokban a \((8, 2)\) színe kék, a \((8, 3)\) színe sárga, a \((9, 2)\) színe fekete a \((9, 3)\) színe pedig piros. Milyen színű lesz a \((8.7, 2.2)\) pont színe?
Adott egy \(1024 \times 1024\) méretű, RGB formátumú textúra. Az eredeti textúrával együtt mennyi tárterületet fog foglalni az előállított MIP-maps?
Megjegyzés
A feladatok megoldásához rajzoljunk ábrát is, és részletezzük a számításokat!
Programozási feladatok¶
Oldjuk meg, hogy a különböző lapokon különböző textúra legyen!
Vizsgáljuk a textúrázást a
cube
példában!Állítsuk be a fényeket és az anyagjellemzőket is!
Jelenítsünk meg egy képet úgy, hogy közben nem perspektivikus vetítést használunk!
Generáljunk sakktábla mintás textúrát!
Rajzoljunk egy körlapot egy textúrára!
Készítsünk színátmenetes textúrát!
Mozgassuk az \((u, v)\) koordinátákat!
Idő függvényében váltogassuk egy modell textúráját!
Textúrázzuk az ütőket, hátteret és a labdát a
pong
játékban!