Hlavní navigace

OpenGL evaluátory (4)

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

Sdílet

V tomto pokračování seriálu o OpenGL evaluátorech se budeme zabývat použitím evaluátorů při vykreslování Bézierových křivek. Ukážeme si postup, jakým je možné nejprve zadat řídící body a další parametry Bézierovy křivky a následně Bézierovu křivku vykreslit.

Obsah

Použití evaluátorů pro vykreslení Bézierovy křivky
Nastavení souřadnic řídících bodů Bézierovy křivky
Nastavení a povolení jednodimenzio­nálního evaluátoru
Použití jednodimenzio­nálního evaluátoru při vykreslování Bézierovy křivky
Využití mapování hodnot pro parametr t
Demonstrační příklady
Obsah dalších pokračování
Seznam funkcí OpenGL zmíněných v této části
Nové funkce OpenGL popsané v této části
Zkomprimovaná verze článku i s přílohami

Použití evaluátorů pro vykreslení Bézierovy křivky

Při popisu grafické knihovny OpenGL (viz první díl seriálu o OpenGL, který taktéž vycházel na Rootu) jsem se zmiňoval o vykreslování základních grafických primitiv, jako jsou body, úsečky, polyčáry (lomené úsečky), trojúhelníky a plošné konvexní polygony. Tvorba složitějších těles pomocí skládání grafických primitiv je velmi složitá a neefektivní, proto OpenGL nabízí i rozšíření pro práci s parametrickými křivkami a plochami pomocí takzvaných evaluátorů, což není nic jiného než aplikační rozhraní k výpočtům parametrických Bézierových křivek a ploch.

V knihovně GLU, která tvoří nadstavbu nad grafickou knihovnou OpenGL, jsou možnosti evaluátorů rozšířeny tak, že se pomocí nich dají počítat a vykreslovat i NURBS (Non-Uniform RationalB-Splines/Surfaces) křivky a plochy.

Na prvním obrázku je zobrazen vykreslovací řetězec OpenGL, ve kterém je vyznačen i blok Evaluators určený pro vyhodnocování bodů ležících na parametrické křivce či ploše. Jak je z obrázku patrné, jsou evaluátory použity pouze pro geometrická data (ať už skalární, či vektorová), tj. pro souřadnice vrcholů grafických primitiv, souřadnice do textury, barvy vrcholů nebo celých ploch apod. Rastrová data (tj. informace o pixelech a fragmentech, které se ve vykreslovacím řetězci zpracovávají) nejsou pomocí evaluátorů v žádném směru měněny.

Vykreslovací řetězec OpenGL s vyznačeným blokem pro vyhodnocení evaluátorů
Obrázek 1: Vykreslovací řetězec OpenGL s vyznačeným blokem pro vyhodnocení evaluátorů

Pomocí OpenGL evaluátorů lze generovat souřadnice, které je možné použít při automatickém vytváření vrcholů na povrchu tělesa, normálových vektorů ve vrcholech, souřadnic do textury a barvy jednotlivých vrcholů. Evaluátory využívají jako bázové funkce Bernsteinovy polynomy, proto je možné velmi jednoduše vytvářet Bézierovy křivky a plochy.

Je jasné, že vykreslování pomocí evaluátorů se od vykreslování s programovým výpočtem parametrických křivek a ploch liší především v rychlosti. Moderní grafické akcelerátory totiž umožňují výpočty pomocí evaluátorů provádět přímo na GPU (grafickém procesoru). Toto zrychlení se projeví především při práci s Bézierovými plochami (pláty), kterými se budeme zabývat v navazujících částech tohoto seriálu.

V dalším textu si ukážeme jednoduchý příklad rozdělený do několika bodů, podle nějž lze vykreslit Bézierovu kubickou křivku pomocí evaluátorů.

Nastavení souřadnic řídících bodů Bézierovy křivky

Před vlastním zadáním Bézierovy křivky je zapotřebí specifikovat její řídící body. Pro jednoduchost budeme uvažovat Bézierovu kubickou křivku, která je zadána čtyřmi body. Prvním a posledním bodem křivka prochází, dva prostřední body se používají pro zadání tečných vektorů na začátku a na konci křivky.

Všechny čtyři body současně představují konvexní obálku, ve které celá křivka leží – to je důležitá vlastnost Bézierových křivek, která je v počítačové grafice často využívána.

Nejjednoduššeji lze zadat řídící body křivky jako dvojrozměrné pole. Každý řádek pole představuje informace o jednom řídícím bodu, který má tři složky – souřadnice x, y a z. Zadání řídících bodů tedy může v programovacím jazyku C nebo C++ vypadat například následovně:

// řídící body Bézierovy křivky
GLfloat controlPoints[4][3]={
    {100.0, 100.0, 0.0},
    {400.0, 100.0, 0.0},
    {400.0, 400.0, 0.0},
    {100.0, 400.0, 0.0}
};

Ve výše uvedeném fragmentu zdrojového kódu jsou specifikovány čtyři řídící body. Bézierova křivka prochází prvním a posledním bodem, tj. souřadnicemi [100, 100] a [100, 400]. Druhý a třetí bod je použit pro zadání tečných vektorů. Výsledná Bézierova křivka je zobrazena na druhém obrázku.

Bézierova kubická křivka
Obrázek 2: Bézierova kubická křivka

Nastavení a povolení jednodimenzio­nálního evaluátoru

Pokud již máme zadány řídící body Bézierovy křivky (tj. bylo vytvořeno pole či oblast paměti, ve které se řídící body nachází), můžeme přistoupit k dalšímu kroku. Tím je povolení a nastavení parametrů jednodimenzio­nálního evaluátoru.

Po provedení těchto příkazů se informace o souřadnicích řídících bodů a stupni křivky uloží do paměti rezervované knihovnou OpenGL. V případě, že je vykreslování Bézierových křivek přímo podporováno grafickým akcelerátorem, může dojít ke kopii souřadnic řídících bodů z operační paměti počítače do interní paměti na grafické kartě. Při vyjadřování souřadnic bodů ležících na křivce se na základě těchto informací (a samozřejmě v závislosti na parametru t) souřadnice vyhodnotí a následně pošlou do vykreslovacího řetězce, podobně jako explicitně zadávané vrcholy či normály.

Prvním důležitým příkazem je povolení práce jednodimenzio­nálního evaluátoru. Povolení se provede jednoduše pomocí známého příkazu:

// povolení 1D evaluátoru
glEnable(GL_MAP1_VERTEX_3);

Opětné zakázání použití evaluátorů po vykreslování by se provedlo příkazem:

// zakázání 1D evaluátoru
glDisable(GL_MAP1_VERTEX_3);

Následujícím příkazem se nastaví řídící body Bézierovy křivky a rozsah, ze kterého je mapován parametr t:

// dosadit řídící body do evaluátoru
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]); 

Evaluátor nazývám jednodimenzionálním z toho důvodu, že se pro vyhodnocení souřadnic vrcholů (nebo barvy atd.) musí do modulu s evaluátorem předat pouze jeden parametr t. V dalších pokračováních tohoto seriálu si ukážeme i evaluátory, které pracují se dvěma parametry u a v.

Prvním argumentem funkce glMap1f() je specifikováno, které geometrické informace se budou pomocí evaluátorů počítat. V našem demonstračním příkladu se budou počítat souřadnice vrcholů lomené čáry, v příkladech uvedených v dalších dílech to budou jiné informace, například normály nebo souřadnice do textury. V prvním argumentu je možné zadat tyto konstanty: GL_MAP1_VERTEX3 (souřadnice vrcholů x, y, z), GL_MAP1_VERTEX4 (souřadnice vrcholů x, y, z a w), GL_MAP1_INDEX (index do barvové palety), GL_MAP1_COLOR4 (barva RGBA), GL_MAP1_NORMAL (normálový vektor), GL_MAP1_TEXTU­RE_COORD1 (jedna souřadnice do textury), GL_MAP1_TEXTU­RE_COORD2 (dvě souřadnice do textury), GL_MAP1_TEXTU­RE_COORD3 (tři souřadnice do textury) a GL_MAP1_TEXTU­RE_COORD4 (čtyři souřadnice do textury).

Ve druhém a třetím argumentu je zadán (zjednodušeně řečeno) rozsah hodnot parametru t. Ten je interně mapován z námi zadaného rozsahu do rozsahu 0–1.

Ve čtvrtém parametru je zadán počet číselných hodnot, které se nacházají mezi jednotlivými řídícími body. V našem případě se předává pole bodů, kde každý bod má tři souřadnice, proto je zde také tato hodnota (3) zadána. Je však možné vytvořit pole s řídícími body, ve kterém budou kromě vlastních souřadnic uloženy i další informace (barvy atd.), proto nám OpenGL nabízí možnost specifikace počtu těchto hodnot, které se budou přeskakovat.

V pátém parametru je zadán počet řídících bodů, který je v případě Bézierových kubických křivek roven čtyřem.

V posledním, šestém argumentu je předán ukazatel na oblast paměti, ve kterém se nachází informace o jednotlivých řídících bodech.

Použití jednodimenzio­nálního evaluátoru při vykreslování Bézierovy křivky

Po nastavení a povolení evaluátoru je jeho použití velmi jednoduché. Nejprve je zapotřebí nastavit barvu vykreslované lomené čáry (polyčáry). Tu je možné nastavit pomocí známého příkazu glColor3f():

// nastavení barvy vykreslované polyčáry
glColor3f(1.0f, 1.0f, 1.0f);

Dále je již možné lomenou čáru, která reprezentuje (alespoň hrubě) Bézierovu křivku, vykreslit. Budeme postupovat podobně jako u programového vykreslování Bézierovy křivky, tj. musíme vyčíslit každý vrchol lomené čáry. Místo programového výpočtu souřadnic [x, y] a dosazení těchto souřadnic do příkazu glVertex2f() se však pouze zavolá funkce glEvalCoord1f().

Tato funkce automaticky vypočítá souřadnice nového bodu na základě zadaného parametru t, který implicitně leží v rozsahu od 0 do 1, ale může být pomocí funkce glMap1f() přemapován. To, že se provádí výpočet souřadnic vrcholů, bylo specifikováno prvním argumentem v příkazuglMap1f(), který je popsán v předešlém odstavci.

Je samozřejmě možné mít současně nastaveno více evaluátorů – jeden může provádět výpočet souřadnic vrcholů těles, druhým může být počítána barva těchto vrcholů apod. Jediné omezení spočívá v rychlosti výpočtu, zejména při softwarové emulaci funkcí OpenGL.

Celá smyčka pro vykreslení Bézierovy křivky tedy může vypadat následovně (všimněte si, že parametr funkce glEvalCoord1f() opravdu probíhá od 0 do 1):

// vykreslit lomenou křivku (polyčáru)
glBegin(GL_LINE_STRIP);
for (i=0; i<=100; i++)
    glEvalCoord1f((GLfloat) i/100.0f);
glEnd();

Využití mapování hodnot pro parametr t

Ve výše uvedených zlomcích zdrojového kódu bylo použito velmi jednoduchého mapování hodnot pro parametr t, protože se prováděl převod z rozsahu 0–1 do téhož rozsahu. Pro programovou implementaci by však bylo mnohdy jednodušší zadávat místo reálných hodnot hodnoty celočíselné, například z rozsahu 0–100. To je samozřejmě možné, dokonce to povede k jednoduššímu zápisu programu.

Nejprve je nutné změnit mapování při zadávání řídících bodů Bézierovy křivky:

// dosadit řídící body do evaluátoru
glMap1f(GL_MAP1_VERTEX_3, 0.0, 100.0, 3, 4, &ctrlpoints[0][0]); 

Smyčka pro vykreslení Bézierovy křivky složené z polyčáry o sto úsecích se při takto zadaném mapování zjednoduší:

glBegin(GL_LINE_STRIP);
    for (i=0; i<=100; i++)
    // vykreslit krivku jako polycaru
        glEvalCoord1f((GLfloat) i);
    glEnd();

Jak je z předešlého úseku kódu patrné, není zapotřebí programově převádět hodnotu ve funkci glEvalCoord1f() do rozsahu 0–1. Je však stále nutné použít reálná čísla, proto se provádí přetypování celočíselné hodnoty na datový typ GLfloat.

Demonstrační příklad

Po spuštění prvního demonstračního příkladu se vykreslí Bézierova křivka, která je vypočtená pomocí OpenGL evaluátorů. Výpočet bodů, jež leží na Bézierově křivce, probíhá ve funkci drawBezierUsin­gEvaluators(). Klávesou ESC nebo Q lze aplikaci ukončit, klávesa F přepne zobrazení na celou obrazovku, klávesa W přepne zobrazení zpět do okna o přednastavené velikosti 450×450 pixelů.

Zdrojový kód prvního demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.

Screenshot prvního demonstračního příkladu
Obrázek 3: Screenshot prvního demonstračního příkladu

Druhý demonstrační příklad je podobný příkladu prvnímu. Jediný rozdíl spočívá v tom, že u druhého příkladu je možné měnit polohu jednotlivých řídících bodů pomocí myši. V horní části okna aplikace jsou zobrazeny pozice jednotlivých řídících bodů a číslo právě vybraného řídícího bodu. Další ovládání aplikace pomocí klávesnice je stejné jako u prvního demonstračního příkladu.

Zdrojový kód druhého demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.

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

UX DAy - tip 2

Obsah dalších pokračování

V dalším pokračování tohoto seriálu si ukážeme použití evaluátorů při vykreslování Bézierových bikubických ploch. Navážeme tedy na minulý díl, ve kterém jsme si Bézierovy plochy popsali teoreticky spolu s programovou implementací.

Seznam funkcí zmíněných v této části

glBegin()
glEnd()
glVertex2f()
glEnable()
glDisable()
glColor3f()
 

Nové funkce popsané v této části

glMap1f()
glEvalCoord1f()

Zkomprimovaná verze článku i s přílohami

Zkomprimovaná verze tohoto článku je umístěna zde.

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.