Hlavní navigace

GLUT (6): tvorba animací

3. 6. 2003
Doba čtení: 5 minut

Sdílet

V dnešním dílu si ukážeme jednoduchý způsob tvorby animací. Animaci lze vytvořit tak, že budeme plynule měnit tvar nebo polohu objektů nacházejících se ve scéně. Pokud bude změna polohy nebo tvaru plynulá a bude probíhat dostatečně rychle (za minimální hodnotu můžeme považovat cca deset snímků za sekundu), získá uživatel dojem spojité animace. K dosažení co nejvyšší plynulosti můžeme využít takzvaný double buffering. Řízení animace zajistí časovač nebo idle funkce. Obě techniky poskytuje knihovna GLUT.

Tvorba animací, časovač a funkce idle

Double buffering

Double buffering je známá metoda, která je při animacích použita pro dosažení dojmu plynulého pohybu. Princip spočívá v tom, že aplikace dostane k dispozici dva barevné buffery (místa v obrazové paměti, kam se renderuje výsledná scéna), z nichž do jednoho se provádí vykreslování a druhý je zobrazen na obrazovce. Po provedení vykreslení do prvního bufferu dojde k prohození funkce obou bufferů, tj. první bude zobrazen a do druhého se bude vykreslovat. Důležité je, že double buffering je většinou hardwarově podporován grafickou kartou, proto je přehození bufferů otázkou několika málo instrukcí a nemusí se provádět časově náročný přenos dat z druhého do prvního bufferu.

Double buffering je přímo podporován knihovnou OpenGL. Při startu aplikace je nutné povolit použití obou bufferů (v OpenGL se nazývají přední buffer (front buffer) a zadní buffer (back buffer)). Toho dosáhneme zavoláním systémově nezávislé funkce z knihovny GLUT glutInitDispla­yMode(unsigned int mode), kde parametr mode určuje, které buffery OpenGL se mají použít. Double buffer povolíme nastavením tohoto parametru na GLUT_RGBA | GLUT_DOUBLE (jedná se o bitové příznaky). Příznakem GLUT_RGBA nastavíme režim barevných bufferů na plnobarevný – TrueColor. Příznakem GLUT_DOUBLE poté povolíme zadní buffer, jehož barevný formát je shodný s předním bufferem.

Při double bufferignu je dále nutné po vykreslení každého obrázku provést přehození předního a zadního bufferu. Opět využijeme funkci z knihovny GLUT, která se jmenuje glutSwapBuffer­s(void).

Mezi buffery, které lze při inicializaci aplikace povolit, patří (jedná se o bitové příznaky, pro jejich kombinaci použijeme operátoru or): TrueColor barvový buffer (GLUT_RGBA), paletový barvový buffer (GLUT_INDEX), druhý barvový buffer (GLUT_DOUBLE), buffer hloubky – Z buffer (GLUT_DEPTH), akumulační buffer (GLUT_ACCUM), alpha buffer (GLUT_ALPHA), buffer šablony (GLUT_STENCIL) a buffer, kde jsou uloženy pouze intenzity pixelů (GLUT_LUMINANCE). Další možností je barevný buffer, kde je použit multisampling (renderování více subpixelů, z nichž je složen výsledný pixel) – GLUT_MULTISAMPLE, ten však na většině implementací není dostupný.

Při inicializaci bufferů je vhodné povolit použití pouze těch bufferů, které aplikace skutečně vyžaduje, protože každý povolený buffer alokuje část paměti na grafickém akcelerátoru nebo přímo hlavní paměti počítače. Při malém množství volné paměti by pak nebylo možné provádět například texturování nebo by celá práce grafického subsystému mohla být zpomalena nutností neustálého přístupu do hlavní paměti počítače. Pro většinu demonstračních programů v tomto seriálu dostačuje použít barevný buffer (GLUT_RGBA) a zadní buffer (GLUT_DOUBLE). Pouze poslední příklad, kde jsou vykreslovaná trojrozměrná tělesa, vyžaduje i buffer hloubky (GLUT_DEPTH). Samozřejmě, že při použití pokročilých renderovacích technik (například vykreslení stínů či konstruktivní geometrie těles pomocí OpenGL) je nutné použít i další buffery (typicky buffer šablony – GLUT_STENCIL).

Časovač a funkce idle

Pomocí knihovny GLUT lze zaregistrovat jednu nebo více callback funkcí časovače (timeru), které jsou zavolány po uplynutí předem stanoveného časového intervalu. Pomocí těchto callback funkcí lze realizovat například jednoduché animace. Druhou možností, jak lze programovat animace, je registrace callback funkce, která je zavolána v případě nečinnosti aplikace (idle), kdy je k dispozici čas CPU vyhrazený pro aplikaci.

Ukázkový příklad číslo 10

V tomto příkladu je naprogramována jednoduchá animace. Pro inicializaci vykreslování jednotlivých snímků (v animacích nazývaných frames) je využito volného času procesoru (idle), který byl vyhrazen aplikaci.

V dnešních multitaskových operačních systémech je strojový čas procesoru postupně přidělován jednotlivým aplikacím. Přidělování se provádí po určitých časových kvantech, která mají velikost cca 10 ms. Rozdělování provádí plánovač (scheduler) podle předem daného algoritmu a podle priorit aplikací resp. jejich threadů. Pokud dostane aplikace přidělen určitý strojový čas, může ho buď celý využít, nebo může zbývající čas uvolnit pro jinou aplikaci. Většina aplikací je interaktivních, tzn. většinou čekají na vstup od uživatele. To znamená, že nemusejí využívat všechen strojový čas, který dostanou přidělený.

Aplikace, které jsou napsané s využitím knihovny GLUT, jsou programovány tak, že se provádí callback funkce volané při výskytu nějaké události. Pokud však aplikace dostane přidělený strojový čas a žádná událost není registrována, žádná callback funkce se neprovede a aplikace vrátí řízení operačnímu systému. Existuje však možnost registrovat tzv. idle funkci, která je volána právě v případě, kdy je aplikaci přidělen volný strojový čas. Pomocí idle funkce lze realizovat jednoduché animace, které však nijak zásadně nezatěžují výpočetní systém.

Pro registraci idle funkce se používá glutIdleFunc(void (*func)(void)), jejíž jediný argument func obsahuje ukazatel na volanou idle funkci. Pro zakázání volání idle funkce lze použít příkazuglutIdle­Func(NULL). Jak je v příkladu ukázáno, lze v idle funkci změnit stavové proměnné aplikace a voláním funkce glutPostRedis­play(void) vynutit překreslení okna aplikace.

Ve starších verzích knihovny GLUT byla na některých platformách nevhodně nastavena podmínka pro volání funkce idle. To mohlo například v případě animací způsobit velké vytížení systému. Proto je vhodné ve funkci typu idle volat systémovou funkci pro uspání threadu (například Sleep(10)), která zajistí přepnutí threadu.

Zdrojový kód desátého příkladu a zdrojový kód se zvýrazněnou syntaxí.

ukázka desátého příkladu


Tento příklad nevyužívá double buffering. Pro jeho povolení je nutno změnit parametry funkce glutInitDispla­yMode() na hodnotu GLUT_RGBA | GLUT_DOUBLE. Dále je nutné po každém vykreslení scény provést přepnutí funkcí předního a zadního bufferu. To se provede ve funkci onDisplay(), kdy se za poslední příkaz OpenGL (glFlush()) zadá glutSwapBuffers().

Ukázkový příklad číslo 10

V tomto příkladu je naprogramována jednoduchá animace. Pro provedení animace je využit časovač (timer) nabízený knihovnou GLUT.

Pro registraci callback funkce časovače je potřeba použít funkci glutTimerFunc(un­signed int msecs, void (*func)(int value), value), která má tři argumenty. První argument msecs specifikuje dobu v milisekundách, po jejímž uplynutí se zavolá registrovaná funkce. Ukazatel na tuto funkci je předán v druhém argumentu func. Třetí argument value je typu int a může obsahovat libovolnou hodnotu, pomocí které se může například rozhodnout nějaká podmínka v registrované callback funkci (například časovač, který tuto callback funkci vyvolal).

Registrovaná callback funkce je zavolána s jedním argumentem, kterým je hodnota předaná do funkce glutTimerFunc() při registraci.

Callback funkce je zavolána pouze jednou, proto je pro další periodické volání zapotřebí provést registraci znovu – viz kód tohoto příkladu. Takovému chování časovače se někdy říká triggerovaný časovač.

Zdrojový kód jedenáctého příkladu a zdrojový kód se zvýrazněnou syntaxí.

ukázka jedenáctého příkladu

CS24 tip temata


Také tento příklad lze upravit tak, aby se využíval double buffering.

V příštím pokračování si popíšeme tvorbu menu, které představuje jeden ze základních prvků grafického uživatelského rozhraní.

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.