Lekce 6

Lekce 6 - Textury

Namapujeme bitmapov² obrßzek na krychli. Pou₧ijeme zdrojovΘ k≤dy z prvnφ lekce, proto₧e je jednoduÜφ (a p°ehledn∞jÜφ) zaΦφt s prßzdn²m oknem ne₧ slo₧it∞ upravovat p°edchozφ lekci.

Porozum∞nφ texturßm mß mnoho v²hod. ╪ekn∞me, ₧e chcete nechat p°elet∞t p°es obrazovku st°elu. A₧ do tohoto tutorißlu byste ji pravd∞podobn∞ vytvo°ili z vybarven²ch n-·helnφk∙. S pou₧itφm textur m∙₧ete vzφt obrßzek skuteΦnΘ st°ely a nechat jej let∞t p°es obrazovku. Co myslφte, ₧e bude vypadat lΘpe? Fotografie, nebo obrßzek posklßdan² z troj·helnφk∙ a Φtverc∙? S pou₧itφm textur to bude nejen vypadat lΘpe, ale i vßÜ program bude rychlejÜφ. St°ela vytvo°enß pomocφ textury bude jen jeden Φtverec pohybujφcφ se po obrazovce. St°ela tvo°enß n-·helnφky by mohla b²t tvo°ena stovkami, nebo tisφci n-·helnφky. Jeden Φtverec pokryt² texturou bude mφt mnohem menÜφ nßroky.

#include <windows.h>// HlaviΦkov² soubor pro Windows

#include <stdio.h>// HlaviΦkov² soubor pro standardnφ vstup/v²stup

#include <gl\gl.h>// HlaviΦkov² soubor pro OpenGL32 knihovnu

#include <gl\glu.h>// HlaviΦkov² soubor pro Glu32 knihovnu

#include <gl\glaux.h>// HlaviΦkov² soubor pro Glaux knihovnu

HDC hDC = NULL;// Privßtnφ GDI Device Context

HGLRC hRC = NULL;// Trval² Rendering Context

HWND hWnd = NULL;// Obsahuje Handle naÜeho okna

HINSTANCE hInstance;// Obsahuje instanci aplikace

bool keys[256];// Pole pro uklßdßnφ vstupu z klßvesnice

bool active = TRUE;// Ponese informaci o tom, zda je okno aktivnφ

bool fullscreen = TRUE;// Ponese informaci o tom, zda je program ve fullscreenu

P°idßme t°i novΘ desetinnΘ prom∞nnΘ... xrot, yrot a zrot. Tyto prom∞nnΘ budou pou₧ity k rotaci krychle okolo os. Poslednφ °ßdek GLuint texture[1] deklaruje prostor pro jednu texturu. Pokud chcete nahrßt vφce ne₧ jednu texturu, zm∞≥te Φφslo jedna na Φφslo odpovφdajφcφ poΦet textur, kterΘ chcete nahrßt.

GLfloat xrot;// X Rotace

GLfloat yrot;// Y Rotace

GLfloat zrot;// Z Rotace

GLuint texture[1];// Uklßdß texturu

Bezprost°edn∞ za p°edchßzejφcφ k≤d a p°ed funkci ReSizeGLScene() p°idßme nßsledujφcφ funkci. Jejφm ·Φelem je nahrßvßnφ souboru s bitmapou. Pokud soubor neexistuje, vrßtφ NULL, co₧ vyjad°uje, ₧e textura nem∙₧e b²t nahrßna. P°ed vysv∞tlovßnφm k≤du je t°eba v∞d∞t n∞kolik VELMI d∙le₧it²ch v∞cφ o obrßzcφch pou₧it²ch pro textury. V²Üka a Üφ°ka obrßzku musφ b²t mocnina dvou, ale nejmΘn∞ 64 pixel∙. Z d∙vod∙ kompatibility by nem∞ly b²t v∞tÜφ ne₧ 256 pixel∙. Pokud by bitmapa, kterou chcete pou₧φt nem∞la velikost 64, 128 nebo 256, zm∞≥te jejφ velikost pomocφ editoru obrßzk∙. Existujφ zp∙soby jak obejφt tyto limity, ale my z∙staneme u standardnφch velikostφ textury. Prvnφ v∞c kterou ud∞lßme je deklarace ukazatele na soubor. Na zaΦßtku jej nastavφme na NULL.

AUX_RGBImageRec *LoadBMP(char *Filename)// Nahraje bitmapu

{

FILE *File=NULL;// Ukazatel na soubor

Dßle se ujistφme, ₧e bylo p°edßno jmΘno souboru. Je mo₧nΘ zavolat funkci LoadBMP() bez zadßnφ jmΘna souboru, tak₧e to musφme zkontrolovat. Nechceme se sna₧it nahrßt nic. Dßle se pokusφme otev°φt tento soubor pro Φtenφ, abychom zkontrolovali, zda soubor existuje.

if (!Filename)// Byla p°edßna cesta k souboru?

{

return NULL;// Pokud ne, konec

}

File=fopen(Filename,"r");// Otev°enφ pro Φtenφ

Pokud se nßm poda°ilo soubor otev°φt, zjevn∞ existuje. Zav°eme soubor a pomocφ funkce auxDIBImageLoad(Filename) vrßtφme data obrßzku.

if (File)// Existuje soubor?

{

fclose(File);// Zav°e ho

return auxDIBImageLoad(Filename);// NaΦte bitmapu a vrßtφ na ni ukazatel

}

Pokud se nßm soubor nepoda°ilo otev°φt soubor vrßtφme NULL, co₧ indikuje, ₧e soubor nemohl b²t nahrßn. Pozd∞ji v programu budeme kontrolovat, zda se vÜe povedlo v po°ßdku.

return NULL;// P°i chyb∞ vrßtφme NULL

}

Nahraje bitmapu (volßnφm p°edchozφho k≤du) a konvertujeme jej na texturu.

int LoadGLTextures()// Loading bitmapy a konverze na texturu

{

Deklarujeme bool prom∞nnou zvanou Status. Pou₧ijeme ji k sledovßnφ, zda se nßm poda°ilo nebo nepoda°ilo nahrßt bitmapu a sestavit texturu. Jejφ poΦßteΦnφ hodnotu nastavφme na FALSE.

int Status=FALSE;// Indikuje chyby

Vytvo°φme zßznam obrßzku, do kterΘho m∙₧eme bitmapu ulo₧it. Zßznam bude uklßdat v²Üku, Üφ°ku a data bitmapy.

AUX_RGBImageRec *TextureImage[1];// Uklßdß bitmapu

Abychom si byli jisti, ₧e je obrßzek prßzdn², vynulujeme p°id∞lenou pam∞¥.

memset(TextureImage,0,sizeof(void *)*1);// Vynuluje pam∞¥

Nahrajeme bitmapu a konvertujeme ji na texturu. TextureImage[0]=LoadBMP("Data/NeHe.bmp") zavolß d°φve napsanou funkci LoadBMP(). Pokud se vÜe poda°φ, data bitmapy se ulo₧φ do TextureImage[0], Status je nastaven na TRUE a zaΦneme sestavovat texturu.

if (TextureImage[0]=LoadBMP("Data/NeHe.bmp"))// Nahraje bitmapu a kontroluje vzniklΘ chyby

{

Status=TRUE;// VÜe je bez problΘm∙

Te∩, kdy₧ mßme nahrßna data obrßzku do TextureImage[0], sestavφme texturu s pou₧itφm t∞chto dat. Prvnφ °ßdek glGenTextures(1, &texture[0]) °ekne OpenGL, ₧e chceme sestavit jednu texturu a chceme ji ulo₧it na index 0 pole. Vzpome≥te si, ₧e jsme na zaΦßtku vytvo°ili mφsto pro jednu texturu pomocφ GLuint texture[1]. Druh² °ßdek glBindTexture(GL_TEXTURE_2D, texture[0]) °ekne OpenGL, ₧e texture[0] (prvnφ textura), bude 2D textura. 2D textury majφ v²Üku (na ose Y) a Üφ°ku (na ose X). Hlavnφ funkcφ glBindTexture() je ukßzat OpenGL dostupnou pam∞¥. V tomto p°φpad∞ °φkßme OpenGL, ₧e volnß pam∞¥ je na &texture[0]. Kdy₧ vytvo°φme texturu, bude ulo₧ena na tomto pam∞¥ovΘm mφst∞. V podstat∞ glBindTexture() ukß₧e do pam∞ti RAM, kde je ulo₧ena naÜe textura.

glGenTextures(1, &texture[0]);// Generuje texturu

glBindTexture(GL_TEXTURE_2D, texture[0]);// TypickΘ vytvß°enφ textury z bitmapy

Vytvo°φme 2D texturu (GL_TEXTURE_2D), nula reprezentuje hladinu podrobnostφ obrßzku (obvykle se zadßvß nula). T°i je poΦet datov²ch komponent. Proto₧e je obrßzek tvo°en Φervenou, zelenou a modrou slo₧kou dat, jsou to t°i komponenty. TextureImage[0]->sizeX je Üφ°ka textury. Pokud znßte Üφ°ku, m∙₧ete ji tam p°φmo napsat, ale je jednoduÜÜφ a univerzßln∞jÜφ nechat prßci na poΦφtaΦi. TextureImage[0]->sizeY je analogicky v²Üka textury. Nula je rßmeΦek (obvykle nechßn nulov²). GL_RGB °φkß OpenGL, ₧e obrazovß data jsou tvo°ena Φervenou, zelenou a modrou v tomto po°adφ. GL_UNSIGNED_BYTE znamenß, ₧e data (jednotlivΘ hodnoty R, G a B) jsou tvo°eny z bezznamΘnkov²ch byt∙ a koneΦn∞ TextureImage[0]->data °φkß OpenGL, kde vzφt data textury. V tomto p°φpad∞ jsou to data ulo₧enß v zßznamu TextureImage[0].

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);// Vlastnφ vytvß°enφ textury

DalÜφ dva °ßdky oznamujφ OpenGL, jakΘ pou₧φt typy filtrovßnφ, kdy₧ je obrßzek v∞tÜφ (GL_TEXTURE_MAG_FILTER) nebo menÜφ (GL_TEXTURE_MIN_FILTER) ne₧ originßlnφ bitmapa. Jß obvykle pou₧φvßm GL_LINEAR pro oba p°φpady. To zp∙sobuje, ₧e textura vypadß hladce ve vÜech p°φpadech. Pou₧itφ GL_LINEAR po₧aduje spoustu prßce procesoru a video karty, tak₧e kdy₧ je vßÜ systΘm pomal², m∞li by jste pou₧φt GL_NEAREST. Textura filtrovanß pomocφ GL_NEAREST bude p°i zv∞tÜenφ vypadat kostiΦkovan∞. Lze takΘ kombinovat obojφ. GL_LINEAR pro p°φpad zv∞tÜenφ a GL_NEAREST na zmenÜenφ.

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);// Filtrovßnφ p°i zmenÜenφ

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);// Filtrovßnφ p°i zv∞tÜenφ

}

Uvolnφme pam∞¥ RAM, kterou jsme pot°ebovali pro ulo₧enφ dat bitmapy. Ujistφme se, ₧e data bitmapy byla ulo₧ena v TextureImage[0]. Pokud ano, ujistφme se, ₧e data byla ulo₧ena v polo₧ce data, pokud ano sma₧eme je. Potom uvolnφme strukturu obrßzku.

if (TextureImage[0])// Pokud obrßzek existuje

{

if (TextureImage[0]->data)// Pokud existujφ data obrßzku

{

free(TextureImage[0]->data);// Uvolnφ pam∞¥ obrßzku

}

free(TextureImage[0]);// Uvolnφ strukturu obrßzku

}

Nakonec vrßtφme status. Pokud je vÜechno v po°ßdku, obsahuje TRUE. FALSE indikuje chybu.

return Status;// Oznßmφ p°φpadnΘ chyby

}

P°idßme pßr °ßdk∙ k≤du do InitGL. VypφÜi celou funkci znovu, tak₧e bude jednoduchΘ najφt zm∞ny. Prvnφ °ßdek if (!LoadGLTextures()) skoΦφ do k≤du, kter² jsme napsali v p°edchozφ Φßsti. Nahraje bitmapu a vygeneruje z nφ texturu. Pokud z jakΘhokoli d∙vodu sel₧e, tak ukonΦφme funkci s nßvratovou hodnotou FALSE. Pokus se texturu poda°ilo nahrßt, povolφme mapovßnφ 2D textur - glEnable(GL_TEXTURE_2D). Pokud jej zapomeneme povolit, budou se objekty obvykle zobrazovat jako bφlΘ, co₧ nßm asi nebude vyhovovat.

int InitGL(GLvoid)// VÜechno nastavenφ OpenGL

{

if (!LoadGLTextures())// Nahraje texturu

{

return FALSE;

}

glEnable(GL_TEXTURE_2D);// Zapne mapovßnφ textur

glShadeModel(GL_SMOOTH);// JemnΘ stφnovßnφ

glClearColor(0.0f, 0.0f, 0.0f, 0.5f);// ╚ernΘ pozadφ

glClearDepth(1.0f);// Nastavenφ hloubkovΘho bufferu

glEnable(GL_DEPTH_TEST);// Zapne hloubkovΘ testovßnφ

glDepthFunc(GL_LEQUAL);// Typ hloubkovΘho testovßnφ

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// NejlepÜφ perspektivnφ korekce

return TRUE;// Inicializace prob∞hla v po°ßdku

}

P°ejdeme k vykreslovßnφ. Pokusφme se o otexturovanou krychli.

int DrawGLScene(GLvoid)// Vykreslovßnφ

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Vyma₧e obrazovku a hloubkov² buffer

glLoadIdentity();// Reset matice

glTranslatef(0.0f,0.0f,-5.0f);// Posun do obrazovky

glRotatef(xrot,1.0f,0.0f,0.0f);// NatoΦenφ okolo osy x

glRotatef(yrot,0.0f,1.0f,0.0f);// NatoΦenφ okolo osy y

glRotatef(zrot,0.0f,0.0f,1.0f);// NatoΦenφ okolo osy z

Nßsledujφcφ °ßdek vybere texturu, kterou chceme pou₧φt. Pokud mßte vφce ne₧ jednu texturu, vyberete ji ·pln∞ stejn∞, ale s jin²m indexem pole glBindTexture(GL_TEXTURE_2D, texture[Φφslo textury kterou chcete pou₧φt]). Tuto funkci nesmφte volat mezi glBegin() a glEnd(). Musφte ji volat v₧dy p°ed nebo za blokem ohraniΦen²m t∞mito funkcemi.

glBindTexture(GL_TEXTURE_2D, texture[0]);// Zvolφ texturu

Ke sprßvnΘmu namapovßnφ textury na Φty°·helnφk se musφte ujistit, ₧e lev² hornφ roh textury je p°ipojen k levΘmu hornφmu rohu Φty°·helnφku ap. Pokud rohy textury nejsou p°ipojeny k odpovφdajφcφm roh∙m Φty°·helnφku, zobrazφ se textura natoΦenß, p°evrßcenß nebo se v∙bec nezobrazφ. Prvnφ parametr funkce glTexCoord2f je sou°adnice x textury. 0.0 je levß strana textury, 0.5 st°ed, 1.0 pravß strana. Druh² parametr je sou°adnice y. 0.0 je spodek textury, 0.5 st°ed, 1.0 vrÜek. Tak₧e te∩ vφme, ₧e 0.0 na X a 1.0 na Y je lev² hornφ vrchol Φty°·helnφka atd. VÜe, co musφme ud∞lat je p°i°adit ka₧dΘmu rohu Φty°·helnφka odpovφdajφcφ roh textury. Zkuste experimentovat s hodnotami x a y funkce glTexCoord2f. Zm∞nou 1.0 na 0.5 vykreslφte pouze polovinu textury od 0.0 do 0.5 atd.

glBegin(GL_QUADS);

// P°ednφ st∞na

glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

// Zadnφ st∞na

glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);

// Vrchnφ st∞na

glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);

// Spodnφ st∞na

glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);

// Pravß st∞na

glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);

// Levß st∞na

glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);

glEnd();

Nakonec zv∞tÜφme hodnoty prom∞nn²ch xrot, yrot a zrot, kterΘ urΦujφ natoΦenφ krychle. Zm∞nou hodnot m∙₧eme zm∞nit rychlost i sm∞r natßΦenφ.

xrot+=0.3f;

yrot+=0.2f;

zrot+=0.4f;

return TRUE;

}

Po doΦtenφ tΘto lekce byste m∞li rozum∞t texturovΘmu mapovßnφ. M∞li by jste b²t schopni namapovat libovolnou texturu na libovoln² objekt. A₧ si budete jistφ, ₧e tomu rozumφte, zkuste namapovat na ka₧dou st∞nu krychle jinou texturu

napsal: Jeff Molofee - NeHe
p°elo₧il: Milan Turek

ZdrojovΘ k≤dy

Lekce 6

<<< Lekce 5 | Lekce 7 >>>