Obsah
ÚvodFunkce glMapGrid()
Funkce glEvalMesh()
Zjednodušení vykreslování Bézierových křivek
Zjednodušení vykreslování Bézierových ploch
Demonstrační příklady
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
Úvod
V předchozích několika částech tohoto seriálu jsme se postupně zabývali programovým výpočtem Bézierových křivek a ploch. Následně jsme si řekli, jakým způsobem lze pro práci s těmito grafickými prvky použít evaluátory, pomocí nichž jsme dosáhli urychlení výpočtu i zobrazení těchto těles. Jak však bylo patrné z demonstračních příkladů, stále se evaluátory používaly poměrně neefektivně – každý bod ležící na křivce či ploše musel být pomocí funkce glEvalCoord*() v programové smyčce samostatně vyhodnocen a poslán jako vrchol vykreslovaného objektu do grafického vykreslovacího řetězce.
Neefektivita výše popsané činnosti spočívá především ve zbytečném posílání dat mezi OpenGL a aplikací, nemluvě o programovém provádění výpočtů. V OpenGL však existuje alternativa ke dříve zmíněnému způsobu práce s Bézierovými křivkami a plochami. Tato alternativa spočívá v tom, že se nejprve zadají všechny parametry Bézierovy křivky či plochy a následně se specifikuje, jakým typem grafických primitiv se má křivka/plocha vykreslit. Po tomto zadání se celý model vykreslí pomocí jednoho příkazu bez zbytečných programových smyček a volání funkcí OpenGL.
Předností tohoto způsobu práce s evaluátory je zjednodušení zápisu programu, protože se pro výpočet jednotlivých vrcholů na křivce nebo ploše nemusí používat programová smyčka – vyhodnocení se provede přímo v OpenGL. Další předností je vyšší rychlost zpracování, protože zejména GPU procesory na novějších grafických kartách mohou veškeré složité výpočty optimalizovat.
Samozřejmě existují také nějaké nevýhody. Značnou nevýhodou je, že nelze manuálně měnit vlastnosti každého vrcholu, například jeho barvu, souřadnice do textury, normálový vektor apod. V případě, že jsou tyto vlastnosti konstantní nebo je lze vypočítat pomocí Bézierovy funkce, nenastávají vážnější problémy. Ty nastanou v případě, že se některá vlastnost (atribut) vrcholu mění podle jiných pravidel, například se načítá z tabulky. Tuto nepříjemnost lze částečně obejít použitím funkce glEvalPoint*().
Funkce glMapGrid*()
První funkcí, kterou si v dnešní části popíšeme, je funkce, pomocí níž se nastavuje rozsah parametrů Bézierovy křivky. Ve druhé části tohoto seriálu jsme si ukázali, jakým způsobem je možné vyčíslit body, které leží na Bézierově křivce. Funkce Bézierovy křivky vrací pro každou hodnotu parametru t souřadnici jednoho bodu. Postupným dosazováním různých hodnot parametru t tak lze vypočítat body, jež na křivce leží.
Funkce glMapGrid1*() provádí přípravu na „hromadné mapování“ mnoha hodnot parametru t. Stačí pouze zadat počáteční a koncovou hodnotu (t1 a t2), kterých má tento parametr nabývat; současně se také musí zadat celkový počet vytvořených hodnot parametru t. Při zavolání dále popsané funkce glEvalMesh1() se parametry postupně začnou vyhodnocovat, tj. bude se vytvářet řada hodnott1, t1+delta, t1+2*delta, … t2, které se budou dosazovat do funkce Bézierovy křivky.
Hodnota delta je vypočtena na základě počáteční a koncové hodnoty spolu s celkovým počtem generovaných hodnot.
Funkce glMapGrid1*() existuje ve dvou variantách, které se liší pouze typem předávaných hodnot:
void glMapGrid1d( GLint tn, GLdouble t1, GLdouble t2 );
resp.
void glMapGrid1f( GLint tn, GLfloat t1, GLfloat t2 );
kde:
- tn představuje celkový počet generovaných hodnot ti.
- t1 je počáteční hodnota parametru t: t1.
- t2 je koncová hodnota parametru t: t2.
V případě práce s Bézierovými plochami taktéž existují funkce pro automatické vyhodnocení bodů na jejich povrchu. Nejprve se však musí specifikovat rozsah parametrů u a v. Navíc je možné plochu vytvořit s různým počtem vrcholů ve směru parametru u a v. Proto je také specifikace poněkud komplikovanější a zajišťují ji tyto dvě funkce:
void glMapGrid2d( GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2 );
resp.
void glMapGrid2f( GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2 );
kde:
- un je celkový počet generovaných hodnot ui.
- u1 je počáteční hodnota parametru u: u1.
- u2 je koncová hodnota parametru u: u2.
- vn je celkový počet generovaných hodnot vj.
- v1 je počáteční hodnota parametru v: v1.
- v2 je koncová hodnota parametru v: v2.
Funkce glEvalMesh*()
Po nastavení rozsahů parametrů pomocí funkcí glMapGrid*() je možné přistoupit k vlastnímu vykreslení Bézierovy křivky. Pro tuto činnost je určena funkce glEvalMesh1(), po jejímž zavolání se celá křivka vykreslí. Tato funkce má následující prototyp:
void glEvalMesh1( GLenum mode, GLint ti1, GLint ti2 );
kde:
- Parametrem mode se udává, jakou grafickou primitivou se bude křivka vykreslovat. Možné jsou dvě hodnoty: GL_POINT – vykreslují se body a GL_LINE – vykreslí se lomená čára (pozor – není toGL_POINTS, ale pouze GL_POINT – tady se dělá často chyba).
- V parametru ti1 se předává index hodnoty pro počáteční bod. Pokud je zde uvedena nula, mapuje se index na hodnotu t1, pokud je zde tn (maximální počet bodů), mapuje se index na hodnotut2.
- V parametru ti2 se předává index hodnoty pro koncový bod. Vlastnosti má stejné jako parametr ti1.
Pro vykreslení Bézierových ploch existuje podobný příkaz jako pro Bézierovy křivky:
void glEvalMesh2( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 );
kde:
- V parametru mode se předává typ grafické primitivy, kterou se plocha vykreslí. Možné hodnoty tohoto parametru jsou: GL_POINT – body,GL_LINE – polyčáry a GL_FILL – pruhy čtyřúhelníků.
- V parametrech i1 a i2 jsou uloženy počáteční a koncové indexy generovaných hodnot ui.
- V parametrech j1 a j2 jsou uloženy počáteční a koncové indexy generovaných hodnot vj.
V dalších odstavcích si ukážeme použití všech výše popsaných funkcí.
Zjednodušení vykreslování Bézierových křivek
V následujícím fragmentu kódu je ukázáno vykreslení Bézierovy křivky pomocí polyčáry:
//----------------------------------------------- // Vykreslení Bézierovy křivky pomocí evaluátorů //----------------------------------------------- void drawBezierUsingEvaluators(GLfloat points[][3]) { #define CAR 50 // dosadit řídící body do evaluátoru glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, points[0][0]); // křivka se vykreslí z padesáti lomených čar glMapGrid1f(CAR, 0.0f, 1.0f); // vlastní vykreslení křivky glEvalMesh1(GL_LINE, 0, CAR); }
Zjednodušení vykreslování Bézierových ploch
Vykreslení vyplněné Bézierovy plochy je možné dosáhnout pomocí následujících příkazů:
//-----------------------------------------------
// Vykreslení Bézierovy plochy pomocí evaluátorů
//-----------------------------------------------
void drawBezierSurfaceUsingEvaluators(GLfloat points[][4][3])
{
#define DELENI 30
glColor3f(0.7f, 0.7f, 0.7f);
// předání řídících bodů Bézierovy plochy
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
points[0][0][0]);
// plocha se vykreslí ze čtyřúhelníků
glMapGrid2f(DELENI, 0.0f, 1.0f, DELENI, 0.0f, 1.0f);
// vlastní vykreslení plochy
glEvalMesh2(GL_FILL, 0, DELENI, 0, DELENI);
}
Demonstrační příklad
Po spuštění prvního demonstračního příkladu se vykreslí Bézierova křivka, která je vypočtena pomocí evaluátorů. Výpočet probíhá ve funkci drawBezierUsingEvaluators(). Nepoužívá se však programová smyčka, ale dvojice funkcí glEvalMesh1() a glMapGrid1f(). Bézierova křivka je zobrazena pomocí bodů, protože ve funkci glEvalMesh1() je parametr mode nastaven na hodnotu GL_POINT.
Počet vypočtených a zobrazených bodů se řídí konstantou BODU, která je implicitně natavena na hodnotu 50.
Pomocí myši lze jednotlivými řídícími body pohybovat po obrazovce, a měnit tak výsledný tvar Bézierovy křivky. Klávesou ESC je možné program ukončit, klávesa F přepíná zobrazení na celou obrazovku a klávesa W přepne zobrazení zpět do okna o velikosti kreslicí plochy 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.
Obrázek 1: Screenshot prvního demonstračního příkladu
Dnešní druhý demonstrační příklad vychází z příkladu prvního. Jediný rozdíl spočívá v tom, že se ve funkci drawBezierUsingEvaluators() Bézierova křivka vykreslí jako lomená čára. Je to způsobeno nastavením parametrumode na hodnotu GL_LINE při volání funkce glEvalMesh(). Počet čar se řídí konstantou CAR, která je implicitně nastavená na hodnotu 50.
Zdrojový kód druhého demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.
Obrázek 2: Screenshot druhého demonstračního příkladu
Po překladu a spuštění třetího demonstračního příkladu se zobrazí Bézierova bikubická plocha, která je vypočtena pomocí evaluátorů. Výpočet probíhá ve funkci drawBezierSurfaceUsingEvaluators() a jsou při něm použity výše popsané funkce glEvalMesh2() a glMapGrid2f().
Bézierova plocha se zobrazí pomocí jednotlivých bodů vykreslovaných grafickou primitivou GL_POINT. Hustota mřížky, tj. počet bodů ve směru parametru u i parametru v, se specifikuje pomocí konstanty DELENI, ktera je implicitně nastavena na hodnotu 30.
Pomocí klávesy S je možné spustit či zastavit animaci Bézierovy plochy, která spočívá v její rotaci okolo středu. Klávesou ESC neboQ se program ukončí, klávesy W a F slouží ke zvětšení a/nebo zmenšení hlavního okna aplikace.
Zdrojový kód třetího demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.
Obrázek 3: Screenshot třetího demonstračního příkladu
Čtvrtý demonstrační příklad se podobá příkladu třetímu. Jediný rozdíl spočívá v tom, že se Bézierova plocha vykreslí pomocí polyčar – ve funkci glMapGrid2f() je první parametr nastaven na GL_LINE. Hustota mřížky se zadává pomocí konstanty DELENI, která je v tomto případě nastavena na hodnotu 20.
Zdrojový kód čtvrtého demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.
Obrázek 4: Screenshot čtvrtého demonstračního příkladu
Pátý demonstrační příklad vychází ze třetího a čtvrtého demonstračního příkladu, Bézierova plocha je však vykreslena pomocí pásu ze čtyřúhelníků.
Zdrojový kód pátého demonstračního příkladu je dostupnýzde, HTML verze se zvýrazněním syntaxe zde.
Obrázek 5: Screenshot pátého demonstračního příkladu
Pokračování
V dalším pokračování tohoto seriálu si ukážeme použití evaluátorů při práci s barvami a souřadnicemi do textury.
Seznam funkcí zmíněných v této části
glEvalCoord()glEvalPoint()
Nové funkce popsané v této části
glMapGrid1d()glMapGrid1f()
glMapGrid2d()
glMapGrid2f()
glEvalMesh1()
glEvalMesh2()
Zkomprimovaná verze článku i s přílohami
Zkomprimovaná verze tohoto článku je umístěna zde.