Lekce 20

Lekce 20 - Maskovßnφ

╚ernΘ okraje obrßzk∙ jsme dosud o°ezßvali blendingem. AΦkoli je tato metoda efektivnφ, ne v₧dy transparentnφ objekty vypadajφ dob°e. Modelovß situace: vytvß°φme hru a pot°ebujeme celistv² text nebo zak°iven² ovlßdacφ panel, ale p°i blendingu scΘna prosvφtß. NejlepÜφm °eÜenφm je maskovßnφ obrßzk∙.

Bitmapov² formßt obrßzku je podporovßn ka₧d²m poΦφtaΦem a ka₧d²m operaΦnφm systΘmem. Nejen, ₧e se s nimi snadno pracuje, ale velmi snadno se nahrßvajφ a konvertujφ na textury. K o°ezßnφ Φern²ch okraj∙ textu a obrßzk∙ jsme s v²hodou pou₧φvali blending, ale ne v₧dy v²sledek vypadal dob°e. P°i spritovΘ animaci ve h°e nechcete, aby postavou prosvφtalo pozadφ. Podobn∞ i text by m∞l b²t pevn² a snadno Φiteln². V takov²ch situacφch se s v²hodou vyu₧φvß maskovßnφ. Mß dv∞ fßze. V prvnφ do scΘny umφstφme Φernobφlou texturu, ve druhΘ na stejnΘ mφsto vykreslφme hlavnφ texturu. Pou₧it² typ blendingu zajistφ, ₧e tam, kde se v masce (prvnφ obrßzek) vyskytovala bφlß barva z∙stane p∙vodnφ scΘna. Textura se nepr∙hledn∞ vykreslφ na Φernou barvu.

#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

Masking uklßdß p°φznak zapnutΘho/vypnutΘho maskovßnφ a podle scene se rozhodujeme, zda vykreslujeme prvnφ nebo druhou verzi scΘny. Loop je °φdφcφ prom∞nnß cykl∙, roll pou₧ijeme pro rolovßnφ textur a rotaci objektu p°i zapnutΘ druhΘ scΘn∞.

bool masking=TRUE;// Maskovßnφ on/off

bool mp;// Stisknuto M?

bool sp;// Stisknut mezernφk?

bool scene;// Kterß scΘna se mß kreslit

GLuint texture[5];// Uklßdß 5 textur

GLuint loop;// ╪φdφcφ prom∞nnß cykl∙

GLfloat roll;// Rolovßnφ textur

Generovßnφ textur je ve svΘm principu ·pln∞ stejnΘ jako ve vÜech minul²ch lekcφch, ale velmi p°ehledn∞ demonstruje nahrßvßnφ vφce textur najednou. TΘm∞° v₧dy jsme pou₧φvali pouze jednu. Deklarujeme pole ukazatel∙ na p∞t bitmap, vynulujeme je a nahrajeme do nich obrßzky, kterΘ vzßp∞tφ zm∞nφme na textury.

int LoadGLTextures()// Nahraje bitmapu a konvertuje na texturu

{

int Status=FALSE;

AUX_RGBImageRec *TextureImage[5];// Alokuje mφsto pro bitmapy

memset(TextureImage,0,sizeof(void *)*5);

if ((TextureImage[0]=LoadBMP("Data/logo.bmp")) &&// Logo

(TextureImage[1]=LoadBMP("Data/mask1.bmp")) &&// Prvnφ maska

(TextureImage[2]=LoadBMP("Data/image1.bmp")) &&// Prvnφ obrßzek

(TextureImage[3]=LoadBMP("Data/mask2.bmp")) &&// Druhß maska

(TextureImage[4]=LoadBMP("Data/image2.bmp")))// Druh² obrßzek

{

Status=TRUE;

glGenTextures(5, &texture[0]);

for (loop=0; loop<5; loop++)// Generuje jednotlivΘ textury

{

glBindTexture(GL_TEXTURE_2D, texture[loop]);

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[loop]->sizeX, TextureImage[loop]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);

}

}

for (loop=0; loop<5; loop++)

{

if (TextureImage[loop])

{

if (TextureImage[loop]->data)

{

free(TextureImage[loop]->data);

}

free(TextureImage[loop]);

}

}

return Status;

}

Z inicializace z∙stala doslova kostra.

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

{

if (!LoadGLTextures())// Nahraje textury

{

return FALSE;

}

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

glClearDepth(1.0);// Povolφ mazßnφ Depth Bufferu

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

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

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

return TRUE;

}

P°i vykreslovßnφ zaΦneme jako obyΦejn∞ mazßnφm buffer∙, resetem matice a translacφ do obrazovky.

int DrawGLScene(GLvoid)// Vykreslovßnφ

{

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

glLoadIdentity();// Reset matice

glTranslatef(0.0f,0.0f,-2.0f);// P°esun do obrazovky


Po rolovßnφ P°ed rolovßnφm

Zvolφme texturu loga a namapujeme ji na obdΘlnφk. Koordinßty vypadajφ n∞jak divn∞. Namφsto obvykl²ch hodnot 0 a₧ 1 tentokrßt zadßme Φφsla 0 a 3. P°edßnφm trojky oznßmφme, ₧e chceme namapovat texturu na polygon t°ikrßt. Pro vysv∞tlenφ m∞ napadß vlastnost vedle sebe p°i umφst∞nφ malΘho obrßzku na plochu OS. Trojku zadßvßme do Üφ°ky i do v²Üky, tudφ₧ se na polygon rovnom∞rn∞ namapuje celkem dev∞t stejn²ch obrßzk∙. Ke koordinßt∙m takΘ p°iΦφtßme (defakto odeΦφtßme) prom∞nnou roll, kterou na konci funkce inkrementujeme. Vznikß dojem, ₧e vykreslovanß hladina scΘny roluje, ale v programu se vlastn∞ m∞nφ pouze texturovΘ koordinßty. Rolovßnφ m∙₧e b²t pou₧ito pro r∙znΘ efekty. Nap°φklad pohybujφcφ se mraky nebo text lΘtajφcφ po objektu.

Logo

glBindTexture(GL_TEXTURE_2D, texture[0]);// V²b∞r textury loga

glBegin(GL_QUADS);// Kreslenφ obdΘlnφk∙

glTexCoord2f(0.0f, -roll+0.0f); glVertex3f(-1.1f,-1.1f, 0.0f);

glTexCoord2f(3.0f, -roll+0.0f); glVertex3f( 1.1f,-1.1f, 0.0f);

glTexCoord2f(3.0f, -roll+3.0f); glVertex3f( 1.1f, 1.1f, 0.0f);

glTexCoord2f(0.0f, -roll+3.0f); glVertex3f(-1.1f, 1.1f, 0.0f);

glEnd();// Konec kreslenφ

Zapneme blending. Aby efekt pracoval musφme vypnout testovßnφ hloubky. Kdyby se nevypnulo nejv∞tÜφ pravd∞podobnostφ by nic nebylo vid∞t.

glEnable(GL_BLEND);// Zapne blending

glDisable(GL_DEPTH_TEST);// Vypne testovßnφ hloubky

Podle hodnoty prom∞nnΘ se rozhodneme, zda budeme obrßzek maskovat nebo pou₧ijeme mnohokrßt vyzkouÜen² blending. Maska je Φernobφlß kopie textury, kterou chceme vykreslit. BφlΘ oblasti masky budou pr∙hlednΘ, ΦernΘ nebudou. Pod bφl²mi sekcemi z∙stane scΘna nezm∞n∞na.

if (masking)// Je zapnutΘ maskovßnφ?

{

glBlendFunc(GL_DST_COLOR,GL_ZERO);// Blending barvy obrazu pomocφ nuly (Φernß)

}

Pokud bude scene true vykreslφme duhou, jinak prvnφ scΘnu.

if (scene)// Vykreslujeme druhou scΘnu?

{

Nechceme objekty p°φliÜ velkΘ, tak₧e se p°esuneme hloub∞ji do obrazovky. Provedeme rotaci na ose z o 0░ a₧ 360░ podle prom∞nnΘ roll.

glTranslatef(0.0f,0.0f,-1.0f);// P°esun o jednotku do obrazovky

glRotatef(roll*360,0.0f,0.0f,1.0f);// Rotace na ose z

Pokud je zapnutΘ maskovßnφ, vykreslφme nejd°φve masku a potom objekt. P°i vypnutΘm pouze objekt.

if (masking)// Je zapnutΘ maskovßnφ?

{

Nastavenφ blendingu pro masku jsme provedli d°φve. Zvolφme texturu masky a namapujeme ji na obdΘlnφk. Po vykreslenφ se na scΘn∞ objevφ Φernß mφsta odpovφdajφcφ masce.

Druhß maska

glBindTexture(GL_TEXTURE_2D, texture[3]);// V²b∞r textury druhΘ masky

glBegin(GL_QUADS);// ZaΦßtek kreslenφ obdΘlnφk∙

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

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

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

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

glEnd();// Konec kreslenφ

}

Znovu zm∞nφme m≤d blendingu. Oznßmφme tφm, ₧e chceme vykreslit vÜechny Φßsti barevnΘ textury, kterΘ NEJSOU ΦernΘ. Proto₧e je obrßzek barevnou kopiφ masky, tak se vykreslφ jen mφsta nad Φern²mi Φßstmi masky. Proto₧e je maska Φernß, nic ze scΘny nebude prosvφtat skrz textury. Vznikne dojem pevn∞ vypadajφcφho obrßzku. Zvolφme barevnou texturu. PotΘ ji vykreslφme se stejn²mi sou°adnicemi bod∙ v prostoru a stejn²mi texturov²mi koordinßty jako masku. Kdybychom masku nevykreslily, obrßzek by se zkopφroval do scΘny, ale dφky blendingu by byl pr∙hledn². Objekty za nφm by prosvφtaly.

Druh² obrßzek

glBlendFunc(GL_ONE, GL_ONE);// Pro druh² barevn² obrßzek

glBindTexture(GL_TEXTURE_2D, texture[4]);// Zvolφ druh² obrßzek

glBegin(GL_QUADS);// ZaΦßtek kreslenφ obdΘlnφk∙

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

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

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

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

glEnd();// Konec kreslenφ

}

P°i hodnot∞ FALSE ulo₧enΘ ve scene se vykreslφ prvnφ scΘna. Op∞t v∞tvφme program podle maskovßnφ. P°i zapnutΘm vykreslφme masku pro scΘnu jedna. Textura roluje zprava doleva (roll p°iΦφtßme k horizontßlnφm koordinßt∙m). Chceme, aby textura zaplnila celou scΘnu, tak₧e neprovßdφme translaci do obrazovky.

else// Vykreslenφ prvnφ scΘny

{

if (masking)// Je zapnutΘ maskovßnφ?

{

Prvnφ maska

glBindTexture(GL_TEXTURE_2D, texture[1]);// V²b∞r textury prvnφ masky

glBegin(GL_QUADS);// ZaΦßtek kreslenφ obdΘlnφk∙

glTexCoord2f(roll+0.0f, 0.0f); glVertex3f(-1.1f,-1.1f, 0.0f);

glTexCoord2f(roll+4.0f, 0.0f); glVertex3f( 1.1f,-1.1f, 0.0f);

glTexCoord2f(roll+4.0f, 4.0f); glVertex3f( 1.1f, 1.1f, 0.0f);

glTexCoord2f(roll+0.0f, 4.0f); glVertex3f(-1.1f, 1.1f, 0.0f);

glEnd();// Konec kreslenφ

}

Blending nastavφme stejn∞ jako minule. Vybereme texturu scΘny jedna a vykreslφme ji na stejnΘ mφsto jako masku.

Prvnφ obrßzek

glBlendFunc(GL_ONE, GL_ONE);// Pro prvnφ barevn² obrßzek

glBindTexture(GL_TEXTURE_2D, texture[2]);// Zvolφ prvnφ obrßzek

glBegin(GL_QUADS);// ZaΦßtek kreslenφ obdΘlnφk∙

glTexCoord2f(roll+0.0f, 0.0f); glVertex3f(-1.1f,-1.1f, 0.0f);

glTexCoord2f(roll+4.0f, 0.0f); glVertex3f( 1.1f,-1.1f, 0.0f);

glTexCoord2f(roll+4.0f, 4.0f); glVertex3f( 1.1f, 1.1f, 0.0f);

glTexCoord2f(roll+0.0f, 4.0f); glVertex3f(-1.1f, 1.1f, 0.0f);

glEnd();// Konec kreslenφ

}

Zapneme testovßnφ hloubky a vypneme blending. V malΘm programu je to v∞c celkem zbyteΦnß, ale u rozsßhlejÜφch projekt∙ n∞kdy nevφte, co zrovna mßte zapnutΘ nebo vypnutΘ. Tyto chyby se obtφ₧n∞ hledajφ a kradou Φas. Po urΦitΘ dob∞ ztrßcφte orientaci, k≤d se stßvß slo₧it∞jÜφm - preventivnφ opat°enφ.

glEnable(GL_DEPTH_TEST);// Zapne testovßnφ hloubky

glDisable(GL_BLEND);// Vypne blending

Aby se scΘna dynamicky pohybovala musφme inkrementovat roll.

roll+=0.002f;// Inkrementace roll

if (roll>1.0f)// Je v∞tÜφ ne₧ jedna?

{

roll-=1.0f;// OdeΦte jedna

}

return TRUE;

}

OÜet°φme vstup z klßvesnice. Po stisku mezernφku zm∞nφme vykreslovanou scΘnu.

// Funkce WinMain()

if (keys[' '] && !sp)// Mezernφk - zm∞na scΘny

{

sp=TRUE;

scene=!scene;

}

if (!keys[' '])// Uvoln∞nφ mezernφku

{

sp=FALSE;

}

Stiskem klßvesy M zapneme, pop°. vypneme maskovßnφ.

if (keys['M'] && !mp)// Klßvesa M - zapne/vypne maskovßnφ

{

mp=TRUE;

masking=!masking;

}

if (!keys['M'])// Uvoln∞nφ klßvesy M

{

mp=FALSE;

}

Vytvo°enφ masky nenφ p°φliÜ t∞₧kΘ. Pokud mßte originßlnφ obrßzek ji₧ nakreslen², otev°ete ho v n∞jakΘm grafickΘm editoru a transformujte ho do ÜedΘ palety barev. Po tΘto operaci zvyÜte kontrast, tak₧e se ÜedΘ pixely ztmavφ na ΦernΘ. Zkuste takΘ snφ₧it jas ap. Je d∙le₧itΘ, aby bφlß byla opravdu bφlß a Φernß Φist∞ Φernß. Mßte-li pochyby p°eve∩te obrßzek do ΦernobφlΘho re₧imu (2 barvy). Pokud by v masce z∙staly ÜedΘ pixely byly by pr∙hlednΘ. Je takΘ d∙le₧itΘ, aby barevn² obrßzek m∞l ΦernΘ pozadφ a masku bφlou. Otestujte si barvy masky kapßtkem (v∞tÜinou b²vajφ chyby na rozhranφ). Bφlß je v RGB 255 255 255 (FF FF FF), Φernß 0 0 0.

Lze zjistit barvu pixel∙ p°i nahrßvßnφ bitmapy. Chcete-li pixel pr∙hledn² m∙₧ete mu p°i°adit alfu rovnou nule. VÜem ostatnφm barvßm 255. Tato metoda takΘ pracuje spolehliv∞, ale vy₧aduje extra k≤d tΘto lekce. ( Chci poukßzat, ₧e k v²sledku existuje vφce cest - vÜechny mohou b²t sprßvnΘ.

NauΦili jsme se, jak vykreslit Φßst textury bez pou₧itφ alfa kanßlu. Klasick² blending, kter² znßme, nevypadal nejlΘpe a textury s alfa kanßlem pot°ebujφ obrßzky, kterΘ alfa kanßl podporujφ. Bitmapy jsou vhodnΘ p°edevÜφm dφky snadnΘ prßci, ale majφ ji₧ zmφn∞nΘ omezenφ. Tento program ukßzal, jak obejφt nedostatky bitmapov²ch obrßzk∙ a vykreslovßnφ jednΘ textury vφcekrßt na jeden obdΘlnφk. VÜe jsme rozÜφ°ili rolovßnφm textur po scΘn∞.

D∞kuji Robu Santovi za ukßzkov² k≤d, ve kterΘm mi poprvΘ p°edstavil trik mapovßnφ dvou textur. NicmΘn∞ ani tato cesta nenφ ·pln∞ dokonalß. Aby efekt pracoval, pot°ebujete dva pr∙chody - dvakrßt vykreslujete jeden objekt. Z toho plyne, ₧e vykreslovßnφ tφmto zp∙sobem je dvakrßt pomalejÜφ. NicmΘn∞... co se dß d∞lat?

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

ZdrojovΘ k≤dy

Lekce 20 (scΘna 1)
Lekce 20 (scΘna 2)

<<< Lekce 19 | Lekce 21 >>>