Hlavní navigace

OpenGL evaluátory (6)

Pavel Tišnovský 15. 6. 2004

V dnešní části seriálu o evaluátorech OpenGL si povíme, jakým způsobem je možné zjednodušit a v mnohých případech i urychlit vykreslování Bézierových křivek a ploch. Pomocí dvou nových příkazů lze naráz (tj. bez programové smyčky) vykreslit celou Bézierovu plochu nebo křivku.

Obsah

Úvod
Funkce 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:

  1. tn představuje celkový počet generovaných hodnot ti.
  2. t1 je počáteční hodnota parametru t: t1.
  3. 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:

  1. un je celkový počet generovaných hodnot ui.
  2. u1 je počáteční hodnota parametru u: u1.
  3. u2 je koncová hodnota parametru u: u2.
  4. vn je celkový počet generovaných hodnot vj.
  5. v1 je počáteční hodnota parametru v: v1.
  6. 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:

  1. 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).
  2. 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.
  3. 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:

  1. 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ů.
  2. V parametrech i1 a i2 jsou uloženy počáteční a koncové indexy generovaných hodnot ui.
  3. 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 drawBezierUsin­gEvaluators(). 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.

Screenshot prvního demonstračního příkladu
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 drawBezierUsin­gEvaluators() 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.

Screenshot druhého demonstračního příkladu
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 drawBezierSur­faceUsingEvalu­ators() 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.

Screenshot třetího demonstračního příkladu
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.

Screenshot čtvrtého demonstračního příkladu
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.

Screenshot pátého demonstračního příkladu
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.

Našli jste v článku chybu?
Vitalia.cz: To není kašel! Správná diagnóza zachrání život

To není kašel! Správná diagnóza zachrání život

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

120na80.cz: Stoná vaše dítě často? Upravte mu jídelníček

Stoná vaše dítě často? Upravte mu jídelníček

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Vitalia.cz: 4 pravidla pro návštěvu čerta

4 pravidla pro návštěvu čerta

Podnikatel.cz: Babiše přesvědčila 89letá podnikatelka?!

Babiše přesvědčila 89letá podnikatelka?!

Vitalia.cz: 9 největších mýtů o mase

9 největších mýtů o mase

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Podnikatel.cz: Udávání kvůli EET začalo

Udávání kvůli EET začalo

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

DigiZone.cz: ČT má dalšího zástupce v EBU

ČT má dalšího zástupce v EBU

Vitalia.cz: Znáte „černý detox“? Ani to nezkoušejte

Znáte „černý detox“? Ani to nezkoušejte

Podnikatel.cz: Zavře krám u #EET Malá pokladna a Teeta?

Zavře krám u #EET Malá pokladna a Teeta?

Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA