V tomto dφlu se pokusφm vysv∞tlit pou₧itφ t°φ odliÜn²ch texturov²ch filtr∙. Dßle pak pohybu objekt∙ pomocφ klßvesnice a nakonec aplikaci jednoduch²ch sv∞tel v OpenGL. Nebude se jako obvykle navazovat na k≤d z p°edchozφho dφlu, ale zaΦne se p∞kn∞ od zaΦßtku.
#include <windows.h>// HlaviΦkov² soubor pro Windows
#include <stdio.h>// HlaviΦkov² soubor pro standartdnφ 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 booleovskΘ prom∞nnΘ. Prom∞nnß light sleduje zda je sv∞tlo zapnutΘ. Prom∞nnΘ lp a fp nßm indikujφ stisk klßvesy 'L' nebo 'F'. ProΦ je pot°ebujeme se dozvφme dßle. Te∩ staΦφ v∞d∞t, ₧e zabra≥ujφ opakovßnφ obslu₧nΘho k≤du p°i delÜφm dr₧enφ.
bool light;// Sv∞tlo ON/OFF
bool lp;// Stisknuto L?
bool fp;// Stisknuto F?
GLfloat xrot;// X Rotace
GLfloat yrot;// Y Rotace
GLfloat xspeed;// Rychlost x rotace
GLfloat yspeed;// Rychlost y rotace
GLfloat z=-5.0f;// Hloubka v obrazovce
Nßsledujφ pole pro specifikaci sv∞tla. Pou₧ijeme dva odliÜnΘ typy. Prvnφ bude okolnφ (ambient). Okolnφ sv∞tlo nevychßzφ z jednoho bodu, ale jsou jφm nasvφceny vÜechny objekty ve scΘn∞. Druh²m typem bude p°φmΘ (diffuse). P°φmΘ sv∞tlo vychßzφ z n∞jakΘho zdroje a odrß₧φ se o povrch. Povrchy objektu, na kterΘ sv∞tlo dopadß p°φmo, budou velmi jasnΘ a oblasti mßlo osv∞tlenΘ budou temnΘ. To vytvß°φ p∞knΘ stφnovΘ efekty po stranßch krabice. Sv∞tlo se vytvß°φ stejn²m zp∙sobem jako barvy. Je-li prvnφ Φφslo 1.0f a dalÜφ dv∞ 0.0f, dostßvßme jasnou Φervenou. Poslednφ hodnotou je alfa kanßl. Ten tentokrßt nechßme 1.0f. ╚ervenß, zelenß a modrß nastavenΘ na stejnou hodnotu v₧dy vytvo°φ stφn z ΦernΘ (0.0f) do bφlΘ (1.0f). Bez okolnφho sv∞tla by mφsta bez p°φmΘho sv∞tla byla p°φliÜ tmavß.
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };// Okolnφ sv∞tlo
V dalÜφm °ßdku jsou hodnoty pro p°φmΘ sv∞tlo. Proto₧e, jsou vÜechny hodnoty 1.0f, bude to nejjasn∞jÜφ sv∞tlo jakΘ m∙₧eme zφskat. P∞kn∞ osvφtφ krabici.
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };// P°φmΘ sv∞tlo
Nakonec nastavφme pozici sv∞tla. Proto₧e chceme aby sv∞tlo svφtilo na bednu zp°edu, nesmφme pohnout sv∞tlem na ose x a y. T°etφ parametr nßm zaruΦφ, ₧e bedna bude osv∞tlena zep°edu. Sv∞tlo bude zß°it sm∞rem k divßkovi. Zdroj sv∞tla neuvidφme, proto₧e je p°ed monitorem, ale uvidφme jeho odraz od bedny. Poslednφ Φφslo definujeme na 1.0f. UrΦuje koordinßty pozice sv∞telnΘho zdroje. Vφce v dalÜφ lekci.
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };// Pozice sv∞tla
Prom∞nnß filter bude pou₧ita p°i zobrazenφ textury. Prvnφ textura je vytvß°ena pou₧itφm GL_NEAREST. Druhß textura bude GL_LINEAR - filtrovßnφ pro ·pln∞ hladk² obrßzek. T°etφ textura pou₧φvß mipmapingu, kter² tvo°φ hodn∞ dobr² povrch. Prom∞nnß filter tedy bude nab²vat hodnot 0, 1 a 2. GLuint texture[3] ukazuje na t°i textury.
GLuint filter;// Specifikuje pou₧φvan² texturov² filtr
GLuint texture[3];// Uklßdß t°i textury
Nahrajeme bitmapu a vytvo°φme z nφ t°i r∙znΘ textury. Tato lekce pou₧φvß glaux knihovny k nahrßvßnφ bitmap. Vφm ₧e Delphi a VC++ majφ tuto knihovnu. Co ostatnφ jazyky, nevφm. K tomu u₧ moc °φkat nebudu, °ßdky jsou okomentovanΘ a kompletnφ vysv∞tlenφ je v 6 lekci. Nahraje a vytvo°φ textury z bitmap.
int LoadGLTextures()// Loading bitmapy a konverze na texturu
{
int Status=FALSE;// Indikuje chyby
AUX_RGBImageRec *TextureImage[1];// Uklßdß bitmapu
memset(TextureImage,0,sizeof(void *)*1);// Vynuluje pam∞¥
Nynφ nahrajeme bitmapu. Kdy₧ vÜe prob∞hne, data obrßzku budou ulo₧ena v TextureImage[0], status se nastavφ na true a zaΦneme sestavovat texturu.
if (TextureImage[0]=LoadBMP("Data/Crate.bmp"))// Nahraje bitmapu a kontroluje vzniklΘ chyby
{
Status=TRUE;// VÜe je bez problΘm∙
Data bitmapy jsou nahrßna do TextureImage[0]. Pou₧ijeme je k vytvo°enφ t°φ textur. Nßsledujφcφ °ßdek oznßmφ, ₧e chceme sestavit 3 textury a chceme je mφt v ulo₧eny v texture[0], texture[1] a texture[2].
glGenTextures(3, &texture[0]);// Generuje t°i textury
V ÜestΘ lekci jsme pou₧ili lineßrnφ filtrovßnφ, kterΘ vy₧aduje hodn∞ v²konu, ale vypadß velice p∞kn∞. Pro prvnφ texturu pou₧ijeme GL_NEAREST. Spot°ebuje mßlo v²konu, ale v²sledek je relativn∞ Üpatn². Kdy₧ ve h°e vidφte ΦtvereΦkovanou texturu, pou₧φvß toto filtrovßnφ, nicmΘn∞ dob°e funguje i na slabÜφch poΦφtaΦφch. VÜimn∞te si ₧e jsme pou₧ili GL_NEAREST pro MIN i MAG. M∙₧eme smφchat GL_NEAREST s GL_LINEAR a textury budou vypadat sluÜn∞, ale zßrove≥ nevy₧adujφ vysok² v²kon. MIN_FILTER se u₧φvß p°i zmenÜovßnφ, MAG_FILTER p°i zv∞tÜovßnφ.
// Vytvo°φ nelineßrn∞ filtrovanou texturu
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
DalÜφ texturu vytvo°φme stejn∞ jako v lekci 6. Lineßrn∞ filtrovanß. Jedin² rozdφl spoΦφvß v pou₧itφ texture[1] mφsto texture[0], proto₧e se jednß o druhou texturu.
// Vytvo°φ lineßrn∞ filtrovanou texturu
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
Mipmaping jeÜt∞ neznßte. Pou₧φvß se p°i malΘm obrßzku, kdy mnoho detail∙ mizφ z obrazovky. Takto vytvo°en² povrch vypadß z blφzka dost Üpatn∞. Kdy₧ chcete sestavit mipmapovanou texturu, sestavφ se vφce textur odliÜnΘ velikosti a vysokΘ kvality. Kdy₧ kreslφte takovou texturu na obrazovku vybere se nejlΘpe vypadajφcφ textura. Nakreslφ na obrazovku mφsto toho, aby zm∞nilo rozliÜenφ p∙vodnφho obrßzku, kterΘ je p°φΦinou ztrßty detail∙. V ÜestΘ lekci jsem se zmφnil o stanoven²ch limitech Üφ°ky a v²Üky - 64, 128, 256 atd. Pro mipmapovanou texturu m∙₧eme pou₧φt jakoukoli Üφ°ku a v²Üku bitmapy. Automaticky se zm∞nφ velikost. Proto₧e toto je textura Φφslo 3, pou₧ijeme texture[2]. Nynφ mßme v texture[0] texturu bez filtru, texture[1] pou₧φvß lineßrnφ filtrovßnφ a texture[2] pou₧φvß mipmaping.
// Vytvo°φ mipmapovanou texturu
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
}
M∙₧eme uvolnit vÜechnu pam∞¥ zapln∞nou daty bitmapy. Otestujeme zda se data nachßzφ v TextureImage[0]. Kdy₧ tam budou, tak je sma₧eme. Nakonec 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
}
return Status;// Oznßmφ p°φpadnΘ chyby
}
Nejd∙le₧it∞jÜφ Φßst inicializace spoΦφvß v pou₧itφ sv∞tel.
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
Nastavφme sv∞tla - konkrΘtn∞ light1. Na zaΦßtku tΘto lekce jsme definovali okolnφ sv∞tlo do LightAmbient. Pou₧ijeme hodnoty nastavenΘ v poli.
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);// Nastavenφ okolnφho sv∞tla
Hodnoty p°φmΘho sv∞tla jsou v LightDiffuse.
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);// Nastavenφ p°φmΘho sv∞tla
Nynφ nastavφme pozici sv∞tla. Ta je ulo₧ena v LightPosition.
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);// Nastavenφ pozice sv∞tla
Nakonec zapneme sv∞tlo jedna. Sv∞tlo je nastavenΘ, umφst∞nΘ a zapnutΘ, jakmile zavolßme glEnable(GL_LIGHTING) rozsvφtφ se.
glEnable(GL_LIGHT1);// Zapne sv∞tlo
return TRUE;// Inicializace prob∞hla v po°ßdku
}
Vykreslφme krychli s texturami. Kdy₧ nepochopφte co n∞kterΘ °ßdky d∞lajφ, podφvejte se do lekce 6.
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,z);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
DalÜφ °ßdek je podobn² °ßdku v lekci 6, ale namφsto texture[0] tu mßme texture[filter]. Kdy₧ stiskneme klßvesu F, hodnota ve filter se zv²Üφ. Bude-li v∞tÜφ ne₧ 2, nastavφme zase 0. P°i startu programu bude filter nastaven na 0. Prom∞nnou filter tedy urΦujeme, kterou ze t°φ textur mßme pou₧φt.
glBindTexture(GL_TEXTURE_2D, texture[filter]);// Zvolφ texturu
P°i pou₧itφ sv∞tel musφme definovat normßlu povrchu. Je to Φßra vychßzejφcφ ze st°edu polygonu v 90 stup≥ovΘm ·hlu. ╪ekne jak²m sm∞rem je Φelo polygonu. Kdy₧ ji neurΦφte, stane se hodn∞ divn²ch v∞cφ. Povrchy kterΘ by m∞ly svφtit se nerozsvφtφ, Üpatnß strana polygonu svφtit bude, atd. Normßla po₧aduje bod vychßzejφcφ z polygonu. Pohled na p°ednφ povrch ukazuje ₧e normßla je kladnß na ose z. To znamenß ₧e normßla ukazuje k divßkovi. Na zadnφ stran∞ normßla jde od divßka, do obrazovky. Kdy₧ bude kostka otoΦenß o 180 stup≥∙ v na ose x nebo y, p°ednφ povrch bude ukazovat do obrazovky a zadnφ uvidφ divßk. Bez ohledu na to kter² povrch je vid∞t divßkem, normßla tohoto povrchu jde sm∞rem k n∞mu. Kdy₧ se tak stane, povrch bude osv∞tlen. U dalÜφch bod∙ normßly sm∞rem k sv∞tlu bude povrch takΘ sv∞tl². Kdy₧ se posunete do st°edu kostky, bude tmav². Normßla je bod ven, nikoli dovnit°, proto nenφ sv∞tlo uvnit° a tak to mß b²t.
glBegin(GL_QUADS);
// P°ednφ st∞na
glNormal3f( 0.0f, 0.0f, 1.0f);// Normßla
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
glNormal3f( 0.0f, 0.0f,-1.0f);// Normßla
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);
// Hornφ st∞na
glNormal3f( 0.0f, 1.0f, 0.0f);// Normßla
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
glNormal3f( 0.0f,-1.0f, 0.0f);// Normßla
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
glNormal3f( 1.0f, 0.0f, 0.0f);// Normßla
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
glNormal3f(-1.0f, 0.0f, 0.0f);// Normßla
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();
xrot+=xspeed;
yrot+=yspeed;
return TRUE;
}
Posuneme se dol∙ k WinMain(). P°idßme k≤d k zapnutφ/vypnutφ sv∞tla, otßΦenφ, v²b∞r filtru a posun kostky do/z obrazovky. T∞sn∞ u konce WinMain() uvidφte p°φkaz SwapBuffers(hDC). Ihned za tento °ßdek p°idßme k≤d.
Nßsledujφcφ k≤d zjiÜ¥uje, zda je stisknuta klßvesa L. Je-li stisknuta ale lp nenφ false, klßvesa jeÜt∞ nebyla uvoln∞na.
// Funkce WinMain()
SwapBuffers(hDC);// Prohozenφ buffer∙
if (keys['L'] && !lp)// Klßvesa L - sv∞tlo
{
Kdy₧ bude lp false, L nebylo stisknuto, nebo bylo uvoln∞no. Tento trik je pou₧it pro p°φpad, kdy je klßvesa dr₧ena dΘle a my chceme, aby se k≤d vykonal pouze jednou. P°i prvnφm pr∙chodu se lp nastavφ na true a prom∞nnß light se invertuje. P°i dalÜφm pr∙chodu je u₧ lp true a k≤d se neprovede a₧ do uvoln∞nφ klßvesy, kterΘ nastavφ lp zase na false. Kdyby zde toto nebylo, sv∞tlo by p°i stisku akorßt blikalo.
lp=TRUE;
light=!light;
Nynφ se podφvßme na prom∞nnou light. Kdy₧ bude false, vypneme sv∞tlo, kdy₧ ne zapneme ho.
if (!light)
{
glDisable(GL_LIGHTING);// Vypne sv∞tlo
}
else
{
glEnable(GL_LIGHTING);// Zapne sv∞tlo
}
}
Nßsleduje nastavenφ prom∞nnΘ lp na false p°i uvoln∞nφ klßvesy L.
if (!keys['L'])
{
lp=FALSE;
}
Nynφ oÜet°φme stisk F. Kdy₧ se stiskne, dojde ke zv²Üenφ filter. Pokud bude v∞tÜφ ne₧ 2, nastavφme ho zp∞t na 0. K oÜet°enφ delÜφho stisku klßvesy pou₧ijeme stejn² zp∙sob jako u sv∞tla.
if (keys['F'] && !fp)// Klßvesa F - zm∞na texturovΘho filtru
{
fp=TRUE;
filter+=1;
if (filter>2)
{
filter=0;
}
}
if (!keys['F'])// Uvoln∞nφ F
{
fp=FALSE;
}
Otestujφ stisk klßvesy Page Up. Kdy₧ bude stisknuto, snφ₧φme prom∞nnou z. To zp∙sobφ vzdalovßnφ kostky v p°φkazu glTranslatef(0.0f,0.0f,z).
if (keys[VK_PRIOR])// Klßvesa Page Up - zv²Üφ zano°enφ do obrazovky
{
z-=0.02f;
}
Otestujφ stisk klßvesy Page Down. Kdy₧ bude stisknuta, zv²Üφme prom∞nnou z. To zp∙sobφ p°ibli₧ovßnφ kostky v p°φkazu glTranslatef(0.0f,0.0f,z).
if (keys[VK_NEXT])// Klßvesa Page Down - snφ₧φ zano°enφ do obrazovky
{
z+=0.02f;
}
Dßle zkontrolujeme kurzorovΘ klßvesy. Bude-li stisknuto vlevo/vpravo, prom∞nnß xspeed se bude zvyÜovat/sni₧ovat. Bude-li stisknuto nahoru/dol∙, prom∞nnß yspeed se bude zvyÜovat/sni₧ovat. Jestli si vzpomφnßte, v²Üe jsem psal, ₧e vysokΘ hodnoty zp∙sobφ rychlou rotaci. Dlouh² stisk n∞jakΘ klßvesy zp∙sobφ prßv∞ rychlou rotaci kostky.
if (keys[VK_UP])// èipka nahoru
{
xspeed-=0.01f;
}
if (keys[VK_DOWN])// èipka dolu
{
xspeed+=0.01f;
}
if (keys[VK_RIGHT])// èipka vpravo
{
yspeed+=0.01f;
}
if (keys[VK_LEFT])// èipka vlevo
{
yspeed-=0.01f;
}
Nynφ byste m∞li v∞d∞t jak vytvo°it vysoce kvalitnφ, realisticky vypadajφcφ, texturovan² objekt. TakΘ jsme se n∞co dozv∞d∞li o t°ech r∙zn²ch filtrech. Stiskem urΦit²ch klßves m∙₧ete pohybovat objektem na obrazovce, a nakonec vφme jak aplikovat jednoduchΘ sv∞tlo. Zkuste experimentovat s jeho pozicφ a barvou.
napsal: Jeff Molofee - NeHe
p°elo₧il: Ji°φ Rajsk² - RAJSOFT junior