OpenGL Imaging Subset II
Pavel Tišnovský
Úvodník
V dnešní části seriálu o OpenGL Imaging Subsetu si řekneme, jakým způsobem
mohou být změněny hodnoty pixelů během přenosu z a do framebufferu. Zaměříme se
jak na operace prováděné v "základním" OpenGL, tak i v Imaging Subsetu.
Obsah
Změna hodnot během přenosu pixelů a fragmentů
Zpracování pixelů nesoucích informaci o barvě
Zpracování pixelů nesoucích index do barevné palety
Zpracování pixelů s informacemi o hloubce
Zpracování pixelů s informacemi o šabloně
Pokračování
Seznam funkcí zmíněných v této části
Zkomprimovaná verze článku
Změna hodnot během přenosu pixelů a fragmentů
Mezi framebufferem a operační pamětí počítače lze přenášet pixely, jejichž
hodnoty mohou mít různý význam. Pokud je pixel zapisován či čten z barvového
bufferu (color bufferu), má jeho hodnota význam barvy, pokud je
zapisován či čten z paměti hloubky (depth bufferu), obsahuje hloubku
fragmentu a pokud se pracuje s pamětí šablony, obsahuje hodnotu zapisovanou
nebo čtenou z paměti šablony (stencil bufferu).
Hodnoty přenášených pixelů se mohou v průběhu přenosu (transferu) změnit.
Imaging subset je při inicializaci grafické knihovny OpenGL nastavený tak, že
se i při povoleném zpracování pixelů (změně světlosti, kontrastu, mapování
apod.) jejich hodnoty nijak nezmění. Způsob změny hodnot přenášených pixelů se
řídí pomocí funkce:
void glPixelTransferi(
GLenum param,
GLint value
);
resp.
void glPixelTransferf(
GLenum param,
GLfloat value
);
V argumentu param je zadána symbolická konstanta specifikující,
který parametr ovlivňující konverzi hodnot pixelů budeme nastavovat, v
argumentu value je potom zadána číselná hodnota tohoto parametru.
Pokud je hodnota parametru value zadaná mimo povolené meze, generuje
se chybová hodnota GL_INVALID_VALUE. Pokud je zadán nesprávný argument
param, generuje se chybová hodnota GL_INVALID_ENUM. Tyto
chybové hodnoty lze zjistit pomocí funkce glGetError(), kterou jsme si
popsali v předchozí části tohoto
seriálu.
V následující tabulce je uveden soupis všech parametrů, které je možné
nastavit i s jejich datovým typem, počáteční hodnotou a povoleným rozsahem
hodnot:
Jméno parametru | Typ Počáteční hodnota Rozsah hodnot |
GL_MAP_COLOR | GLboolean GL_FALSE GL_TRUE/GL_FALSE |
GL_MAP_STENCIL | GLboolean GL_FALSE GL_TRUE/GL_FALSE |
GL_INDEX_SHIFT | GLint 0 MIN_INT-MAX_INT |
GL_INDEX_OFFSET | GLint 0 MIN_INT-MAX_INT |
GL_RED_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_GREEN_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_BLUE_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_ALPHA_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_DEPTH_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_RED_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_GREEN_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_BLUE_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_ALPHA_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_DEPTH_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_POST_CONVOLUTION_RED_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_POST_CONVOLUTION_GREEN_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_POST_CONVOLUTION_BLUE_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_POST_CONVOLUTION_ALPHA_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_POST_CONVOLUTION_RED_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_POST_CONVOLUTION_GREEN_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_POST_CONVOLUTION_BLUE_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_POST_CONVOLUTION_ALPHA_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_POST_COLOR_MATRIX_RED_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_POST_COLOR_MATRIX_GREEN_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_POST_COLOR_MATRIX_BLUE_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_POST_COLOR_MATRIX_ALPHA_SCALE | GLfloat 1.0 celý rozsah GLfloat |
GL_POST_COLOR_MATRIX_RED_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_POST_COLOR_MATRIX_GREEN_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_POST_COLOR_MATRIX_BLUE_BIAS | GLfloat 0.0 celý rozsah GLfloat |
GL_POST_COLOR_MATRIX_ALPHA_BIAS | GLfloat 0.0 celý rozsah GLfloat |
Zpracování pixelů nesoucích informaci o barvě
Pixely, které nesou informaci o barvě v režimu true-color (formát RGB nebo
RGBA), jsou během přenosu modifikovány podle následujícího schématu:
- Každá barvová složka (včetně alfa složky, kterou v tomto případě
nerozlišujeme od pravých barvových složek) je nejprve vynásobena příslušnou
hodnotou scale. Tato hodnota je nastavena pomocí funkce
glPixelTransferi() nebo glPixelTransferf() se jmény parametrů
GL_RED_SCALE, GL_GREEN_SCALE, GL_BLUE_SCALE a
GL_ALPHA_SCALE a hodnotami typu GLint resp. GLfloat.
Pokud ponecháme původní nastavení OpenGL, jako při inicializaci, jsou všechny
hodnoty scale nastaveny na jedničku, tj. barvové složky se vynásobením
nezmění.
- K hodnotám barev, které vznikly výpočtem v předchozím bloku, jsou
připočteny konstanty bias, které se taktéž nastavují pomocí funkce
glPixelTransfer*(). V tomto případě jsou však použita jména parametrů
GL_RED_BIAS, GL_GREEN_BIAS, GL_BLUE_BIAS a
GL_ALPHA_BIAS s hodnotami typu GLfloat. Původní nastavení
OpenGL je takové, že inicializační hodnoty bias jsou nastaveny na
nulu, tj. barvy se přičtením těchto hodnot nijak nezmění.
- Po provedení předchozích dvou operací jsou hodnoty vypočtených barev
oříznuty do rozsahu 0.0-1.0.
- Pokud je nastavena operace mapování hodnot pomocí tabulek LUT, tj. byla
zavolána funkce glPixelTransfer(GL_MAP_COLOR, GL_TRUE), je každá
barvová hodnota vynásobena velikostí LUT tabulky a v této tabulce je vyhledán
řádek s vypočteným indexem (vzhledem k tomu, že hodnota pixelu byla předem
ořezána do rozsahu 0.0-1.0, je tato operace v pořádku a nikdy nemůže dojít k
tomu, že by se index odkazoval mimo tabulku). Nová hodnota barvy pixelu je poté
z vyhledávací tabulky nebo tabulek přečtena. Pokud je pro každou barvovou
složku alokována tabulka s jinou velikostí, vypočtou se indexy pro každou barvu
samostatně (samozřejmě že korektně).
- Po mapování pomocí LUT je opět provedeno oříznutí hodnot barev do rozsahu
0.0-1.0. V případě, že imaging subset není podporován nebo je vypnut,
zpracování v tomto bodu končí a vypočtené RGBA hodnoty se mohou zapsat do
framebufferu.
- V případě, že je podporován imaging subset, je možné na výsledný obrázek
aplikovat jednoduchý konvoluční filtr, který může být buď jednorozměrný nebo
dvourozměrný. Pokud jsou parametry konvolučního filtru zadány a filtrace je
povolena, je v tomto bodu aplikován na pixely ukládané do framebufferu.
- Po provedení filtrace, kde na každou barvovou složku může být aplikován
jiný konvoluční filtr, se provede opětovné vynásobení každé barvové složky o
hodnotu uloženou v konstantách GL_POST_CONVOLUTION_RED_SCALE,
GL_POST_CONVOLUTION_GREEN_SCALE,
GL_POST_CONVOLUTION_BLUE_SCALE a
GL_POST_CONVOLUTION_ALPHA_SCALE. Inicializační hodnota těchto konstant
je rovna jedné, tj. barvové složky se vynásobením nezmění.
- Následně je ke každé barvové složce přičtena jedna z konstant
GL_POST_CONVOLUTION_RED_BIAS, GL_POST_CONVOLUTION_GREEN_BIAS,
GL_POST_CONVOLUTION_BLUE_BIAS a
GL_POST_CONVOLUTION_ALPHA_BIAS. Inicializační hodnota těchto konstant
je rovna nule, opět se tedy nemění hodnoty zpracovávaných barvových
složek.
Zpracování pixelů nesoucích index do barevné palety
Pixely, které nesou informaci o barvě v paletovém (index color) režimu, jsou
během přenosu modifikovány poněkud odlišným způsobem, než pixely, které
obsahují true-color barvu:
- Hodnota pixelu (což je, jak již víme, číslo v pevné řádové čárce) je
posunuta pomocí operace bitového posunu doleva o GL_INDEX_SHIFT bitů,
nové bity z pravé strany jsou doplněny nulami. Pokud je pomocí funkce
glPixelTransfer*() zadáno do parametru GL_INDEX_SHIFT záporné
číslo, provádí se bitový posun doprava, nové bity se opět vyplňují nulami (jde
tedy o unsigned hodnoty).
- K nové hodnotě pixelu je připočtena konstanta GL_INDEX_OFFSET,
která je opět zadaná pomocí funkce glPixelTransfer*().
- Pokud je barvový buffer nastavený do paletového režimu, je provedeno
překódování barev pomocí vyhledávací tabulky - viz dále popsaná funkce
glPixelMap(). Přitom je použita tabulka
GL_PIXEL_MAP_I_TO_I.
- Pokud jsou barvové buffery nastaveny do režimu pravých barev (RGBA, true
color), jsou indexy do barevné palety zkonvertovány na pravé barvy. To se
provede tak, že z vyhledávacích tabulek GL_PIXEL_MAP_I_TO_R,
GL_PIXEL_MAP_I_TO_G, GL_PIXEL_MAP_I_TO_B a
GL_PIXEL_MAP_I_TO_A jsou přečteny jednotlivé barvy na indexu
odpovídajícímu hodnotě pixelu. Všechny čtyři vyhledávací tabulky jsou opět
specifikovány pomocí funkce glPixelMap*(). Velikost vyhledávacích
tabulek může být u jednotlivých barevných položek různá - indexy se však vždy
vypočtou tak, aby přesně spadaly do velikosti tabulky.
Zpracování pixelů s informacemi o hloubce
Pixely, které nesou informace o hloubce, tj. jsou zapisovány do paměti
hloubky (depth buffer, Z-buffer), nebo jsou z této paměti
naopak čteny, se zpracovávají následovně:
- Hodnota pixelu je nejprve vynásobena konstantou GL_DEPTH_SCALE.
Tato konstanta je nastavena pomocí funkce glPixelTransfer*().
- Následně je k výsledku předchozího výpočtu přičtena hodnota
GL_DEPTH_BIAS, která je rovněž nastavena pomocí funkce
glPixelTransfer*().
- Vzhledem k tomu, že všechny hodnoty zapisované do paměti hloubky, musí být
v rozsahu 0.0-1.0, je provedeno ořezání výsledku z předchozí operace právě na
tento rozsah.
Zpracování pixelů s informacemi o šabloně
Pixely, které nesou hodnoty zapisované do paměti šablony (stencil
bufferu), nebo jsou z této paměti čteny, jsou zpracovávány podle
následujícího postupu:
- Každá čtená či zapisovaná hodnota pixelu je posunuta o konstantu
GL_INDEX_SHIFT. Tato operace je podobná operaci, která se provádí s
pixely obsahujícími informace o indexu barvy. Kladná hodnota konstanty
GL_INDEX_SHIFT značí posun doleva, záporná hodnota posun doprava.
- Hodnota získaná z předchozího bodu je přičtena ke konstantě
GL_INDEX_OFFSET.
- Podobně jako u pixelů s indexovými barvami, i zde se může provést mapování
podle nastavené vyhledávací tabulky - ovšem pouze v případě, že je mapování
povoleno, viz GL_MAP_STENCIL. Velikost vyhledávací tabulky odpovídá
hodnotě GL_PIXEL_MAP_S_TO_S_SIZE.
Pokračování
V dalším pokračování tohoto seriálu si popíšeme vytvoření LUT tabulek
používaných pro mapování pixelů.
Seznam funkcí zmíněných v této části
glPixelTransferi()
glPixelTransferf()
glPixelMap()
glGetError()
Zkomprimovaná verze článku
Zkomprimovaná verze tohoto článku je umístěna zde.
Autor: Pavel Tišnovský 2004