Hlavní navigace

OpenGL a nadstavbová knihovna GLU (17)

Pavel Tišnovský

Dnešní pokračování seriálu o nadstavbové grafické knihovně GLU bude věnováno popisu funkcí, které lze použít pro pokročilejší manipulaci s rastrovými obrázky, tj. s bitmapami či pixmapami, které se mají použít pro texturování. Mezi operace, které lze s rastrovými obrázky provádět, patří zejména změna jejich měřítka a tvorba takzvaných mipmap, které se uplatní primárně při texturování, jejich použití je však možné i při aplikaci dalších algoritmů počítačové grafiky.

Obsah

1. Manipulace s rastrovými obrazy pro potřeby texturování a změny měřítka
2. Změna měřítka bitmapy či pixmapy
3. Vytváření mipmap
4. Vytvoření jednorozměrné mipmapy
5. Demonstrační příklady
6. Obsah dalšího pokračování
7. Seznam funkcí OpenGL a GLUT zmíněných v této části
8. Nové funkce popsané v této části
9. Zkomprimovaná verze článku i s přílohami

1. Manipulace s rastrovými obrazy pro potřeby texturování a změny měřítka

Nadstavbová knihovna GLU obsahuje některé funkce, které je možné použít při mipmappingu, tj. při vytváření série bitmap či pixmap, z nichž každá má oproti předchozímu obrázku poloviční rozlišení jak v horizontální, tak i ve vertikální ose. Kromě toho jsou v této knihovně dostupné i funkce pro změnu měřítka bitmap a pixmap, jejichž použití však není omezeno pouze na texturování, ale lze pomocí nich měnit rozlišení rastrových obrázků na obrazovce. Všechny tyto funkce si popíšeme v dalším textu.

2. Změna měřítka bitmapy či pixmapy

Pomocí funkce gluScaleImage() je možné měnit rozlišení bitmapy (jednobarevného obrázku) či pixmapy (tj. barevného rastrového obrázku s volitelným alfa kanálem) na libovolnou hodnotu. Při rozbalování a balení pixmapy se korektně používají nastavené režimy rozbalování a balení pixelů – viz podrobný popis funkcí glPixelStorei() a glPixelStoref(), které byly popsány v seriálu o grafické knihovně OpenGL. Kromě toho je možné pomocí funkce gluScaleImage() měnit i datový typ uložených pixelů.

Pokud se provádí zmenšování obrázku, tj. rozlišení finálního (cílového) obrázku v obou osách je menší než rozlišení obrázku zdrojového, používá se filtr, který mixuje barvy více pixelů zdrojového obrázku do jednoho pixelu obrázku cílového. Vizuální výsledek je tedy mnohem lepší než při prostém přemapování pixelů, při němž dochází k velké ztrátě vizuálních informací.

Při zvětšování obrázku (tj. zvyšování rozlišení) se provádí bilineární interpolace, protože zdrojových pixelů je méně než pixelů ve finálním obrázku. Vizuální výsledek je opět lepší než při použití prostého mapování pixelů, protože se částečně rozmazávají hranice mezi původními pixely.

Funkce gluScaleImage(), pomocí níž se změna měřítka rastrového obrázku provádí, má následující hlavičku:

GLint gluScaleImage(
    GLenum       format,
    GLint        widthIn,
    GLint        heightIn,
    GLenum       typeIn,
    const void  *dataIn,
    GLint        widthOut,
    GLint        heightOut,
    GLenum       typeOut,
    void        *dataOut
);

Význam jednotlivých parametrů funkce gluScaleImage() je následující:

  1. V parametru format je uložen formát vstupního i výstupního obrázku, který je stejný jako při použití funkce glDrawPixels(), tj. je zde možné použít následující hodnoty:
    GL_COLOR_INDEX (indexy do barevné palety),
    GL_STENCIL_INDEX (indexy do paměti šablony),
    GL_DEPTH_COMPO­NENT (hodnoty paměti hloubky),
    GL_RED (červené barvové složky),
    GL_GREEN (zelené barvové složky),
    GL_BLUE (modré barvové složky),
    GL_ALPHA (průhlednosti pixelů),
    GL_RGB (barvový formát RGB),
    GL_RGBA (barvový formát RGB s průhledností),
    GL_BGR_EXT („obrácený“ formát RGB – prohozené barvové složky),
    GL_BGRA_EXT („obrácený“ formát RGBA),
    GL_LUMINANCE (světlosti pixelů) a
    GL_LUMINANCE_AL­PHA (světlosti a průhlednosti pixelů).
  2. Ve druhém parametru widthIn je funkci gluScaleImage() předána šířka zdrojového obrázku, která je specifikována přímo v pixelech.
  3. Ve třetím parametru heightIn je předána výška obrázku, která je taktéž specifikována v pixelech.
  4. Hodnotou parametru typeIn se specifikuje datový typ, ve kterém jsou uloženy barvy či jiné informace o jednotlivých pixelech. Tento parametr má stejný význam jako parametr type ve funkci glDrawPixels(), tj.:
    GL_UNSIGNED_BYTE (8bitový bezznaménkový integer),
    GL_BYTE (8bitový integer),
    GL_BITMAP (bity spojené do slov),
    GL_UNSIGNED_SHORT (16bitový bezznaménkový integer),
    GL_SHORT, (16bitový integer)
    GL_UNSIGNED_INT, (32bitový bezznaménkový integer)
    GL_INT (32bitový integer) nebo
    GL_FLOAT (32bitový float dle normy IEEE).
  5. Ukazatel na vlastní zdrojový obrázek, tj. na pole pixelů, se předává v parametru dataIn.
  6. Pomocí parametrů widthOut a heightOut je specifikována velikost výsledného obrázku. Je možné celý obrázek buď zvětšovat, zmenšovat, nebo ho dokonce v jednom směru roztáhnout a ve druhém stlačit.
  7. V parametru typeOut se předává datový typ pixelů ve výsledném obrázku – to mimo jiné znamená, že výsledný obrázek může být zkonvertován do jiné struktury, což se hodí zejména při práci s obrázky načtenými z externích souborů. Tento parametr může nabývat hodnot: GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHOR­T, GL_SHORT, GL_UNSIGNED_INT, GL_INT, neboGL_FLOAT, podobně jako parametr typeIn.
  8. V posledním parametru dataOut je předán ukazatel na nově vznikající cílový obrázek, tj. na jeho jednotlivé pixely.

Pokud proběhne změna rozlišení rastrového obrázku korektně, vrací se návratová hodnota 0, v případě chyby se vrací chybový kód, který je od nuly odlišný. Převod chybového kódu na čitelný řetězec (s případným výpisem tohoto řetězce) se může provést pomocí funkcegluError­String(). Většinou se vrací chybové kódy GLU_INVALID_ENUM, GLU_INVALID_VALUE nebo GLU_OUT_OF_ME­MORY.

3. Vytváření mipmap

Další skupinou funkcí, kterou nabízí grafická nadstavbová knihovna GLU, jsou funkce pro vytváření takzvaných mipmap. Použitím mipmap jsem se zabýval již v seriálu o grafické knihovně OpenGL, zejména v části XXV (www.root.cz/cla­nek/1974), zde si pouze rychle zopakujme přednosti mipmap při texturování:

  • odstranění vizuálních artefaktů při přibližování a vzdalování kamery od otexturovaného povrchu.
  • zamezení poblikávání pixelů (vzniklé nanášením texelů na zobrazovaný povrch) při průchodu scénou.
  • zlepšení náhledu na textury při velkém přiblížení nebo naopak vzdálení.
  • hierarchická datová struktura, s jejíž pomocí je možné mipmapami velmi jednoduše procházet.

V dalších odstavcích a následujícím pokračování tohoto seriálu si funkce pro práci s mipmapami podrobně popíšeme.

4. Vytvoření jednorozměrné mipmapy

První popisovanou funkcí pro práci s mipmapami je funkce pro vytvoření jednorozměrné mipmapy. Vstupem této funkce je jednorozměrný rastrový obrázek, výstupem je mipmapa, na jejíž nejvyšší úrovni je zadaný obrázek o specifikovaném rozlišení a na úrovni nejnižší je pouze jeden pixel, který reprezentuje průměrnou barvu všech pixelů ve zdrojovém obrázku. Vytvoření všech úrovní mipmapy se provádí pomocí dříve popsané funkce gluScaleImage().

Funkce pro vytvoření jednorozměrné mipmapy se jmenuje gluBuild1DMip­maps() a má následující deklaraci:

GLint gluBuild1DMipmaps(
    GLenum       target,
    GLint        components,
    GLint        width,
    GLenum       format,
    GLenum       type,
    void        *data
);

Význam jednotlivých parametrů funkce gluBuild1DMip­maps():

  1. V parametru target musí být předán typ cílové textury, která bude z mipmapy vytvářena. U této funkce musí být parametr target vždy nastaven na hodnotu GL_TEXTURE_1D, v opačném případě se funkce neprovede korektně a vrátí se chybový kód GLU_INVALID_ENUM.
  2. Parametrem components je možné specifikovat počet barvových komponent v textuře. Mezi podporované hodnoty patří: 1 (jedna barva, průhlednost nebo luminance), 2 (většinou luminance a průhlednost), 3 (RGB) nebo 4 (RGBA) barvové složky.
  3. V parametru width se zadává šířka obrázku, který je uložen na nejvyšší úrovni mipmapy. Tento údaj by měl být mocninou dvou, jinak se před vlastní konstrukcí mipmapy obrázek automaticky zvětší či zmenší na nejbližší hodnotu, která je mocninou dvou. Změna velikosti obrázku se provádí jednoduše – zavolá se výše popsaná funkce gluScaleImage().
  4. V parametru format se předává formát pixelů, tj. informace o tom, z jakých barvových složek může být barva pixelu vytvořena. Povolené hodnoty jsou:
    GL_COLOR_INDEX (index do barvové palety),
    GL_RED (pouze červená barvová složka),
    GL_GREEN (pouze zelená barvová složka),
    GL_BLUE (pouze modrá barvová složka),
    GL_ALPHA (průhlednost),
    GL_RGB (true color barvy),
    GL_RGBA (true color barvy s průhledností),
    GL_BGR_EXT (obrácený formát RGB),
    GL_BGRA_EXT (obrácený formát RGBA),
    GL_LUMINANCE (světlost) a
    GL_LUMINANCE_AL­PHA (světlost s průhledností).
  5. Parametrem type se specifikuje datový typ jednotlivých barvových složek pixelů. Povolené hodnoty jsou stejné jako u funkce glDrawPixels() nebo u výše zmíněné funkce gluScaleImage(), tj. GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHOR­T,GL_SHORT, GL_UNSIGNED_INT, GL_INT nebo GL_FLOAT.
  6. V posledním parametru data je předán ukazatel na rastrová data obrázku, ze kterého se má vytvořit jednorozměrná mipmapa. Vlastní obrázek není vytvořením mipmapy nijak změněn.

Pokud proběhne vytvoření mipmapy bez chyby, vrací se hodnota 0, v případě výskytu chyby se vrací chybový kód, který je od nuly odlišný. Převod chybového kódu na čitelný řetězec (s případným výpisem tohoto řetězce) se může provést pomocí funkce gluErrorString(). Většinou se vrací chybové kódy GLU_INVALID_ENUM (špatně použité symbolické konstanty), GLU_INVALID_VALUE (nekorektní hodnoty parametrů) nebo GLU_OUT_OF_MEMORY (nedostatek paměti pro vytvoření mipmapy).

Po vytvoření mipmapy je pro každou její úroveň zavolána funkce glTexImage1D(), takže uživatel již toto volání nemusí v aplikaci explicitně provádět.

Funkce pro vytvoření dvojrozměrné a trojrozměrné mipmapy budou uvedeny v následujícím pokračování tohoto seriálu.

5. Demonstrační příklady

Po překladu a spuštění prvního demonstračního příkladu se zobrazí model tělesa, který je pokrytý texturou. Textura je vytvořena ve formě mipmapy se základním rozlišením 64×64 texelů. Při vykreslování stěny zmenšeného tělesa se vyberou dvě nejbližší textury z mipmapy a z těchto se lineární interpolací vypočtou dvě barvy. Výsledná barva je vyčíslena pomocí další lineární interpolace těchto dvou barev.

Jedná se o demonstrační příklad, který připomíná význam a tvorbu mipmap. Vyčíslení barev texelů v mipmapách je provedeno programově, zatímco ve druhém demonstračním příkladu je pro změnu velikosti textur na jednotlivých úrovních mipmapy použita funkce gluScaleImage().

Zdrojový kód prvního demonstračního příkladu je dostupný zde, jeho HTML verze se zvýrazněním syntaxe zde.

Screenshot prvního demonstračního příkladu
Obrázek 1: Screenshot prvního demonstračního příkladu

Jak již bylo uvedeno v předchozím odstavci, je ve druhém demonstračním příkladu ukázáno, jakým způsobem je možné použít funkci gluScaleImage() pro vytvoření mipmapy. Tato funkce se volá na vstupní texturu o velikosti 64×64 texelů s tím, že se postupně vytváří textury (tj. součásti mipmapy) o velikosti 32×32, 16×16, 8×8, 4×4, 2×2 a konečně 1×1 texelů.

Zdrojový kód druhého demonstračního příkladu je dostupný zde, jeho HTML verze se zvýrazněním syntaxe zde.

Screenshot prvního demonstračního příkladu
Obrázek 2: Screenshot druhého demonstračního příkladu

6. Obsah dalšího pokračování

V dalším pokračování tohoto seriálu si popíšeme zbývající funkce pro manipulaci s rastrovými obrázky, především funkce pro tvorbu dvourozměrných a trojrozměrných mipmap.

7. Seznam funkcí OpenGL a GLUT zmíněných v této části

glPixelStorei()
glPixelStoref()
glDrawPixels()
glTexImage1D()

8. Nové funkce popsané v této části

gluScaleImage()
gluBuild1DMipmaps()

9. Zkomprimovaná verze článku i s přílohami

Zkomprimovaná verze tohoto článku i s přílohami a demonstračními příklady je uložena zde.

Našli jste v článku chybu?

23. 11. 2004 10:16

Johanka (neregistrovaný)

Auuuu sorry ja jsem blba :(

23. 11. 2004 9:29

Tomas Krause (neregistrovaný)

Trochu v tom Johance radil sotek, Pavlovi se omlouvame.

Vitalia.cz: Proč vás každý zubař posílá na dentální hygienu

Proč vás každý zubař posílá na dentální hygienu

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

DigiZone.cz: Velká cena v Abú Dhabí: 131 ti­síc diváků

Velká cena v Abú Dhabí: 131 ti­síc diváků

120na80.cz: 5 nejčastějších mýtů o kondomech

5 nejčastějších mýtů o kondomech

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Podnikatel.cz: Chaos u EET pokračuje. Jsou tu další návrhy

Chaos u EET pokračuje. Jsou tu další návrhy

Vitalia.cz: Jmenuje se Janina a žije bez cukru

Jmenuje se Janina a žije bez cukru

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

Vitalia.cz: Taky věříte na pravidlo 5 sekund?

Taky věříte na pravidlo 5 sekund?

Podnikatel.cz: Udávání a účtenková loterie, hloupá komedie

Udávání a účtenková loterie, hloupá komedie

Podnikatel.cz: Chtějte údaje k dani z nemovitostí do mailu

Chtějte údaje k dani z nemovitostí do mailu

120na80.cz: Na ucho teplý, nebo studený obklad?

Na ucho teplý, nebo studený obklad?

120na80.cz: Co všechno ovlivňuje ženskou plodnost?

Co všechno ovlivňuje ženskou plodnost?

Měšec.cz: Stavební spoření: alternativa i pro seniory

Stavební spoření: alternativa i pro seniory

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Vitalia.cz: Pamlsková vyhláška bude platit jen na základkách

Pamlsková vyhláška bude platit jen na základkách