Lekce 15 - Mapování textur na fonty

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>

Zdrojové kódy

Lekce 15

<<< Lekce 14 | Lekce 16 >>>