OpenGL v C++ Builderu (4.díl) - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



C/C++

OpenGL v C++ Builderu (4.díl)

open gl

21. září 2001, 00.00 | Tak se opět po krátkém čase setkáváme při pokračování seriálu o OpenGL. Jak vám již nadpis napověděl, dnes poznáme, co tajemného skrývají pojmy DisplayList, blending, textury.

Tak se opět po krátkém čase setkáváme při pokračování seriálu o OpenGL. Jak vám již nadpis napověděl, dnes poznáme, co tajemného skrývá pojem DisplayList. A také se naučíme, jakým způsobem jednoduše udělat objekt průhledným (simple blending) a nakonec vyzkoušíme velmi užitečnou věc, pokrývání objektů texturou.

Poskládáme si pyramidu z krychlí, kterou vidíme na obrázku. Stavíme se tak před problém, jakým způsobem do scény umístit rozumně 15 krychlí, které jsou na chlup stejné. Mohli bychom udělat cyklus a postupně vykreslit všech patnáct krychlí. Každou krychli bychom jako obvykle seskládali ze 6 stěn.

Sami uznáte, že při každém volání funkce DrawScene by počítač pokaždé musel přepočítat celou scénu, tzn. posunout 15 krychlí do správné polohy a správně zobrazit (barva, průhlednost, světla ... atd.). To může mít za následek značné zpomalení při složitějších scénách.

Druhá možnost, která se nám nabízí je, předem vytvořit jeden objekt - . Tento objekt potom tuto předem připravenou krychli 15x nakopírujeme do scény - výsledkem je opět pyramida.

Tím se dostáváme k tomu, co je to DisplayList. Je to seznam objektů, které jsou předem připravené pro zobrazení ve scéně. Do tohoto seznamu můžeme umístit libovolný objekt nebo skupinu objektů, můžeme s nimi libovolně manipulovat nebo vykreslovat a později z DisplayListu smazat. Je mnohem efektivnější vytvořit objekt ještě před vykreslením, uložit do DislplayListu a později v pravou chvíli vykreslit, jednou, dvakrát ......atd.

Teď již víme vše k tomu, abychom mohli začít rýsovat pyramidu.

Poznámka:
můžeme narýsovat i odlišným způsobem než jsme si zvykli (tedy ze 6 stěn). Vraťme se letmo k minulému dílu, krychli lze udělat pomocí funkce gluCylinder. Musíme ale omezit síť, jinak bychom dostali válec. Toho dosáhneme řádkem:
gluCylinder(quadratic,1.0f,1.0f,3.0f,4,1); - kvádr

box=glGenLists(2);

glNewList(box,GL_COMPILE);
. . . . .
  // krychle
  . . . . . 	
glEndList();

Každý objekt nebo skupinu objektů, které chceme umístit do DisplayListu, označíme pořadovým číslem (indexem), podle kterého jej budeme identifikovat.
box=glGenLists(2);
Nyní založíme nový objekt do DisplayListu

glNewList(box,GL_COMPILE);
nebo to samé
glNewList(2,GL_COMPILE);

ten ukončíme podobně jako blok glBegin a glEnd příkazem
glEndList();

Jednu krychličku už máme teď nás čeká milá povinnost, editujeme uživatelskou funkci DrawScene. Zde musíme naskládat do pyramidy všech 15 krychlí, po řádcích v počtu od 1 do 6.

for (yloop = 1; yloop < 6; yloop++) {   // 1 až 6 krychlí

 glColor3f((double) yloop/5, 0, (double) (1-yloop/5));
 for (xloop = 0; xloop < yloop; xloop++) {
 glLoadIdentity(); // Reset pohledu
 glTranslatef(1.4f+(float(xloop)*2.8f)-(float(yloop)*1.4f),
             ((6.0f-float(yloop))*2.4f)-7.0f,-20.0f); 
  
 glRotatef(45.0f-(2.0f*yloop)+xrot,1.0f,0.0f,0.0f); // ještě pootočit
 glRotatef(45.0f+yrot,0.0f,1.0f,0.0f);
 glCallList(box);
 }
}    

Výpočet pyramidy zajistí přesně aby k sobě krychličky pasovali. Můžeme je i otáčet. Na potočení máme staré známe proměnné xrot, yrot, jejíž hodnoty měníme pomocí kurzorových kláves.

Vše pěkně zabaleno v zip souboru (161 KB).

Textury

Dnes se na tomto místě konečně dostáváme k pojmu, který je v herním průmyslu a mezi fanoušky počítačových her skloňován snad ve všech pádech. Jedná se o tzv. textury. Společně poodestřeme roušku tajemství, které textury skrývají.

Začneme opět jednoduše, rotující krychlí. Dnes si jí vylepšíme pohlednou texturou viz obrázek.

Textura je obyčejný obrázek. Tento obrázek musí splňovat určitá kritéria. Musí mít předepsanou velikost, tzn. čtverec o velikostech 16*16, 32*32, 64*64, 128*128, 256*256, 512*512 ..... s jinou velikostí bychom neuspěli.
Ujasněme si formát, půjde o BMP texturu (bitmapu).

Nejprve potřebujeme prostředek pro načtení BMP obrázku. Pro tento účel si napíšeme funkci, která načte obrázek do paměti a vrátí na něj ukazatel.

AUX_RGBImageRec *LoadBMP(char *Filename);

Uvnitř této funkce voláme velmi důležitou proceduru, která zajistí načtení DIB obrázku a vrácení ukazatele. Jde o funkci z knihovny glaux.

auxDIBImageLoad(Filename);

Tím ale naše trampoty nekončí. Nyní musíme převést obrázek na texturu tak, aby ji akceptoval OpenGL. K tomuto účelu potřebujeme opět vlastní funkci LoadGLTextures(), která načte všechny textury (pozn. do budoucna až bude textur více)

Budeme potřebovat ukazatel na obrázek:

AUX_RGBImageRec *TextureImage[1];

Načteme obrázek pomocí funkce LoadBMP, která nám vrátí ukazatel a pokud je vše v pořádku (soubor existuje a je úspěšně otevřen), vytvoříme tedy texturu. Toho dosáhneme třemi řádky

glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, 
            TextureImage[0]->sizeY, 0, GL_RGB,
                GL_UNSIGNED_BYTE, TextureImage[0]->data);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

Prvním řádkem v rámečku říkáme OpenGL, že vytváříme 2D texturu, která jé přístupná přes ukazatel texture[0]. 2D textura je dána šířkou X a výškou Y.
Nyní přiřadíme textuře vlastnosti

void glTexImage2D( GLenum target, GLint level, GLint components, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );

target - určuje typ textury, vždy musí být GL_TEXTURE_2D
level - detail zobrazení, čím větší číslo, tím horší zobrazení (doporučuji 0)
components - určuje počet barevných součástí, takže, když zadáte 1 nebo 2, bude textura černobílá, když zadáte 3 nebo 4 bude barevná (RGB)
width - zadáváme šířku textury v pixelech (TextureImage[0]->sizeX)
height - zadáváme výšku textury v pixelech (TextureImage[0]->sizeY)
border - specifikuje šířku ohraničení, musí být 0 nebo 1
format - určuje barevný formát, v našem případě jsme definovali GL_RGB třísložkový - červená, zelená, modrá. možné hodnoty jsou GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA,, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA. doporučuji vyzkoušet na vlastní kůži. V našem případě ostatní hodnoty nedávají smysluplný výsledek, jejich význam poznáme v dalších dílech.
type - zadáváme datový typ pro 1 pixel, tedy GL_UNSIGNED_BYTE
pixels - ukazatel na data, jednotlivé pixely



Doufám, že následující popis byl pro vás dostatečně pochopitelný, protože postupujeme dál k funkci glTexParameteri, nastavení dalších parametrů textury. První hodnota může nabývat GL_TEXTURE_1D nebo GL_TEXTURE_2D, doporučuji pouze tu druhou možnost. Další parametr udává kvalitu texturování. Zvolíme minimální, takže hodnotu GL_TEXTURE_MIN_FILTER a typ mapování textury nastavíme jako lineární - GL_LINEAR.

Před ukončením funkce musíme ještě uvolnit použitou paměť, i když jsme sami vlastně žádnou nealokovali, musíme uvolnit TextureImage[0]->data, kde byl uložen surový obrázek a ještě TextureImage[0].

if (TextureImage[0])
{
 if (TextureImage[0]->data)
 {
   free(TextureImage[0]->data);					
 }
 free(TextureImage[0]);								
}

Tak to nejhorší máme za sebou, nyní stačí jen vytvořenou funkci zavolat při inicializaci OpenGL. Nesmíme zapomenout aktivovat používání textur, podobně, jako tomu bylo u světel.

if (!LoadGLTextures())								
{
 return FALSE;							
}
glEnable(GL_TEXTURE_2D);

Nastavení textury máme úspěšně za sebou, nyní se můžeme vrhnout na samotné nanášení textur. není to nic těžkého. Jak to funguje?

 

Mapování textur znázorňuje obrázek. Potřebujeme dosadit levý roh bitmapy do levého rohu čtverce, pravý roh bitmapy potřebujeme dosadit do pravého rohu čtverce atd... Toho dosáhneme tak, že šířku a výšku bitmapy budeme brát jako logický celek, takže jak vidíte na obrázku, levý horní roh bitmapy identifikujeme jako (0,0) a pravý dolní roh určíme jako (1,1).

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);

Řádkem glBindTexture(GL_TEXTURE_2D, texture[0]) nejprve aktivujeme texturu uloženou do texture[0]. Do každého bodu namapujeme bitmapu podle obrázku - funkcí glTexCoord2f(float s, float t), takže příkazem z rámečku
glTexCoord2f(0.0f, 0.0f);
umístíme do daného bodu levý horní roh bitmapy. Pro ostatní body provedeme analogicky.

To je celé, program je ke stažení zde (174 KB).

No a to je opět všechno, co jsem chtěl dnes sdělit. Příště se podíváme, jak potexturovat složitější objekty, nakousneme průhledné textury a možná i vytvoříme mlhu hustou tak, že by se dala krájet.
Budu se opět těšit na další 3D seance.

 

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » C/C++  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: