Vykreslovací řetězec a framebuffer
Obsah
Nastavování a zjišťování konfigurace framebufferuFunkce glutInitDisplayMode()
Funkce glXGetConfig()
Funkce glGetIntegerv()
Funkce glutGet()
Význam a použití bufferů ve framebufferu
Barvové buffery (color buffers)
Paměť šablony (stencil buffer)
Paměť hloubky (depth buffer)
Akumulační buffer (accumulation buffer)
Operace s fragmenty při vykreslování
Pokračování
Zkomprimovaný článek i s obrázky pro modemisty
Nastavování a zjišťování konfigurace framebufferu
Již v prvních dílech tohoto seriálu jsme si popsali způsob vykreslování scén pomocí grafické knihovny OpenGL. Vykreslování probíhá tím způsobem, že se každé vykreslované primitivum (bod, úsečka, polygon) podrobí několika transformacím (reprezentovaných maticemi) a poté se v obrazové rovině rastruje na dále nedělitelné plošky nazývané fragmenty. Tyto fragmenty jsou poté podrobeny několika testům a dalším operacím. Po provedení těchto operací mohou být zapsány do framebufferu.
Na prvním obrázku je zobrazen vykreslovací řetězec OpenGL. V dnešní části nás budou zajímat především bloky Rasterization a Per-fragment operations. V bloku Rasterization se provádí rasterizace primitiv, tj. převedení primitiv z vektorového popisu na mřížku fragmentů. V bloku Per-fragment operations se provádějí operace s nově vytvářenými fragmenty.
Obrázek 1: Vykreslovací řetězec OpenGL
Framebuffer se může skládat z následujících bufferů:
- Buffery pro uložení barev fragmentů (color buffers)
- Paměť hloubky fragmentů (depth buffer, Z-buffer)
- Paměť pro šablonu (stencil buffer)
- Akumulační buffer (accumulation buffer)
Podle konkrétní implementace OpenGL na grafickém akcelerátoru je určeno, které buffery jsou dostupné a kolik bitů je určeno pro uložení jednoho fragmentu v každém bufferu.
Způsob nastavení a následného zjišťování konfigurace framebufferu (zejména počtu bitů pro části fragmentů uložených v jednotlivých bufferech) je systémově závislý, není tedy řešen na úrovni OpenGL, ale na úrovni operačního systému či jeho grafické nadstavby.
Pro nastavení framebufferu se používají systémově závislé funkce, napříkladglXChooseVisual() v X Window systému nebo ChoosePixelFormat() v systémech Microsoft Windows.
Funkce glutInitDisplayMode()
Nad těmito systémovými funkcemi je postavena knihovna GLUT, která poskytuje systémově nezávislé rozhraní, zejména funkci glutInitDisplayMode(). Bližší popis této funkce je uveden v článcích popisujících knihovnu GLUT [I] [II] [III] [IV] [V] [VI] [VII] [VIII] [IX], které vyšly taktéž na Rootu.
Funkce glXGetConfig()
Informace o bufferech, zejména jejich dostupnost a popřípadě i bitovou hloubku, lze v X Window systému zjistit pomocí funkce:
int glXGetConfig( Display *dpy, XVisualInfo *vis, int attrib, int *value );
jejíž parametry mají následující význam:
- dpy – struktura s popisem spojení s X serverem.
- vis – ukazatel na strukturu typu XVisualInfo naplněnou např. funkcí glXChooseVisual().
- attrib – symbolické jméno atributu framebufferu, který zjišťujeme.
- value – ukazatel na proměnnou, do které se uloží hodnota atributu.
Symbolická jména atributů framebufferu používaná v parametru attrib a význam hodnot vracených v parametru value:
- GLX_USE_GL – logická jednička, pokud je renderování pomocí OpenGL povoleno. V opačném případě se vrací logická nula.
- GLX_RGBA – v případě použití true color režimu se vrátí logická jednička, v případě paletového režimu logická nula.
- GLX_DOUBLEBUFFER – v případě, že je alokován přední i zadní barvový buffer, vrátí se logická jednička. V opačném případě se vrátí logická nula.
- GLX_STEREO – pokud je alokován levý a pravý barvový buffer, vrátí se logická jednička. Pokud je alokován pouze levý barvový buffer, vrátí se logická nula.
- GLX_AUX_BUFFERS – vrátí počet přídavných (auxiliary) barvových bufferů.
- GLX_BUFFER_SIZE – celkový počet bitů na část fragmentu uloženou v barvovém bufferu. Jedná se o součet hodnot GLX_RED_SIZE, GLX_GREEN_SIZE, GLX_BLUE_SIZE a GLX_ALPHA_SIZE. V paletovém režimu se vrací počet bitů na index do palety.
- GLX_RED_SIZE – počet bitů pro červenou barevnou složku v barvových bufferech.
- GLX_GREEN_SIZE – počet bitů pro zelenou barevnou složku v barvových bufferech.
- GLX_BLUE_SIZE – počet bitů pro modrou barevnou složku v barvových bufferech.
- GLX_ALPHA_SIZE – počet bitů na alfa složku v barvových bufferech.
- GLX_DEPTH_SIZE – počet bitů pro uložení hloubky fragmentu v paměti hloubky.
- GLX_STENCIL_SIZE – počet bitů pro reprezentaci pixelů v paměti šablony.
- GLX_ACCUM_RED_SIZE – počet bitů pro červenou barevnou složku v akumulačním bufferu.
- GLX_ACCUM_GREEN_SIZE – počet bitů pro zelenou barevnou složku v akumulačním bufferu.
- GLX_ACCUM_BLUE_SIZE – počet bitů pro modrou barevnou složku v akumulačním bufferu.
- GLX_ACCUM_ALPHA_SIZE – počet bitů pro alfa složku v akumulačním bufferu.
Funkce glGetIntegerv()
I samotná knihovna OpenGL poskytuje funkci pro zjištění základní konfigurace framebufferu. Tato funkce má hlavičku:
void glGetIntegerv( GLenum pname, GLint *params );
Do parametru pname se zadává název atributu, který chceme zjistit, výsledek se uloží na adresu specifikovanou parametrem params.
Symbolické názvy parametru pname a význam vrácených hodnot:
- GL_RED_BITS – počet bitů červené barevné složky v barvových bufferech.
- GL_GREEN_BITS – počet bitů zelené barevné složky v barvových bufferech.
- GL_BLUE_BITS – počet bitů modré barevné složky v barvových bufferech.
- GL_ALPHA_BITS – počet bitů na alfa kanál uložený v barvových bufferech.
- GL_INDEX_BITS – počet bitů na index do palety při použití paletového režimu.
- GL_DEPTH_BITS – počet bitů pro uložení hloubky fragmentu v paměti hloubky.
- GL_STENCIL_BITS – počet bitů na jeden pixel šablony ve stencil bufferu.
- GL_ACCUM_RED_BITS – počet bitů pro červenou barevnou složku v akumulačním bufferu.
- GL_ACCUM_GREEN_BITS – počet bitů pro zelenou barevnou složku v akumulačním bufferu.
- GL_ACCUM_BLUE_BITS – počet bitů pro modrou barevnou složku v akumulačním bufferu.
- GL_ACCUM_ALPHA_BITS – počet bitů pro alfa složku v akumulačním bufferu.
Funkce glutGet()
Podobnou činnost jako funkce glXGetConfig() a glGetIntegerv() vykonává i funkce z knihovny GLUT s hlavičkou:
int glutGet( GLenum state );
která má pouze jeden parametr state, do něhož se zadává jméno atributu, který chceme zjistit. Výsledek je předán jako návratová hodnota této funkce. Význam hodnot předávaných v parametru state a korespondujících návratových hodnot je uveden v následujícím seznamu.
- GLUT_WINDOW_RED_SIZE – počet bitů červené barevné složky v barvových bufferech.
- GLUT_WINDOW_GREEN_SIZE – počet bitů zelené barevné složky v barvových bufferech.
- GLUT_WINDOW_BLUE_SIZE – počet bitů modré barevné složky v barvových bufferech.
- GLUT_WINDOW_ALPHA_SIZE – počet bitů na alfa kanál uložený v barvových bufferech.
- GLUT_WINDOW_BUFFER_SIZE – celkový počet bitů pro uložení barvy fragmentu.
- GLUT_WINDOW_STENCIL_SIZE – počet bitů na jeden pixel šablony ve stencil bufferu.
- GLUT_WINDOW_DEPTH_SIZE – počet bitů pro uložení hloubky fragmentu v paměti hloubky.
- GLUT_WINDOW_ACCUM_RED_SIZE – počet bitů pro červenou barevnou složku v akumulačním bufferu.
- GLUT_WINDOW_ACCUM_GREEN_SIZE – počet bitů pro zelenou barevnou složku v akumulačním bufferu.
- GLUT_WINDOW_ACCUM_BLUE_SIZE – počet bitů pro modrou barevnou složku v akumulačním bufferu.
- GLUT_WINDOW_ACCUM_ALPHA_SIZE – počet bitů pro alfa složku v akumulačním bufferu.
- GLUT_WINDOW_DOUBLEBUFFER – logická hodnota nastavená na jedničku, pokud je alokován přední i zadní barvový buffer.
- GLUT_WINDOW_STEREO – logická hodnota nastavená na jedničku, pokud je alokován levý i pravý barvový buffer.
- GLUT_WINDOW_RGBA – logická hodnota nastavená na jedničku, pokud jsou barvové režimy nastaveny na true color.
- GLUT_DISPLAY_MODE_POSSIBLE – příznak, zda je vybraná konfigurace framebufferu podporována.
- GLUT_INIT_DISPLAY_MODE – bitové příznaky nastavené konfigurace framebufferu.
Význam a použití bufferů ve framebufferu
V následujících odstavcích bude stručně vysvětlen význam jednotlivých bufferů, které se ve framebufferu mohou nacházet. Další informace byly uvedeny už v dvanáctém dílu tohoto seriálu.
Barvové buffery (color buffers)
V barvových bufferech je uložena barevná informace jednotlivých fragmentů. Vždy do jednoho z těchto bufferů se provádí vykreslování, to znamená, že alespoň jeden barvový buffer musí být vždy vytvořen.
Každá implementace OpenGL, která podporuje stereoskopické pohledy, musí obsahovat minimálně dva barvové buffery, které jsou nazývány levý a pravý. Implementace OpenGL, jenž podporuje double-buffering, musí také obsahovat minimálně dva barvové buffery nazývané přední a zadní.
Je samozřejmě možné kombinovat stereoskopický pohled s double-bufferingem. Pro tuto kombinaci je nutné alokovat minimálně čtyři barvové buffery: přední levý, přední pravý, zadní levý a zadní pravý.
Konkrétní implementace OpenGL však může podporovat i další přídavné barvové buffery, jejichž funkce může být libovolná.
Na vytvoření barvových bufferů pro stereoskopický pohled je zapotřebí inicializovat framebuffer pomocí funkce glutInitDisplayMode() s nastaveným příznakem (bitovou hodnotou) GLUT_STEREO. Pro vytvoření předního a zadního barvového bufferu se musí použít příznak GLUT_DOUBLE. V opačném případě by se použil pouze jeden (přední) barvový buffer.
Získání informací o podpoře stereoskopického pohledu lze získat pomocí funkce glGetBooleanv(GL_STEREO, &result). Informace o podpoře double-bufferingu se získají po zavolání funkce glGetBooleanv(GL_DOUBLEBUFFER, &result).
Paměť šablony (stencil buffer)
Paměť šablony slouží k maskování vytvářených fragmentů, tj. k určení, které fragmenty se mají vykreslit a které se mají z vykreslovacího řetězce vyloučit. Do zamaskovaných částí framebufferu se vykreslování (tj. zápis) nebude provádět.
Paměť šablony má odlišnou funkci od nám již známého ořezávání. Při ořezávání se odstraňují vrcholy grafických primitiv, ale při použití paměti šablony se pracuje přímo s jednotlivými fragmenty (tj. obrazovými elementy).
Funkci, která je pro test fragmentů používaná, lze programově změnit, což se také často děje, například při vytváření těles pomocí CSG či používání stínových těles při vykreslování stínů.
Paměť šablony nachází své uplatnění také při tvorbě grafického uživatelského rozhraní nebo při vytváření speciálních efektů, jakým je například zrcadlení nebo simulace stereopohledů bez alokace stereo barvových bufferů.
Pro vytvoření paměti šablony ve framebufferu je zapotřebí při inicializaci volat funkci glutInitDisplayMode() s nastaveným bitovým příznakem GLUT_STENCIL.
Paměť hloubky (depth buffer)
V tomto bufferu jsou uloženy informace o hloubce fragmentu, tj. o vzdálenosti fragmentu od projekční roviny. Tyto vzdálenosti nejsou většinou ukládány ve své původní podobě, spíše se používá převrácená hodnota vzdálenosti (tj. se zvyšující se vzdáleností fragmentu směrem k nekonečnu klesá ukládaná hodnota směrem k nule).
Při běžném použití přepíše fragment s menší vzdáleností již dříve uložený fragment s větší vzdáleností od promítací roviny. Tato vlastnost paměti hloubky je však programově změnitelná, takže pro speciální účely je možné vykreslovat například jen odlehlé části těles apod. Bližší informace budou uvedeny v následující části tohoto seriálu.
Ve většině implementací OpenGL se používá pouze jedna paměť hloubky, jejich větší počet postrádá pro značnou část vykreslovacích postupů smysl.
Pro vytvoření paměti hloubky ve framebufferu je zapotřebí při inicializaci volat funkci glutInitDisplayMode() s nastaveným bitovým příznakem GLUT_DEPTH.
Akumulační buffer (accumulation buffer)
Akumulační buffer se používá pro sloučení více scén nebo více pohledů na jednu scénu do výsledného obrazu. V tomto bufferu jsou uloženy barevné složky fragmentů, většinou ve formátu RGBA, podobně jako u barvových bufferů. V paletovém (indexovém) režimu nelze akumulační buffer použít, protože zde ztrácí svůj význam (nemá cenu sčítat a průměrovat indexy do barevné palety).
Pomocí akumulačního bufferu lze vykreslovat i antialiasovanou scénu. V tomto případě se do akumulačního bufferu renderuje scéna s jakoby vyšším rozlišením, než je rozlišení barvového bufferu, a následně se provede průměrování barev sousedních fragmentů (ve skutečnosti se scéna může několikrát renderovat v původním rozlišení s posunutou kamerou). Dalším často aplikovaným efektem je například vykreslování těles, které jsou rozmazány pohybem (motion blur) nebo rozmazání příliš blízkých nebo naopak vzdálených těles – viz druhý obrázek.
Do akumulačního bufferu se většinou přímo nezapisuje. Používá se technika vykreslení (renderingu) do barvového bufferu s následným přenosem barev fragmentů do akumulačního bufferu – viz nám již známé funkce glDrawPixels(), glReadPixels() a glCopyPixels(). Přenos fragmentů se však musí vždy provádět pouze v obdélníkové oblasti, což je pro některé grafické efekty omezující.
Pro vytvoření akumulačního bufferu ve framebufferu je zapotřebí při inicializaci volat funkci glutInitDisplayMode() s nastaveným bitovým příznakem GLUT_ACCUM.
Obrázek 2: Rozmazání blízkých a vzdálených částí těles pomocí akumulačního bufferu
Operace s fragmenty při vykreslování
Na třetím obrázku je zobrazeno pořadí operací, které se mohou provádět s vykreslovanými fragmenty. Šipky naznačují směr pohybu dat. Například v bloku Depth buffer test se přečte hloubka již zapsaného fragmentu a v případě úspěšného porovnání se do framebufferu zapíše hloubka nová – šipka je tedy obousměrná. Naopak, při provádění blendingu se hodnoty z framebufferu pouze čtou, neboť zápis se provede až po dalších operacích s vykreslovaným fragmentem – šipka je jednosměrná.
Význam jednotlivých operací si podrobněji popíšeme v další části.
Obrázek 3: Pořadí operací a testů s vykreslovanými fragmenty
Pokračování
V další, předposlední části, si podrobněji popíšeme jednotlivé operace, které jsou s fragmentem prováděny před zápisem do framebufferu. V demonstračních příkladech bude ukázka práce se stencil bufferem, ořezáním nůžkami a s akumulačním bufferem.
Zkomprimovaný článek i s obrázky pro modemisty
Pro majitele pomalejšího připojení k internetu je zde k dispozici celý článek i s obrázky zabalený do jednoho zip souboru.