Hlavní navigace

Grafická knihovna OpenGL (28): blending

13. 1. 2004
Doba čtení: 8 minut

Sdílet

V tomto dílu seriálu o grafické knihovně OpenGL se budeme věnovat jedné z metod, která je často použita pro změnu barvy nebo nanášené textury vykreslovaných těles. Jedná se o blending, tj. prolínání (míchání) barev vykreslovaného tělesa s pozadím na základě předem zadané míchací funkce.

Texturování 7 – blending

Obsah

Blending – míchání barev v obrazu
Míchací rovnice použitá při blendingu
Význam míchacích faktorů definovaných v souboru gl.h
Příklad použití blendingu
Problémy, které při použití blendingu mohou nastat
Antialiasing a blending
Demonstrační příklad
Pokračování
 

Blending – míchání barev v obrazu

V předchozích dílech jsme si již několikrát popisovali barevný formát používaný při práci s barvami v OpenGL. Barvy jsou v tomto barevném formátu popsány pomocí tří barvových složek R (Red), G (Green) a B (Blue). K těmto složkám se často přidává ještě složka čtvrtá, nazývaná A (Alfa). Výsledný barevný model se označuje RGBA.

Pomocí alfa složky (někdy také nazývané alfa-kanál) lze specifikovat míru průhlednosti resp. neprůhlednosti vybraných objektů nebo jejich plošek. Alfa složku lze také nastavit samostatně pro každý texel ve vykreslované textuře, čehož se využívá při programování mnoha grafických efektů, například výbuchů či „magických jevů“ – viz první a druhý obrázek.

Použití blendingu pro vykreslování výbuchů
Obrázek 1: Použití blendingu pro vykreslování výbuchůPoužití blendingu pro vykreslování magických jevů
Obrázek 2: Použití blendingu pro vykreslování magických jevů

Při spuštění programu, který používá pro vykreslování grafickou knihovnu OpenGL, je vliv alfa složky na vykreslovanou plošku zakázán. Proto pokud chceme programovat některé grafické efekty, musíme před vykreslením vhodně nastavit režim míchání již nakreslené části scény s nově vykreslovanými tělesy.

Při použití blendingu (tj. míchání barev) musíme nejdříve specifikovat, jakým způsobem se budou kombinovat právě vykreslované fragmenty s hodnotami uloženými ve framebufferu.

Připomeňme, že fragment je datová struktura složená z barvy pixelu, jeho průhlednosti, vzdálenosti od pozorovatele a případných dalších informací. Framebuffer je ve své podstatě pravidelná matice fragmentů. Barvy fragmentů tvoří ve framebufferu samostatný color-buffer, který se zobrazuje na obrazovce. Rasterizace je proces, kterým se matematický model plošky (polygonu) převádí na jednotlivé fragmenty.

Způsob míchání barvy uložené ve framebufferu a barvy vykreslovaného fragmentu se řídí uživatelem definovanou míchací rovnicí (blending function). V této rovnici vystupují následující členy:

  • Zdroj (source) je fragment vzniklý rasterizací v právě běžícím rasterizačním procesu.
  • Cíl (destination) je hodnota zapsaná ve framebufferu, tj. barva fragmentu, který již byl vykreslen dříve. Tako hodnota bude v závislosti na nastavené blending funkci přepsána nebo jinak ovlivněna.

V knihovně OpenGL lze stanovit koeficienty míchání pro každou barevnou složku zvlášť. Tak lze jednoduše dosáhnout na první pohled složitých efektů, například maskování jedné barvy apod.

Míchací rovnice použitá při blendingu

Míchací rovnici (původně ve vektorovém tvaru), která se při blendingu používá pro výpočet nové barvy fragmentu, lze rozepsat do čtyř rovnic odpovídajících barvovému modelu RGBA:

Rn=RsSr+RdDr
Gn=GsSg+GdDg
Bn=BsSb+BdDb
An=AsSa+AdDa

Význam jednotlivých členů v rovnicích:

Rn – nově vypočtená červená barevná složka
Gn – nově vypočtená zelená barevná složka
Bn – nově vypočtená modrá barevná složka
An – nová hodnota alfa složky
Rs – červená barevná složka zdrojového fragmentu
Gs – zelená barevná složka zdrojového fragmentu
Bs – modrá barevná složka zdrojového fragmentu
As – alfa složka zdrojového fragmentu
Rd – červená barevná složka cílového fragmentu
Gd – zelená barevná složka cílového fragmentu
Bd – modrá barevná složka cílového fragmentu
Ad – alfa složka cílového fragmentu
Sr – míchací faktor pro červenou barvu zdrojového fragmentu
Sg – míchací faktor pro zelenou barvu zdrojového fragmentu
Sb – míchací faktor pro modrou barvu zdrojového fragmentu
Sa – míchací faktor pro alfa složku zdrojového fragmentu
Dr – míchací faktor pro červenou barvu cílového fragmentu
Dg – míchací faktor pro zelenou barvu cílového fragmentu
Db – míchací faktor pro modrou barvu cílového fragmentu
Da – míchací faktor pro alfa složku cílového fragmentu

Stačí si však zapamatovat význam jednotlivých písmen: R-red, G-green, B-blue, A-alpha, n-new fragment, s-source fragment, d-destination fragment.

Ve výše uvedených rovnicích je nutné specifikovat míchací faktory (koeficienty) Sr, Sg, Sb, Sa, Dr, Dg, Db a Da, ostatní hodnoty odpovídají barvám a alfa-složkám zdrojových a cílových fragmentů. Koeficienty S a D se nezadávají přímo číselnou hodnotou, protože se mohou měnit v závislosti na barvách zdrojových a cílových fragmentů. Místo toho se používají symboly, jejichž kontrétní hodnota se vypočte automaticky při rasterizaci.

Pro zadání míchacích koeficientů se používá funkce:

void glBlendFunc(GLenum sFactor, GLenum dFactor);

První parametr sFactor určuje způsob výpočtu míchacích faktorů Sr, Sg, Sb a Sa, druhý parametrdFactor způsob výpočtu faktorů Dr, Dg, Db a Da.

Pro hodnoty, které lze do těchto parametrů dosadit, platí základní pravidla:

  1. Za sFactor popř. dFactor lze dosadit některou z konstant, které jsou předdefinovány v hlavičkovém souboru gl.h.
  2. Některé z těchto konstant lze zadat do obou parametrů. Jedná se například o konstanty GL_ZERO, GL_ONE apod. Význam těchto konstant se samozřejmě liší podle toho, do kterého parametru jsou dosazeny.
  3. Některé konstanty lze použít pouze pro parametr sFactor. Jedná se například o konstanty GL_DST_COLOR nebo GL_ONE_MINUS_DST_CO­LOR.
  4. Některé konstanty lze naopak použít pouze pro parametr dFactor. Jde o konstanty GL_SRC_COLOR, GL_ONE_MINUS_SRC_CO­LOR apod.

Význam míchacích faktorů definovaných v souboru gl.h

V následující tabulce je vypsán význam míchacích faktorů, které můžeme použít pro specifikaci koeficientů míchací rovnice. Ve sloupci Název je jméno faktoru, tj. symbolická konstanta definovaná v souboru gl.h. Ve sloupci Použití je označeno, zda se může symbolická konstanta použít pro dosazení do parametru sFactor (S), dFactor (D) nebo do obou parametrů. Ve sloupci Význam jsou ve vektorovém tvaru naznačeny hodnoty zdrojových či cílových koeficientů.

Tabulka č. 533
Název Použití Význam
GL_ZERO S nebo D (0, 0, 0, 0)
GL_ONE S nebo D (1, 1, 1, 1)
GL_DST_COLOR S (Rd, Gd, Bd, Ad)
GL_SRC_COLOR D (Rs, Gs, Bs, As)
GL_ONE_MINUS_DST_CO­LOR S (1, 1, 1, 1)-(Rd, Gd, Bd, Ad)
GL_ONE_MINUS_SRC_CO­LOR D (1, 1, 1, 1)-(Rs, Gs, Bs, As)
GL_SRC_ALPHA S nebo D (As, As, As, As)
GL_ONE_MINUS_SRC_AL­PHA S nebo D (1, 1, 1, 1)-(As, As, As, As)
GL_DST_ALPHA S nebo D (Ad, Ad, Ad, Ad)
GL_ONE_MINUS_DST_AL­PHA S nebo D (1, 1, 1, 1)-(Ad, Ad, Ad, Ad)
GL_SRC_ALPHA_SA­TURATE S (f, f, f, 1)   f=min(As, 1-Ad)

Příklad použití blendingu

Jako příklad na použití blendingu si uvedeme jednoduchý problém. Máme zobrazit dvě plošky přes sebe, ale při překrytí má být bližší ploška průhledná z 50% Postup řešení tohoto problému je následující:

  1. Blending globálně povolíme příkazem glEnable(GL_BLEN­D).
  2. Nastavíme zdrojový faktor na hodnotu GL_ONE.
  3. Nastavíme cílový faktor na hodnotu GL_ZERO.
  4. Vykreslíme první (spodní) plošku. Tato ploška je vykreslena svou originální barvou, protože cílový fragment (tj. pozadí) je vynulován a barva plošky je vynásobena jedničkou.
  5. Nastavíme zdrojový faktor na hodnotu GL_SRC_ALPHA.
  6. Nastavíme cílový faktor na hodnotu GL_ONE_MINUS_SRC_AL­PHA.
  7. Vykreslíme druhou (vrchní) plošku. Alfa hodnota barvy této plošky musí být nastavena na 0.5. To znamená, že se zdrojový i cílový faktor vynásobí stejnou hodnotou (1=1–0.5) a posléze sečtou. Výsledkem našeho snažení je, že tato druhá ploška je vykreslena s padesátiprocentní průhledností.

Problémy, které při použití blendingu mohou nastat

Při vykreslování průhledných těles záleží na pořadí vykreslování objektů. Jako první by se proto měly vykreslit nejvzdálenější objekty (resp. plošky). Zejména proto, že řazení plošek podle vzdálenosti od pozorovatele je časově náročné a nejednoznačné, je nutno metodu trošku vylepšit. Doporučuji dodržovat následující postup:

  • Nejprve je zapotřebí při startu aplikace alokovat společně s barvovými buffery i hloubkový buffer (Z-buffer). To zařídí vhodně nastavené parametry funkce glutInitDispla­yMode.
  • Hloubkový buffer se musí nastavit do režimu čtení i zápisu (read-write) hloubek fragmentů. Toho dosáhneme zavoláním příkazu glDepthMask(GL_TRU­E).
  • Po nastavení hloubkového bufferu se vykreslí všechny neprůhledné objekty. Tyto objekty se vzhledem k testu hloubky každého vykreslovaného fragmentu vykreslí korektně. To je zapříčiněno funkcí hloubkového bufferu, který pro každý vykreslovaný fragment testuje, zda je umístěn před nebo za již vykresleným fragmentem, jehož hloubka je v hloubkovém bufferu uložena. Po vykreslení všech neprůhledných objektů je tedy v hloubkovém bufferu zapsána „výšková mapa“ nejbližších vykreslených fragmentů v každé buňce framebufferu.
  • Před vykreslením průhledných objektů se musí hloubkový režim nastavit do režimu read-only, tj. hloubky fragmentů jsou z hloubkového bufferu pouze čteny (a popř. odstraněny z dalšího vykreslování). Zápis hodnot do hloubkového bufferu je zakázán, protože průhledné objekty se musí vykreslit i tehdy, pokud jsou schovány za dalším průhledným objektem a neprůhledné objekty se za objekty průhlednými nesmí vymazat. Nastavení hloubkového bufferu do režimu read-only provedeme příkazem glDepthMask(GL_FAL­SE).
  • Dalším krokem je seřazení průhledných objektů podle jejich hloubky (vzdálenosti) od pozorovatele. Objekty se poté vykreslí v tomto pořadí, nejdříve samozřejmě objekt nejvzdálenější.
  • Složité objekty, tj. objekty, jejichž plošky jsou složeny z mnohoúhelníků, je někdy nutné tesselací rozdělit na jednotlivé trojúhelníky, jinak by mohly nastat vizuální chyby při překrývání objektů. K tesselaci je možné použít funkce z knihovny GLU.
  • Po vykreslení všech průhledných objektů se hloubkový buffer nastaví opět do režimu read-write (glDepthMask(GL_TRU­E)), aby se v příštím průchodu neprůhledné objekty vykreslily korektně.

Na třetím obrázku je zobrazena ukázka trojrozměrné scény, ve které jsou vykresleny průhledné objekty. Tyto objekty byly vykresleny výše popsanou metodou.

Ukázka 3D scény s průhlednými objekty
Obrázek 3: Ukázka 3D scény s průhlednými objekty

Antialiasing a blending

Jak jsme si již řekli v předchozích dílech, podporuje knihovna OpenGL antialiasing, tj. vykreslování objektů s rozmazanými hranami, které vyrovnávají viditelný rastr obrazovky. Spolu s antialiasingem lze použít i blending, který kromě rozmazání hran objektů zajistí i korektní prolínání jednotlivých objektů. Bez blendingu by totiž později nakreslené hrany objektů (které jsou sice vyhlazené, ale ostře oddělené od okolí) překreslovaly již nakreslené hrany.

Antialiasing se povolí funkcemi glEnable(GL_PO­INT_SMOOTH), glEnable(GL_LI­NE_SMOOTH) a glEnable(GL_PO­LYGON_SMOOTH). Blending se pro úsečky a body musí nastavit příkazem glBlendFunc(GL_SRC_AL­PHA, GL_ONE_MINUS_SRC_AL­PHA). Pro polygony je vhodnější nastavitglBlen­dFunc(GL_SRC_AL­PHA_SATURATE, GL_ONE).

Demonstrační příklad

V demonstračním příkladu je provedeno vykreslení již známého mnohabarevného domku. Po jeho vykreslení se do scény přidávají dvě poloprůhledné roviny, proto je zapotřebí měnit funkci hloubkového bufferu z režimu read-write do režimu read-only. Všimněte si prekrývání domečku a rovin při přibližování a vzdalování.

Zdrojový kód demonstračního příkladu je dostupný zde, k dispozici je i HTML verze se zvýrazněnou syntaxí.

Screenshot z demonstračního příkladu
Obrázek 4: Screenshot z demonstračního příkladu

UX DAy - tip 2

Pokračování

V příštím dílu se budeme zabývat použitím alfa složky v texturách a popíšeme si také základy modulace textur.

Pro majitele pomalejšího připojení k internetu je zde k dispozici celý článek i s přílohami zabalený do jednoho zip souboru.

Byl pro vás článek přínosný?