Tutoriál demonstruje extrémně realistické odrazy za použití stencil bufferu a jejich ořezávání, aby "nevystoupily" ze zrcadla. Je mnohem více pokrokový než předchozí lekce, takže před začátkem čtení doporučuji menší opakování. Odrazy objektů nebudou vidět nad zrcadlem nebo na druhé straně zdi a budou mít barevný nádech zrcadla - skutečné odrazy.
Důležité: Protože grafické karty Voodoo 1, 2 a některé jiné nepodporují stencil buffer, nebude na nich tento tutoriál fungovat. Pokud si nejste jistí, že vaše karta stencil buffer podporuje, stáhněte si zdrojový kód a zkuste jej spustit. Kromě toho budete také potřebovat procesor a grafickou kartu se slušným výkonem. Na mé GeForce 1 občas vidím malé zpomalení. Demo běží nejlépe v 32 bitových barvách.
První část kódu je celkem standardní.
#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
Nastavíme pole pro definici osvětlení. Okolní světlo bude 70% bílé. Difúzní světlo nastavuje rozptyl osvětlení (množství světla rovnoměrně odrážené na plochách objektů). V tomto případě odrážíme plnou intenzitou. Poslední je pozice. Pokud bychom ho mohli spatřit, plulo by v pravém horním rohu monitoru.
// Parametry světla
static GLfloat LightAmb[] = {0.7f, 0.7f, 0.7f, 1.0f};// Okolní
static GLfloat LightDif[] = {1.0f, 1.0f, 1.0f, 1.0f};// Rozptýlené
static GLfloat LightPos[] = {4.0f, 4.0f, 6.0f, 1.0f};// Pozice
Ukazatel q je pro quadratic koule (plážový míč). Xrot a yrot ukládají hodnoty natočení míče, xrotspeed a yrotspeed definují rychlost rotace. Zoom používáme pro přibližování a oddalování scény a height je výška balónu nad podlahou. Pole texture[] už standardně ukládá textury.
GLUquadricObj *q;// Quadratic pro kreslení koule (míče)
GLfloat xrot = 0.0f;// X rotace
GLfloat yrot = 0.0f;// Y rotace
GLfloat xrotspeed = 0.0f;// Rychlost x rotace
GLfloat yrotspeed = 0.0f;// Rychlost y rotace
GLfloat zoom = -7.0f;// Hloubka v obrazovce
GLfloat height = 2.0f;// Výška míče nad scénou
GLuint texture[3];// 3 textury
Vytváření lineárně filtrovaných textur z bitmap je standardní, v předchozích lekcích jsme jej používali velice často, takže ho sem nebudu opisovat. Na obrázcích vidíte texturu míče, podlahy a světla odráženého od míče.
Inicializace OpenGL.
int InitGL(GLvoid)// Nastavení OpenGL
{
if (!LoadGLTextures())// Loading textur
{
return FALSE;// Ukončí program
}
glShadeModel(GL_SMOOTH);// Vyhlazené stínování
glClearColor(0.2f, 0.5f, 1.0f, 1.0f);// Světle modré pozadí
glClearDepth(1.0f);// Nastavení hloubkového bufferu
Příkaz glClearStencil() definuje chování funkce glClear() při mazání stencil bufferu. V tomto případě ho budeme vyplňovat nulami.
glClearStencil(0);// Nastavení mazání stencil bufferu
glEnable(GL_DEPTH_TEST);// Povolí testování hloubky
glDepthFunc(GL_LEQUAL);// Typ testování hloubky
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// Perspektivní korekce
glEnable(GL_TEXTURE_2D);// Mapování textur
Nastavíme světla. Pro okolní použijeme hodnoty z pole LightAmb[], rozptylové světlo definujeme pomocí LightDif[] a pozici z LightPos[]. Nakonec povolíme světla. Pokud bychom dále v kódu chtěli vypnout všechna světla, použili bychom glDisable(GL_LIGHTING), ale při vypínání jenom jednoho postačí pouze glDisable(GL_LIGHT(0až7)). GL_LIGHTING v parametru zakazuje globálně všechna světla.
glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmb);// Okolní
glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDif);// Rozptylové
glLightfv(GL_LIGHT0, GL_POSITION, LightPos);// Pozice
glEnable(GL_LIGHT0);// Povolí světlo 0
glEnable(GL_LIGHTING);// Povolí světla
Dále vytvoříme a nastavíme objekt quadraticu. Vygenerujeme mu normály pro světlo a texturové koordináty, jinak by měl ploché stínování a nešly by na něj namapovat textury.
q = gluNewQuadric();// Nový quadratic
gluQuadricNormals(q, GL_SMOOTH);// Normály pro světlo
gluQuadricTexture(q, GL_TRUE);// Texturové koordináty
Nastavíme mapování textur na vykreslované objekty a to tak, aby při natáčení míče byla viditelná stále stejná část textury. Zatím ho nezapínáme.
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);// Automatické mapování textur
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);// Automatické mapování textur
return TRUE;// Inicializace v pořádku
}
Následující funkci budeme volat pro vykreslení plážového míče. Bude jím quadraticová koule s nalepenou texturou. Nastavíme barvu na bílou, aby se textura nezabarvovala, poté zvolíme texturu a vykreslíme kouli o poloměru 0.35 jednotek, s 32 rovnoběžkami a 16 poledníky.
void DrawObject()// Vykreslí plážový míč
{
glColor3f(1.0f, 1.0f, 1.0f);// Bílá barva
glBindTexture(GL_TEXTURE_2D, texture[1]);// Zvolí texturu míče
gluSphere(q, 0.35f, 32, 16);// Nakreslí kouli
Po vykreslení první koule vybereme texturu světla, nastavíme opět bílou barvu, ale tentokrát s 40% alfou. Povolíme blending, nastavíme jeho funkci založenou na zdrojové alfa hodnotě, zapneme kulové mapování textur a nakreslíme stejnou kouli jako před chvílí. Výsledkem je simulované odrážení světla od míče, ale vlastně se jedná jen o světlé body namapované na plážový míč. Protože je povoleno kulové mapování, textura je vždy natočena k pozorovateli stejnou částí bez ohledu na natočení míče. Je také zapnutý blending takže nová textura nepřebije starou (jednoduchá forma multitexturingu).
glBindTexture(GL_TEXTURE_2D, texture[2]);// Zvolí texturu světla
glColor4f(1.0f, 1.0f, 1.0f, 0.4f);// Bílá barva s 40% alfou
glEnable(GL_BLEND);// Zapne blending
glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Mód blendingu
glEnable(GL_TEXTURE_GEN_S);// Zapne kulové mapování
glEnable(GL_TEXTURE_GEN_T);// Zapne kulové mapování
gluSphere(q, 0.35f, 32, 16);// Stejná koule jako před chvílí
Vypneme kulové mapování a blending.
glDisable(GL_TEXTURE_GEN_S);// Vypne kulové mapování
glDisable(GL_TEXTURE_GEN_T);// Vypne kulové mapování
glDisable(GL_BLEND);// Vepne blending
}
Následující funkce kreslí podlahu, nad kterou se míč vznáší. Vybereme texturu podlahy a na ose z vykreslíme čtverec s jednoduchou texturou.
void DrawFloor()// Vykreslí podlahu
{
glBindTexture(GL_TEXTURE_2D, texture[0]);// Zvolí texturu podlahy
glBegin(GL_QUADS);// Kreslení obdélníků
glNormal3f(0.0, 1.0, 0.0);// Normálová vektor míří vzhůru
glTexCoord2f(0.0f, 1.0f);// Levý dolní bod textury
glVertex3f(-2.0, 0.0, 2.0);// Levý dolní bod podlahy
glTexCoord2f(0.0f, 0.0f);// Levý horní bod textury
glVertex3f(-2.0, 0.0,-2.0);// Levý horní bod podlahy
glTexCoord2f(1.0f, 0.0f);// Pravý horní bod textury
glVertex3f( 2.0, 0.0,-2.0);// Pravý horní bod podlahy
glTexCoord2f(1.0f, 1.0f);// Pravý dolní bod textury
glVertex3f( 2.0, 0.0, 2.0);// Pravý dolní bod podlahy
glEnd();// Konec kreslení
}
Na tomto místě zkombinujeme všechny objekty a obrázky tak, abychom vytvořili výslednou scénu. Začneme mazáním obrazovky (GL_COLOR_BUFFER_BIT) na výchozí modrou barvu, hloubkového bufferu (GL_DEPTH_BUFFER_BIT) a stencil bufferu (GL_STENCIL_BUFFER_BIT). Při čištění stencil bufferu ho vyplňujeme nulami.
int DrawGLScene(GLvoid)// Vykreslí výslednou scénu
{
// Smaže obrazovku, hloubkový buffer a stencil buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
Nadefinujeme rovnici ořezávací plochy (clipping plane equation). Bude použita při vykreslení odraženého míče. Hodnota na ose y je záporná, to znamená, že uvidíme pixely jen pokud jsou kresleny pod podlahou nebo na záporné části osy y. Při použití této rovnice se nezobrazí nic, co vykreslíme nad podlahou (odraz nemůže vystoupit ze zrcadla). Více později.
// Rovnice ořezávací plochy
double eqr[] = { 0.0f, -1.0f, 0.0f, 0.0f };// Použito pro odražený objekt
Všemu, co bylo doposud probráno v této lekci byste měli rozumět. Teď přijde něco "maličko" horšího. Potřebujeme nakreslit odraz míče a to tak, aby se na obrazovce zobrazoval jenom na těch pixelech, kde je podlaha. K tomu využijeme stencil buffer. Pomocí funkce glClear() jsme ho vyplnili samými nulami. Různými nastaveními, které si vysvětlíme dále, docílíme toho, že se podlaha sice nezobrazí na obrazovce, ale na místech, kde se měla vykreslit se stencil buffer nastaví do jedničky. Pro pochopení si představte, že je to obrazovka v paměti, jejíž pixely jsou rovny jedničce, pokud se na nich objekt vykresluje a nule (nezměněný) pokud ne. Na místa, kde je stencil buffer v jedničce vykreslíme plochý odraz míče, ale ne do stencil bufferu - viditelně na obrazovku. Odraz vlastně můžeme vykreslit i kdekoli jinde, ale pouze tady bude vidět. Nakonec klasickým způsobem vykreslíme všechno ostatní. To je asi všechno, co byste měli o stencil bufferu prozatím vědět.
Nyní už konkrétně ke kódu. Resetujeme matici modelview a potom přesuneme scénu o šest jednotek dolů a o zoom do hloubky. Nejlepší vysvětlení pro translaci dolů bude na příkladě. Vezměte si list papíru a umístěte jej rovnoběžně se zemí do úrovně očí. Neuvidíte nic víc než tenkou linku. Posunete-li jím o maličko dolů, spatříte celou plochu, protože se na něj budete dívat více ze shora namísto přímo na okraj. Rozšířil se zorný úhel.
glLoadIdentity();// Reset matice
glTranslatef(0.0f, -0.6f, zoom);// Zoom a vyvýšení kamery nad podlahu
Novým příkazem definujeme barevnou masku pro vykreslované barvy. Funkci se předávají čtyři parametry reprezentující červenou, zelenou, modrou a alfu. Pokud například červenou složku nastavíme na jedna (GL_TRUE) a všechny ostatní na nulu (GL_FALSE), tak se bude moci zobrazit pouze červená barva. V opačném případě (0,1,1,1) se budou zobrazovat všechny barvy mimo červenou. Asi tušíte, že jsou barvy implicitně nastaveny tak, aby se všechny zobrazovaly. No, a protože v tuto chvíli nechceme nic zobrazovat zakážeme všechny barvy.
glColorMask(0,0,0,0);// Nastaví masku barev, aby se nic nezobrazilo
Začínáme pracovat se stencil bufferem. Napřed potřebujeme získat obraz podlahy vyjádřený jedničkami (viz. výše). Začneme zapnutím stencilového testování (stencil testing). Jakmile je povoleno jsme schopni modifikovat stencil buffer.
glEnable(GL_STENCIL_TEST);// Zapne stencil buffer pro paměťový obraz podlahy
Následující příkaz je možná těžko pochopitelný, ale určitě se velice těžko vysvětluje. Funkce glStencilFunc(GL_ALWAYS,1,1) oznamuje OpenGL, jaký typ testu chceme použít na každý pixel při jeho vykreslování. GL_ALWAYS zaručí, že test proběhne vždy. Druhý parametr je referenční hodnotou a třetí parametr je maska. U každého pixelu se hodnota masky ANDuje s referenční hodnotou a výsledek se uloží do stencil bufferu. V našem případě se do něj umístí pokaždé jednička (reference & maska = 1 & 1 = 1). Nyní víme, že na souřadnicích pixelu na obrazovce, kde by se vykreslil objekt, bude ve stencil bufferu jednička.
Pozn.: Stencilové testy jsou vykonávány na pixelech pokaždé, když se objekt vykresluje na scénu. Referenční hodnota ANDovaná s hodnotou masky se testuje proti aktuální hodnotě ve stencil bufferu ANDované s hodnotou masky.
glStencilFunc(GL_ALWAYS, 1, 1);// Pokaždé proběhne, reference, maska
GlStencilOp() zpracuje tři rozdílné požadavky založené na stencilových funkcích, které jsme se rozhodli použít. První parametr říká OpenGL, co má udělat pokud test neuspěje. Protože je nastaven na GL_KEEP nechá hodnotu stencil bufferu tak, jak právě je. Nicméně test uspěje vždy, protože máme funkci nastavenu na GL_ALWAYS. Druhý parametr určuje co dělat, pokud stencil test proběhne, ale hloubkový test bude neúspěšný. Tato situace by nastala například, když by se objekt vykreslil za jiným objektem a hloubkový test by nepovolil jeho vykreslení. Opět může být ignorován, protože hned následujícím příkazem hloubkové testy vypínáme. Třetí parametr je pro nás důležitý. Definuje, co se má vykonat, pokud test uspěje (uspěje vždycky). V našem případě OpenGL nahradí nulu ve stencil bufferu na jedničku (referenční hodnota ANDovaná s maskou = 1).
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);// Vykreslením nastavíme konkrétní bit ve stencil bufferu na 1
Po nastavení stencilových testů vypneme hloubkové testy a zavoláme funkci pro vykreslení podlahy.
glDisable(GL_DEPTH_TEST);// Vypne testování hloubky
DrawFloor();// Vykreslí podlahu (do stencil bufferu ne na scénu)
Takže teď máme ve stencil bufferu neviditelnou masku podlahy. Tak dlouho, jak bude stencilové testování zapnuté, budeme moci zobrazovat pixely pouze tam, kde je stencil buffer v jedničce (tam kde byla vykreslena podlaha). Zapneme hloubkové testování a nastavíme masku barev zpět do jedniček. To znamená, že se od teď vše vykreslované opravdu zobrazí.
glEnable(GL_DEPTH_TEST);// Zapne testování hloubky
glColorMask(1, 1, 1, 1);// Povolí zobrazování barev
Namísto užití GL_ALWAYS pro stencilovou funkci, použijeme GL_EQUAL. Reference i maska zůstávají v jedničce. Pro stencilové operace nastavíme všechny parametry na GL_KEEP. Vykreslované pixely se zobrazí na obrazovku POUZE tehdy, když je na jejich souřadnicích hodnota stencilu v jedničce (reference ANDovaná s maskou (1), které jsou rovny (GL_EQUAL) hodnotě stencil bufferu ANDované s maskou (také 1)). GL_KEEP zajistí, že se hodnoty ve stencil bufferu nebudou modifikovat.
glStencilFunc(GL_EQUAL, 1, 1);// Zobrazí se pouze pixely na jedničkách ve stencil bufferu (podlaha)
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);// Neměnit obsah stencil bufferu
Zapneme ořezávací plochu zrcadla, která je definována rovnicí uloženou v poli eqr[]. Umožňuje, aby byl odraz objektu vykreslen pouze směrem dolů od podlahy (v podlaze). Touto cestou nebude moci odraz míče vystoupit do "reálného světa". Pokud nechápete, co je tímto míněno zakomentářujte v kódu řádek glEnable(GL_CLIP_PLANE0), zkompilujte program a zkuste projít reálným míčem skrz podlahu. Pokud clipping nebude zapnutý uvidíte, jak při vstupu míče do podlahy jeho odraz vystoupí nahoru nad podlahu. Vše vidíte na obrázku. Mimochodem, všimněte si, že vystoupivší obraz je pořád vidět jen tam, kde je ve stencil bufferu obraz podlahy.
Po zapnutí ořezávací plochy 0 (obyčejně jich může být 0 až 5) jí předáme parametry rovnice uložené v eqr[].
glEnable(GL_CLIP_PLANE0);// Zapne ořezávací testy pro odraz
glClipPlane(GL_CLIP_PLANE0, eqr);// Rovnice ořezávací roviny
Zálohujeme aktuální stav matice, aby ji změny trvale neovlivnily. Zadáním mínus jedničky do glScalef() obrátíme směr osy y. Do této chvíle procházela zezdola nahoru, nyní naopak. Stejný efekt by měla rotace o 180°. Vše je teď invertované jako v zrcadle. Pokud něco vykreslíme nahoře, zobrazí se to dole (zrcadlo je vodorovně ne svisle), rotujeme-li po směru, objekt se otočí proti směru hodinových ručiček a podobně. Tento stav se může zrušit buď opětovným voláním glScalef(), které provede opětovnou inverzi nebo POPnutím matice.
glPushMatrix();// Záloha matice
glScalef(1.0f, -1.0f, 1.0f);// Zrcadlení směru osy y
Nadefinujeme pozici světla podle pole LightPos[]. Na reálný míč svítí z pravé horní strany, ale protože se i poloha světla zrcadlí, tak na odraz bude zářit zezdola.
glLightfv(GL_LIGHT0, GL_POSITION, LightPos);// Umístění světla
Přesuneme se na ose y nahoru nebo dolů v závislosti na proměnné height. Opět je translace zrcadlena, takže pokud se přesuneme o pět jednotek nad podlahu budeme vlastně o pět jednotek pod podlahou. Stejným způsobem pracují i rotace. Nakonec nakreslíme objekt plážového míče a POPneme matici. Tím zrušíme všechny změny od volání glPushMatrix().
glTranslatef(0.0f, height, 0.0f);// Umístění míče
glRotatef(xrot, 1.0f, 0.0f, 0.0f);// Rotace na ose x
glRotatef(yrot, 0.0f, 1.0f, 0.0f);// Rotace na ose y
DrawObject();// Vykreslí míč (odraz)
glPopMatrix();// Obnoví matici
Vypneme ořezávací testy, takže se budou zobrazovat i objekty nad podlahou. Také vypneme stencil testy, abychom mohli vykreslovat i jinam než na pixely, které byly modifikovány podlahou.
glDisable(GL_CLIP_PLANE0);// Vypne ořezávací rovinu
glDisable(GL_STENCIL_TEST);// Už nebudeme potřebovat stencil testy
Připravíme program na vykreslení podlahy. Opět umístíme světlo, ale tak, aby už jeho pozice nebyla zrcadlena. Osa y je sice už v pořádku, ale světlo je stále vpravo dole.
glLightfv(GL_LIGHT0, GL_POSITION, LightPos);// Umístění světla
Zapneme blending, vypneme světla (globálně) a nastavíme 80% průhlednost bez změny barev textur (bílá nepřidává barevný nádech). Mód blendingu je nastaven pomocí glBlendFunc(). Poté vykreslíme částečně průhlednou podlahu. Asi nechápete, proč jsme napřed kreslili odraz a až poté zrcadlo. Je to proto, že chceme, aby byl odraz míče smíchán s barvami podlahy. Pokud se díváte do modrého zrcadla, tak také očekáváte trochu namodralý odraz. Vykreslení míče napřed způsobí zabarvení podlahou. Efekt je více reálný.
glEnable(GL_BLEND);// Zapne blending, jinak by se odraz míče nezobrazil
glDisable(GL_LIGHTING);// Kvůli blendingu vypneme světla
glColor4f(1.0f, 1.0f, 1.0f, 0.8f);// Bílá barva s 80% průhledností
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// Funkce na bázi alfy zdroje a jedna mínus alfy cíle
DrawFloor();// Vykreslí podlahu
A konečně vykreslíme reálný míč. Napřed ale zapneme světla (pozice už je nastavená). Kdybychom nevypnuli blending, míč by při průchodu podlahou vypadal jako odraz. To nechceme.
glEnable(GL_LIGHTING);// Zapne světla
glDisable(GL_BLEND);// Vypne blending
Tento míč už narozdíl od jeho odrazu neořezáváme. Kdybychom používali clipping, nezobrazil by se pod podlahou. Docílili bychom toho definováním hodnoty +1.0f na ose y u rovnice ořezávací roviny. Pro toto demo není žádný důvod, abychom míč nemohli vidět pod podlahou. Všechny translace i rotace zůstávají stejné jako minule s tím rozdílem, že nyní už jde osa y klasickým směrem. Když posuneme reálný míč dolů, odraz jde nahoru a naopak.
glTranslatef(0.0f, height, 0.0f);// Umístění míče
glRotatef(xrot, 1.0f, 0.0f, 0.0f);// Rotace na ose x
glRotatef(yrot, 0.0f, 1.0f, 0.0f);// Rotace na ose y
DrawObject();// Vykreslí míč
Zvětšíme hodnoty natočení míče a jeho odrazu o rychlost rotací. Před návratem z funkce zavoláme glFlush(), které počká na ukončení renderingu. Prevence mihotání na pomalejších grafických kartách.
xrot += xrotspeed;// Zvětší natočení
yrot += yrotspeed;// Zvětší natočení
glFlush();// Vyprázdní pipeline
return TRUE;// Všechno v pořádku
}
Následující funkce testuje stisk kláves. Voláme ji periodicky v hlavní smyčce WinMain(). Šipkami ovládáme rychlost rotace míče, klávesy A a Z přibližují/oddalují scénu, Page Up s Page Down umožňují změnit výšku plážového míče nad podlahou. Klávesa ESC plní stále svoji funkci, ale její umístění zůstalo ve WinMain().
void ProcessKeyboard()// Ovládání klávesnicí
{
if (keys[VK_RIGHT]) yrotspeed += 0.08f;// Šipka vpravo zvýší rychlost y rotace
if (keys[VK_LEFT]) yrotspeed -= 0.08f;// Šipka vlevo sníží rychlost y rotace
if (keys[VK_DOWN]) xrotspeed += 0.08f;// Šipka dolů zvýší rychlost x rotace
if (keys[VK_UP]) xrotspeed -= 0.08f;// Šipka nahoru sníží rychlost x rotace
if (keys['A']) zoom +=0.05f;// A přiblíží scénu
if (keys['Z']) zoom -=0.05f;// Z oddálí scénu
if (keys[VK_PRIOR]) height += 0.03f;// Page Up zvětší vzdálenost míče nad podlahou
if (keys[VK_NEXT]) height -= 0.03f;// Page Down zmenší vzdálenost míče nad podlahou
}
V CreateGLWindow() je úplně miniaturní změna, nicméně by bez ní program nefungoval. Ve struktuře PIXELFORMATDESCRIPTOR pfd nastavíme číslo, které vyjadřuje počet bitů stencil bufferu. Ve všech minulých lekcích jsme ho nepotřebovali, takže mu byla přiřazena nula. Při použití stencil bufferu MUSÍ být počet jeho bitů větší nebo roven jedné! Nám stačí jeden bit.
// Uprostřed funkce CreateGLWindow()
static PIXELFORMATDESCRIPTOR pfd=// Oznamuje Windows jak chceme vše nastavit
{
sizeof(PIXELFORMATDESCRIPTOR),// Velikost struktury
1,// Číslo verze
PFD_DRAW_TO_WINDOW |// Podpora okna
PFD_SUPPORT_OPENGL |// Podpora OpenGL
PFD_DOUBLEBUFFER,// Podpora double bufferingu
PFD_TYPE_RGBA,// RGBA formát
bits,// Barevná hloubka
0, 0, 0, 0, 0, 0,// Bity barev ignorovány
0,// Žádný alfa buffer
0,// Ignorován shift bit
0,// Žádný akumulační buffer
0, 0, 0, 0,// Akumulační bity ignorovány
16,// 16 bitový z-buffer
1,// Stencil buffer (DŮLEŽITÉ)
0,// Žádný auxiliary buffer
PFD_MAIN_PLANE,// Hlavní vykreslovací vrstva
0,// Rezervováno
0, 0, 0// Maska vrstvy ignorována
};
Jak jsem se zmínil výše, test stisknutí kláves už nebudeme vykonávat přímo ve WinMain(), ale ve funkci ProcessKeyboard(), kterou voláme hned po vykreslení scény.
// Funkce WinMain()
DrawGLScene();// Vykreslí scénu
SwapBuffers(hDC);// Prohodí buffery
ProcessKeyboard();// Vstup z klávesnice
Doufám, že jste si užili tuto lekci. Vím, že probírané téma nebylo zrovna nejjednodušší, ale co se dá dělat? Byl to jeden z nejtěžších tutoriálů, jak jsem kdy napsal. Pro mě je celkem snadné pochopit, co který řádek dělá a který příkaz se musí použít, aby vznikl požadovaný efekt. Ale sedněte si k počítači a pokuste se to vysvětlit lidem, kteří neví, co to je stencil buffer a možná o něm dokonce v životě neslyšeli (Překl.: Můj případ). Osobně si myslím, že i když mu napoprvé neporozumíte, po druhém přečtení by mělo být vše jasné...
napsal: Jeff Molofee - NeHe <nehe (zavináč) connect.ab.ca>
přeložil: Michal Turek - Woq <WOQ (zavináč) seznam.cz> & Milan Turek <nalim.kerut (zavináč) email.cz>