Hlavní navigace

Grafické karty a grafické akcelerátory (21)

27. 7. 2005
Doba čtení: 11 minut

Sdílet

V dnešní části seriálu o grafických kartách a grafických akcelerátorech si popíšeme vertex a pixel shadery, které mohou být na moderních grafických akcelerátorech využity k programovému vytváření velkého množství působivých grafických efektů.

Obsah

1. Úvodní informace o shaderech
2. Vertex shader
3. Význam jednotlivých funkčních bloků využívaných vertex shaderem
4. Pixel shader
5. Význam jednotlivých funkčních bloků využívaných pixel shaderem
6. Obsah dalšího pokračování tohoto seriálu

1. Úvodní informace o shaderech

Jménem shadery se v počítačové grafice označují programy, které slouží k ovlivnění vykreslování scény modifikací základních vykreslovacích algoritmů. Známé jsou například shadery používané v pokročilých renderovacích programech (příkladem může být známý programRenderMan aj.). Pomocí shaderů, které jsou zabudovány v renderovacích programech, lze například ovlivňovat způsob výpočtu osvětlení těles, měnit geometrii vykreslovaných ploch, modifikovat nanášené textury a konečně také modifikovat způsob vykreslování jednotlivých pixelů do výsledného rastrového obrázku. Modifikací nanášených textur lze vytvářet například složité procedurální textury nezávislé na rozlišení výsledné scény, změnou geometrie vykreslovaných ploch lze aplikovat takzvaný displacement mapping (hrbolatý povrch) apod. Shadery se v renderovacích programech zapisují pomocí poměrně jednoduchého programovacího jazyka, který jako základní datové typy obsahuje například celá i desetinná čísla, vektory, matice, barvy atd.

Podporu shaderů mají i moderní grafické akcelerátory. Shadery zde slouží k modifikaci výpočtů ve vykreslovacím řetězci. Protože však GPU nejsou programovatelné tak jako běžná CPU (zejména kvůli rychlosti vykreslování), je úloha shaderů na grafických akcelerátorech omezena na modifikaci poloh bodových světel a orientace vrcholů (vertex shader), resp. na modifikaci texelů čtených z textury a zapisovaných do framebufferu (pixel shader). Tyto dva typy shaderů budou popsány v následujících kapitolách.

2. Vertex shader

Vertex shader neboli vertexový procesor je zpracováván v programovatelné jednotce, která je umístěna přímo na programovatelném grafickém procesoru (GPU – Graphics Processing Unit). Pomocí této jednotky je možné do jisté míry (závisející na generaci GPU) přeprogramovat transformační řetězec (transformation pipeline). Všechny geometrické údaje o jednotlivých vrcholech vykreslovaných plošek (tj. vlastní polohy vrcholů včetně jejich normálových vektorů) procházejí před vlastní rasterizací tímto transformačním řetězcem. Kromě údajů o vrcholech plošek vykreslovaných těles jsou v transformačním řetězci zpracovávány i další vektorové informace. Zejména se jedná o pozice a směry/orientace světel ve scéně (rozlišuje se přitom bodové/všesměrové, vektorové/směrové a reflektorové světlo) a v neposlední řadě také koordináty do textury, které mohou být specifikovány zvlášť pro každý vrchol vykreslované plošky.

Možnost programové změny transformačního řetězce představuje pro zkušeného programátora velmi silný nástroj pro implementaci nejrůznějších grafických efektů, například mapování obrázků okolního prostředí na zobrazované těleso (environment mapping), vykreslování skutečně hrbolatých povrchů (displacement mapping, což je rozdíl oproti „trikovému“ bump mappingu) či dokonce výpočet a vykreslování parametrických křivek a ploch. Nutno však podotknout, že současné implementace shaderů jsou poněkud omezené, zejména se to týká maximálního množství instrukcí, které se mohou v shaderu nacházet. Pokud je do vertexového procesoru nahrán standardní, dále nemodifikovaný program (standard vertex shader), probíhá zpracování geometrických informací v grafickém procesoru ve funkčních blocích naznačených na následujícím obrázku.

Transformace prováděné standardním vertex shaderem

Transformace prováděné standardním vertex shaderem

3. Význam jednotlivých bloků využívaných vertex shaderem

Význam jednotlivých bloků GPU zobrazených na předchozím obrázku je následující:

  1. Vertex (object) – souřadnice vrcholu vykreslovaného polygonu, které jsou specifikovány ve světových souřadnicích, tj. nezávisle na nastavení pozorovatele (kamery) a bodu, na který se pozorovatel dívá.
  2. Vertex (clip) – souřadnice vrcholu vykreslovaného polygonu, které jsou v blocích T1T3 transformovány do normovaných souřadnic. Tyto souřadnice slouží k testu na ořezání částí polygonu tělesem záběru. Normované souřadnice se typicky nacházejí v osově orientované krychli o jednotkové délce hran.
  3. Vertex (eye) – souřadnice vrcholu plošky, které jsou transformovány do okna záběru. Tyto souřadnice slouží pro vlastní vykreslení polygonu v rasterizačním řetězci (toto vykreslování se však provádí až v dalších blocích, které zde nejsou naznačeny).
  4. Normal – normála vztažená k celému polygonu nebo ke každému vrcholu zvlášť. Po transformaci je normála použita k výpočtu osvětlení polygonu. Normály vrcholů mohou být využity také k automatizovanému výpočtu texturovacích souřadnic. Řízení způsobu výpočtu texturovacích souřadnic naznačují přepínače SW2 a SW3.
  5. Color – barva vztažená k celému polygonu nebo každému vrcholu zvlášť. Barva je reprezentována trojicí barevných složek R, G, B, ke kterým je přidána průhlednost α.
  6. Secondary color – sekundární barva určená pro blending, modulaci textur a aplikaci efektu mlhy.
  7. TexCoord – souřadnice v textuře. Tyto souřadnice jsou buď pro každý vrchol explicitně zadány (tj. jsou součástí vstupních geometrických dat), nebo mohou být automaticky vypočteny v bloku TexGen. Volbu, která metoda se pro získání texturovacích souřadnic použije, je nutné provést programovým přepínačem SW3.
  8. EdgeFlag – příznak, kterým je specifikováno, zda se má příslušná hrana polygonu vykreslit, či nikoli (má význam především při flat shadingu). Tento příznak není nijak zpracováván, je pouze kopírován ze vstupu na výstup.
  9. T1-T3 – bloky provádějící transformaci podle tří transformačních matic. Jedná se o pohledovou transformační matici, projekční transformační matici a inverzní pohledovou transformační matici. Souřadnice vrcholů (vertexů), pomocí kterých jsou zadány jednotlivé polygony, jsou transformovány pohledovou transformační maticí a následně projekční maticí. Normálové vektory vrcholů se transformují podle stejných matic jako samotné vrcholy.
  10. Lighting – v tomto bloku probíhá výpočet osvětlení na základě barvy vrcholů, jejich souřadnic a normál. Pro povrchy, ve kterých se osvětlení nemusí počítat, může být tento blok přeskočen, což je naznačeno přepínačem SW1. V případě, že je výpočet osvětlení pomocí přepínače SW1 vypnut, provádí se kopie primární barvy s případným omezením hodnot barevných složek. Pokud je výpočet osvětlení zapnutý, použije se primární barva jako barva základní, která se dále moduluje podle dosahu, barvy a dalších parametrů světel ve scéně.
  11. (0, 1) – ořezání každé barevné složky v barvovém modelu RGBA do rozsahu 0..1. Ořezává se i hodnota průhlednosti α.
  12. Texgen – automatické generování souřadnic v textuře na základě souřadnic jednotlivých vrcholů a jejich normál. To, zda se automaticky vygenerované souřadnice do textur použijí, závisí na nastavení přepínače SW3. Pomocí přepínače SW2 lze dále určit, zda se pro výpočet texturovacích souřadnic použijí transformované nebo netransformované normálové vektory.
  13. Texture Matrix – blok, který provádí transformace souřadnic v textuře na základě zadané transformační texturovací matice. Tato transformace se provede nezávisle na tom, zda jsou souřadnice do textury explicitně zadány, nebo dopočítány automaticky.

Pokud je programovatelný vertexový procesor zapnut (tj. uživatelský vertex shader je povolen a provádí se), změní se předchozí blokové schéma a z něj vyplývající datový tok tak, jak je naznačeno na následujícím obrázku.

Transformace prováděné obecným vertex shaderem

Transformace prováděné obecným vertex shaderem uloženým ve vertexovém procesoru

Z předchozího obrázku je patrné, že zpracování veškerých geometrických operací je měnitelné pomocí programu aplikovaného ve vertexovém procesoru. Vstupní data je tedy možné libovolným způsobem mapovat na data výstupní, například použít souřadnice vertexů jako primární barvu nebo jako souřadnice do textury (otázkou samozřejmě zůstává, zda to má v daném okamžiku nějaký smysl). Jediným, zato podstatným omezením je, že data ve vertex shaderu nemohou vznikat ani zanikat. Proto je nutné pro každou sekvenci vstupních dat vygenerovat sekvenci dat výstupních.

Vertex shader disponuje nejen vstupními daty (v tomto kontextu je nazýváme atributy) odpovídajícími například souřadnicím vertexů či jejich barvám, ale i všemi informacemi, které má k dispozici pevně naprogramovaná transformační jednotka. Proto je možné ve vertexových programech komfortně využívat například parametry světel (a příslušně modifikovat barvy vertexů) nebo zadané transformační matice, zejména pohledovou, projekční a inverzní pohledovou matici. Pro samotný zápis vertex shaderu jsou dostupné operátory pracující nad vektory a maticemi, protože tyto operátory jsou přímo implementovány v GPU.

Další informace a mezivýsledky výpočtů může vertex shader ukládat do pomocných proměnných (temporaries), které pracují na stejném principu jako registry u univerzálních mikroprocesorů. Kromě těchto informací je možné předat vertexovému shaderu parametry, což je podobná technika jako předávání parametrů procesu spouštěného operačním systémem. Jediným, zato podstatným omezením je počet pomocných proměnných, který se u různých typů GPU výrazně liší.

4. Pixel shader

Pixel shader neboli rasterizační program je implementován v samostatné programovatelné jednotce, která je, podobně jako výše popsaná jednotka pro vertex shader, taktéž umístěna na grafickém procesoru (korektnější název pro tento shader by byl fragment shader, neboť kromě samotných barev pixelů je možné programově měnit i další vlastnosti fragmentů, například jejich hloubku). Pomocí pixel shaderu je možné programově změnit původní operace prováděné nad vykreslovanými fragmenty. Mezi tyto operace patří zejména multitexturing, modulace textur, bump-mapping apod. Kromě změny těchto základních operací je možné programově aplikovat různé konvoluční filtry nebo další efekty na pixelové úrovni nezahrnuté v původním vybavení grafického akcelerátoru. Může se jednat o různé hranové filtry, filtry pro rozmazání vykreslovaných fragmentů apod. Pixel shadery lze také použít při vytváření složitějších efektů, například záblesků, rozšířeného bump-mappingu, jitteringu, tělesově orientovanému antialiasingu apod.

Na moderních grafických akcelerátorech je z celého rasterizačního řetězce v současné době programovatelná pouze část jeho operací, která je na dalším obrázku reprezentovaná blokem Point, Line and Polygon Rasterization. Z této skutečnosti také plyne fakt, že například odstraňování neviditelných polygonů (culling) nebo operace skládání trojúhelníků jsou pevně naprogramované v grafickém procesoru a není je možné měnit ani pomocí pixel shaderu, ani pomocí vertex shaderu. V budoucnu však pravděpodobně dojde k rozšíření programovatelnosti i na tyto oblasti rasterizace.

Pokud je funkce programovatelného pixel shaderu vypnuta, probíhá rasterizace podle následujícího postupu:

  1. Každý fragment se zpracovává samostatně, nezávisle na ostatních fragmentech (to představuje omezení, zejména při aplikaci konvolučních filtrů).
  2. Vstupem pro rasterizaci jsou souřadnice vykreslovaného pixelu z textury (texelu), primární barva, sekundární barva a parametry pro aplikaci efektu mlhy.
  3. Barvu vykreslovaného fragmentu získáme postupnou kombinací texelů z příslušných textur. V této fázi se aplikují grafické efekty prováděné nad texturami, mezi něž patří například výše zmíněný environment mapping, bump mapping apod. Tento bod zpracování se provádí pouze v případě, že je texturování povoleno. V případě, že je texturování zakázáno, se pro výpočet barvy fragmentu využije pouze primární a sekundární barva.
  4. Barva získaná kombinací barev texelů se moduluje primární barvou a k výsledku je přičtena barva sekundární.
  5. V dalším kroku je aplikován efekt mlhy (fog), což je ve skutečnosti opět operace míchání dvou barev. Barva mlhy je vypočtena pomocí jednoduché směšovací funkce, jejíž výsledek závisí na hloubce fragmentu (tj. vzdálenosti od pozorovatele).
  6. Následuje test na hloubku fragmentu oproti hloubce uložené v paměti hloubky (Z-bufferu, depth bufferu). Pokud test proběhne úspěšně, je fragment poslán do dalšího zpracování; v opačném případě je z vykreslovacího řetězce odstraněn.
  7. Na fragment může být následně aplikován alfa-blending (míchání pomocí alfa složky zdrojového a cílového fragmentu) s fragmentem uloženým ve framebufferu. Po provedení alfa-blendingu je výsledný fragment zapsán do framebufferu.
Rasterizační řetězec grafického akcelerátoru

Rasterizační řetězec grafického akcelerátoru

5. Význam jednotlivých bloků využívaných pixel shaderem

Význam funkčních bloků GPU zobrazených na předchozím obrázku je následující:

  1. Position – předem transformované pozice vrcholů bodů, úseček a polygonů, nejčastěji trojúhelníků. Tyto pozice reprezentují vrchol polygonu v obrazovkových souřadnicích. Transformace se provádí v již popsaném vertex shaderu, ať již standardním, nebo uživatelském.
  2. ClipVertex – souřadnice vrcholů ořezávací roviny nebo ořezávacích rovin. Ořezání se provádí v bloku Culling, Clipping.
  3. Varyingn – další parametry (atributy), které mohou být přiřazeny ke každému vrcholu. Mezi tyto parametry patří například barvy jednotlivých vrcholů.
  4. EdgeFlag – příznak, zda je vykreslovaná hrana viditelná (tělesová), či nikoliv (pomocná).
  5. RasterPos – počáteční pozice pixmapy nebo bitmapy pro následné vykreslování.
  6. Primitive Assembly – blok provádějící základní operace s grafickými primitivy, zejména sestavování trojúhelníků.
  7. Flatshade – přiřazení konstantní barvy celé plošce, pokud je konstantní stínování zapnuto (flat shading).
  8. Culling, clipping – odstranění neviditelných plošek a ořezání plošek, které se nacházejí mimo těleso záběru (viewing volume).
  9. Face processing – podle nastavení způsobu zobrazení polygonu se v tomto bloku může polygon převést na body nebo úsečky (wireframe).
  10. Point, Line, Polygon Rasterization – hlavní část rasterizačního řetězce, převod (rasterizace) geometrických dat na jednotlivé fragmenty.
  11. Pixel Rectangle, Bitmap Rasterization – převod (rasterizace) bitmap a pixmap na jednotlivé fragmenty s případnými operacemi zvětšování a zmenšování.
  12. Coord – vypočtené souřadnice fragmentů, které jsou použity v dalším kroku při přístupu do framebufferu.

Detailní pohled na programovatelnou část rasterizačního řetězce je na následujícím obrázku.

Programovatelná část rasterizačního řetězce

Programovatelná část rasterizačního řetězce grafického akcelerátoru

Význam jednotlivých výkonných bloků vyobrazených na předchozím obrázku:

  1. Tex – výběr texelu z jedné či více textur. Pozice texelu v textuře se zjistí pomocí souřadnic zadaných do textur, které do rasterizačního řetězce vstupují z bloku TexCoord. Tyto souřadnice byly předem transformovány buď podle texturovací transformační matice, nebo pomocí programu spuštěného ve vertexovém procesoru.
  2. Mod – modulace textur primární barvou fragmentu. Tento výpočetní blok se použije pouze v případě, že se kombinuje osvětlení (výpočet světla odraženého od vykreslované plošky) spolu s texturováním.
  3. Sum – přičtení sekundární barvy k již vypočtené barvě fragmentu. Provádění tohoto bloku je opět nepovinné a závisí na vybraném režimu osvětlování. Pokud je výpočet osvětlení povolen, může sekundární barvě odpovídat ambientní složka dopadajícího světla.
  4. [0,1] – ořezání hodnot barevných složek do rozsahu (0,1), neboť v předchozích operacích mohlo dojít k překročení tohoto rozsahu. Pro další výpočty jsou tak zaručeny korektní hodnoty barevných složek i alfa složky počítaného fragmentu.
  5. Fog – aplikace efektu mlhy, tj. smíchání vypočtené barvy s barvou mlhy, která je váhovaná dle výsledku funkce i=f(z), kde z je hloubka fragmentu.

Pokud je provádění pixel shaderu povoleno, probíhají veškeré operace nad fragmenty v blocích naznačených na dalším obrázku. Programovatelný rasterizační řetězec opět nakládá se vstupními hodnotami (atributy) zcela libovolně, podobně jako vertex shader. K dispozici jsou veškeré informace, které obsahuje pevná (nenaprogramo­vatelná) rasterizační jednotka zobrazená na předchozím obrázku. Vždy však musí být zaručeno, že výstupem z pixel shaderu musí být již zmíněné informace o hodnotě fragmentu, tj. zejména jeho výsledná barva.

Pozice rasterizačního procesoru v rasterizačním řetězci

Pozice rasterizačního procesoru v rasterizačním řetězci

CS24_early

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

V dalším pokračování tohoto seriálu bude podrobněji popsán způsob programování pixel a vertex shaderů pomocí specializovaných programovacích jazyků.

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

Autor článku

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