Po vysvětlení bitmapových a 3D fontů v předchozích dvou lekcích jsem se rozhodl napsat lekci o mapování textur na fonty. Jedná se o tzv. automatické generování koordinátů textur. Po dočtení této lekce budete umět namapovat texturu opravdu na cokoli - zcela snadno a jednoduše.
Stejně jako v minulé a předminulé lekci je kód specifický pro Windows. Pokud by měl někdo na platformě nezávislý kód sem s ním a já napíšu nový tutoriál o fontech.
#include <windows.h>// Hlavičkový soubor pro Windows
#include <math.h>// Hlavičkový soubor pro matematickou knihovnu
#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
GLuint base;// Ukazatel na první z display listů pro font
GLuint texture[1];// Ukládá texturu
GLuint rot;// Pro pohyb, rotaci a barvu textu
Při psaní funkce nahrávající font jsem udělal malou změnu. Pokud jste si spustili program, asi jste na první pohled nenašli ten font - ale byl tam. Všimli jste si poletující pirátské lebky se zkříženými kostmi. Právě ona je jeden znak z písma Wingdings, které patří mezi tzv. symbolové fonty.
GLvoid BuildFont(GLvoid)// Vytvoření fontu
{
GLYPHMETRICSFLOAT gmf[256];// Ukládá informace o fontu
HFONT font;// Proměnná fontu
base = glGenLists(256);// 256 znaků
font = CreateFont(-12,// Výška
0,// Šířka
0,// Úhel escapement
0,// Úhel orientace
FW_BOLD,// Tučnost
FALSE,// Kurzíva
FALSE,// Podtržení
FALSE,// Přeškrtnutí
Místo ANSI_CHARSET podle stylu lekce 14, použijeme SYMBOL_CHARSET. Tím řekneme Windowsům, že vytvářený font není typickým písmem tvořeným znaky, ale že obsahuje malé obrázky (symboly). Pokud byste zapomněli změnit tuto řádku, písma typu Wingdings, webdings a další, která zkoušíte použít, nebudou vykreslovat symboly (lebka ...), ale normální znaky (A, B ...).
SYMBOL_CHARSET,// Znaková sada
OUT_TT_PRECIS,// Přesnost výstupu (TrueType)
CLIP_DEFAULT_PRECIS,// Přesnost ořezání
ANTIALIASED_QUALITY,// Výstupní kvalita
FF_DONTCARE|DEFAULT_PITCH,// Rodina a pitch
"Wingdings");// Jméno fontu
SelectObject(hDC, font);// Výběr fontu do DC
wglUseFontOutlines(hDC,// Vybere DC
0,// Počáteční znak
255,// Koncový znak
base,// Adresa prvního znaku
Počítám s větší hranatostí. To znamená, že se OpenGL nebude držet obrysů fontu tak těsně. Pokud zde předáte 0.0f, všimnete si problémů spojených s mapováním textur na zakřivené roviny. Povolíte-li jistou hranatost, většina problémů zmizí. (Já (překladatel) jsem žádné problémy s 0.0f neměl, dokonce to vypadalo o dost lépe.)
0.1f,// Hranatost
0.2f,// Hloubka v ose z
WGL_FONT_POLYGONS,// Polygony ne drátěný model
gmf);// Adresa bufferu pro uložení informací.
}
K nahrání textur přidáme kód, který už znáte z předchozích tutoriálů. Vytvoříme mipmapovanou texturu, protože vypadá lépe.
int LoadGLTextures()// Vytvoří texturu
{
int Status=FALSE;// Indikuje chyby
AUX_RGBImageRec *TextureImage[1];// Místo pro obrázek
memset(TextureImage,0,sizeof(void *)*1);// Nastaví ukazatel na NULL
if (TextureImage[0]=LoadBMP("Data/Lights.bmp"))// Nahraje bitmapu
{
Status=TRUE;
glGenTextures(1, &texture[0]);// Generuje texturu
// Vytvoří lineárně mipmapovanou texturu
glBindTexture(GL_TEXTURE_2D, texture[0]);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
Další řádky umožňují použít automatické generování koordinátů textur na jakékoli zobrazované objekty. Příkaz glTexGen je velmi silný a komplexní. Popsat všechny vlastnosti, které zahrnuje, by byl tutoriál sám o sobě. Nicméně, vše, co potřebujete vědět, je že, GL_S a GL_T jsou texturové koordináty. Implicitně jsou nastaveny tak, aby vzaly pozice x a y na obrazovce a přišly s bodem textury. Všimněte si, že objekty nejsou texturovány na ose z. Přední i zadní část ploch je otexturovaná a to je to, na čem záleží. x (GL_S) mapuje textury zleva doprava a y (GL_T) nahoru a dolů. GL_TEXTURE_GEN_MODE použijeme při výběru texturového mapování S i T. Jsou celkem tři možnosti v dalším parametru:
GL_EYE_LINEAR - textura je namapovaná na všechny stěny stejně
GL_OBJECT_LINEAR - textura je fixovaná na přední stěnu, do hloubky se protáhne
GL_SPHERE_MAP - textura kovově odrážející světlo
Je důležité poznamenat, že jsem vypustil spoustu kódu. Správně bychom měli určit také GL_OBJECT_PLANE, ale implicitní nastavení nám stačí. Pokud byste se chtěli dozvědět více, tak si kupte nějakou dobrou knihu nebo zkuste nápovědu MSDN.
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
}
if (TextureImage[0])// Pokud bitmapa existuje
{
if (TextureImage[0]->data)// Pokud existují data bitmapy
{
free(TextureImage[0]->data);// Smaže data bitmapy
}
free(TextureImage[0]);// Smaže strukturu bitmapy
}
return Status;
}
Uděláme také několik změn v inicializačním kódu. BuildFont() přesuneme pod loading textur. Pokud byste chtěli měnit barvy textur použitím glColor3f(R,G,B), přidejte glEnable(GL_COLOR_MATERIAL).
int InitGL(GLvoid)// Všechna nastavení OpenGL
{
if (!LoadGLTextures())// Nahraje texturu
{
return FALSE;
}
BuildFont();// Vytvoří font
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);// Povolí hloubkové testování
glDepthFunc(GL_LEQUAL);// Typ hloubkového testování
glEnable(GL_LIGHT0);// Zapne implicitní světlo
glEnable(GL_LIGHTING);// Zapne světla
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// Nejlepší perspektivní korekce
Zapneme automatické mapování textur. texture[0] se teď namapuje na jakýkoli 3D objekt kreslený na obrazovku. Pokud byste potřebovali více kontroly můžete automatické mapování při kreslení ručně zapínat a vypínat.
glEnable(GL_TEXTURE_2D);// Zapne texturové mapování
glBindTexture(GL_TEXTURE_2D, texture[0]);// Zvolí texturu
return TRUE;
}
Namísto udržování objektu uprostřed obrazovky budeme v této lekci "létat" dokola po celém monitoru. Přesuneme se o 3 jednotky dovnitř. Hodnota pro osu x se bude měnit od -1.1 do +1.1. Krajní meze na ose y jsou -0.8 a +0.8. K výpočtu použijeme proměnnou "rot". Jako vždy budeme rotovat okolo os.
int DrawGLScene(GLvoid)// Vykreslování
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Smaže obrazovku a hloubkový bufferu
glLoadIdentity();// Reset matice
glTranslatef(1.1f*float(cos(rot/16.0f)),0.8f*float(sin(rot/20.0f)),-3.0f);
glRotatef(rot,1.0f,0.0f,0.0f);// Rotace na x
glRotatef(rot*1.2f,0.0f,1.0f,0.0f);// Rotace na y
glRotatef(rot*1.4f,0.0f,0.0f,1.0f);// Rotace na z
Přesuneme se trochu doleva, dolů a dopředu k vycentrování symbolu na každé ose, abychom simulovali také otáčení kolem vlastního centra (-0.35 je číslo, které pracuje ;) S tímto přesunem jsem si musel trochu pohrát, protože si nejsem jistý, jak je font široký, každé písmeno se víceméně liší. Nejsem si jistý, proč se fonty nevytvářejí kolem centrálního bodu.
glTranslatef(-0.35f,-0.35f,0.1f);// Vycentrování
Nakonec nakreslíme lebku a zkřížené kosti. Nechápete-li proč právě "N", tak si pusťte MS Word vyberte písmo Wingdings a napište "N" - odpovídá mu tento symbol. Aby se lebka pohybovala každým překreslením inkrementujeme rot.
glPrint("N");// Vykreslí lebku a zkřížené kosti
rot+=0.1f;// Inkrementace rotace a pohybu
return TRUE;
}
I když jsem nepopsal probíranou látku do žádných extrémních detailů, měli byste pochopit, jak požádat OpenGL o automatické generování texturových koordinátů. Neměli byste mít žádné problémy s otexturováním jakýchkoli objektů. Změnou pouhých dvou řádků kódu (viz. GL_SPHERE_MAP u vytváření textur), dosáhnete perfektního efektu sférického mapování (kovové odlesky světla).
napsal: Jeff Molofee - NeHe <nehe (zavináč) connect.ab.ca>
přeložil: Michal Turek - Woq <WOQ (zavináč) seznam.cz>