Obsah
1. Postup při práci s NURB křivkami2. Vytvoření objektu pro NURB křivky
3. Nastavení a zjištění atributů NURB křivek
4. Registrace callback funkce, která se volá v případě chyby
5. Začátek vytváření NURB křivky
6. Zadání řídících bodů a knot vektoru NURB křivky
7. Konec vytváření NURB křivky
8. Zrušení objektu pro NURB křivky
9. Demonstrační příklady
10. Obsah dalšího pokračování
11. Nové funkce GLU popsané v této části
12. Odkazy na další zdroje na Internetu
13. Zkomprimovaná verze článku i s přílohami
1. Postup při práci s NURB křivkami
V dnešním dílu se zaměřím na popis práce s NURB křivkami pomocí funkcí, jež jsou v knihovně GLU dostupné. Práce s NURB je interně založená na evaluátorech, které jsem podrobně popsal ve svém minulém seriálu na Rootu – viz odkazy na konci článku. Postup při práci s NURB křivkami lze shrnout do několika bodů. Všimněte si prosím podobnosti práce s NURB křivkami s již dříve popsaným postupem práce s kvadrikami (OpenGL evaluátory VI, OpenGL evaluátory VII a OpenGL evaluátory VIII):
- Nejprve je vhodné korektně nastavit stavový stroj OpenGL. Vzhledem k tomu, že se při vykreslování NURB generuje velký počet vrcholů, je možné zvážit, zda se má pro každý vrchol automaticky počítat i jeho normála. Pokud to není nutné (například se nepoužívá osvětlení), je možné výpočet normálových vektorů zakázat funkcí glDisable(GL_AUTO_NORMAL), opětovné povolení se provede funkcí glEnable(GL_AUTO_NORMAL).
- Dále se musí vytvořit programový objekt, který reprezentuje zvolenou NURB křivku v operační paměti počítače. Vytvoření se provede pomocí funkce gluNewNurbsRenderer().
- Pro NURB křivky je možné nastavit několik atributů, podobně jako u dříve popsaných kvadrik. O nastavení těchto atributů se stará funkce gluNurbsProperty().
- Následně je možné provést registraci callback funkce, jež se zavolá v případě výskytu nějaké chyby při vytváření či renderování NURB křivek. Pro registraci je zapotřebí zavolat funkci gluNurbsCallback(). Typů chyb, které mohou při práci s NURBS vzniknout, je velmi mnoho (v používané verzi knihovny GLU celkem 37), proto je vhodné na chyby jasně definovaným způsobem reagovat.
- Počátek vytváření NURB křivky (tj. zadávání řídících bodů a uzlového vektoru) se specifikuje zavoláním funkce gluBeginCurve().
- Poté je již možné specifikovat jednotlivé řídící body a složky uzlového vektoru přes funkci gluNurbsCurve().
- Konec specifikace parametrů NURB křivky, a tím i ukončení jejího vykreslování, je indikován zavoláním funkce gluEndCurve().
- Po použití NURBS křivky je možné zrušit i její objekt zavoláním funkce gluDeleteNurbsRenderer().
Jednotlivé body výše zmíněného postupu si podrobněji popíšeme v následujících odstavcích.
2. Vytvoření objektu pro NURB křivky
Prvním důležitým úkolem při práci s NURB křivkami je vytvoření programového objektu, který reprezentuje NURB křivku v operační paměti počítače. Tento objekt se vytváří pomocí funkce gluNewNurbsRenderer() a má následující hlavičku:
GLUnurbs *gluNewNurbsRenderer( void );
Jak je z hlavičky předchozí funkce patrné, nevyžaduje se žádný parametr. Funkce vrací buď ukazatel na paměťovou strukturu popisující vzniklý objekt, nebo, v případě chyby, hodnotu 0 (resp. NULL, to je čitelnější).
3. Nastavení a zjištění atributů NURB křivek
NURB křivky se mohou vytvářet s různými vlastnostmi, které se nastavují pomocí funkce gluNurbsProperty(). Tato funkce má hlavičku:
void gluNurbsProperty( GLUnurbs * nurb, GLenum property, GLfloat value );
V parametru nurb musí být předán ukazatel na objekt (paměťovou strukturu) NURB křivky či plochy. V parametru property je specifikován atribut, který se má změnit. Hodnota tohoto atributu se předává v posledním parametru value. Při inicializaci objektu s NURB křivkou či plochou jsou její atributy nastaveny tak, aby se křivka/plocha vykreslila „rozumně“, tj. s poměrně malou chybou, ale se zachováním vysoké rychlosti vykreslování. Existují samozřejmě situace, kdy je počáteční nastavení atributů nekorektní, podrobnosti si popíšeme v některém z dalších pokračování tohoto seriálu.
Zjištění nastavených atributů lze provést pomocí funkce gluGetNurbsProperty() s následující hlavičkou:
void gluGetNurbsProperty( GLUnurbs * nurb, GLenum property, GLfloat * data );
Význam jednotlivých parametrů je u této funkce prakticky shodný jako u funkce gluNurbsProperty(), s tím rozdílem, že poslední parametr data obsahuje ukazatel na proměnnou, do které se vybraný atribut uloží.
4. Registrace callback funkce, která se volá v případě chyby
Podobně jako při práci s kvadrikami, i při vykreslování NURBS mohou vzniknout různé neošetřené stavy a chyby. Z tohoto důvodu poskytuje knihovna GLU možnost registrace callback funkcí, které jsou v případě vzniku nějaké chyby vyvolány. Koncept callback funkcí je velmi pružný, protože se tyto mohou měnit přímo za běhu aplikace, což je rozdíl oproti např. strukturovaným výjimkám. Aplikace by měla na vzniklé chyby nějakým způsobem reagovat, protože se může stát, že se při výskytu chyby nemusí vykreslit celá NURB křivka či plocha, nebo se může vykreslit nesmyslný tvar (zejména při chybně zadaném uzlovém vektoru či vahách krajních řídících bodů).
Registrace callback funkce se provádí pomocí funkce gluNurbsCallback(), jež má hlavičku:
void gluNurbsCallback( GLUnurbs * nurb, GLenum which, GLUfuncptr callBackFunc );
V prvním parametru se opět předává ukazatel na objekt NURB křivky či plochy, jež v operační paměti počítače vznikl vyvoláním příkazu gluNewNurbsRenderer(). Ve druhém parametru musí být vždy předána konstanta GLU_ERROR, v budoucnu se však mohou vyskytnout i další události, při kterých se callback funkce bude volat. Třetí parametr obsahuje ukazatel na uživatelem vytvořenou callback funkci, jež nevrací žádnou hodnotu (tj. je typu void) a má jeden parametr typu GLenum, ve kterém se předává kód vzniklé chyby. Callback funkci lze jednoduše odregistrovat tak, že se v posledním parametru předá hodnota NULL.
5. Začátek vytváření NURB křivky
Začátek vykreslování NURB křivky se specifikuje zavoláním funkce gluBeginCurve() s hlavičkou:
void gluBeginCurve( GLUnurbs * nurb );
a jediným parametrem nurb, ve kterém je předán ukazatel na objekt NURB křivky. Tato funkce neočekává žádné další parametry.
6. Zadání řídících bodů a knot vektoru NURB křivky
Prakticky nejsložitější funkcí, kterou knihovna GLU tvůrcům aplikací nabízí, je funkce pro bližší specifikaci NURB křivky a plochy. U NURB křivky se jedná o funkci gluNurbsCurve() s hlavičkou:
void gluNurbsCurve( GLUnurbs * nurb, GLint knotCount, GLfloat * knots, GLint stride, GLfloat * control, GLint order, GLenum type );
Pomocí této funkce se specifikují řídící body NURB křivky, váhy jednotlivých řídících bodů a složky uzlového vektoru. Vzhledem ke složitosti této funkce se budu jejím podrobnějším popisem zabývat až v následující části tohoto seriálu.
7. Konec vytváření NURB křivky
Vzhledem k tomu, že začátek vytváření NURB křivky se specifikoval zavoláním funkce gluBeginCurve(), je jednoduché odhadnout jméno funkce, jejímž zavoláním se provede ukončení vytváření zpracovávané křivky. Ano, tato funkce se podle všech očekávání jmenuje gluEndCurve() a má hlavičku:
void gluEndCurve( GLUnurbs * nurb; );
se stejným parametrem, jako má funkce gluBeginCurve().
8. Zrušení objektu pro NURB křivky
Zrušení NURB křivky je stejně jednoduché jako její vytvoření. Stačí pouze zavolat funkci gluDeleteNurbsRenderer(), která má hlavičku:
void gluDeleteNurbsRenderer( GLUnurbs * nurb );
Tato funkce opět požaduje pouze jeden parametr, v němž je uložen ukazatel na NURBS objekt, který se má zrušit. Po zavolání této funkce je NURB křivka či plocha (a s ní spojený renderovací objekt) zrušena, tj. jsou uvolněny všechny interní paměťové struktury, které se k tomuto objektu vztahují. Ukazatel na zrušený objekt se již nesmí dále v běžící aplikaci použít.
9. Demonstrační příklady
Po spuštění prvního demonstračního příkladu se zobrazí NURB křivka, která je specifikovaná pomocí čtyř řídících bodů. Uzlový vektor musí v tomto případě obsahovat osm položek. Vzhledem k tomu, že první a poslední čtveřice položek je v uzlovém vektoru stejná, prochází křivka svým prvním a posledním řídícím bodem. Kromě křivky jsou zobrazeny i polohy jednotlivých řídících bodů, které jsou pro lepší ilustraci spojeny polyčarou.
Zdrojový kód prvního demonstračního příkladu je dostupný zde, jeho HTML verze se zvýrazněním syntaxe zde.
Obrázek 1: Screenshot prvního demonstračního příkladu
Druhý demonstrační příklad je v mnohém podobný příkladu prvnímu s tím rozdílem, že je NURB křivka specifikovaná osmi řídícími body a uzlový vektor má dvanáct položek (tedy o čtyři více, než je počet řídících bodů, což odpovídá stupni křivky).
Zdrojový kód druhého demonstračního příkladu je dostupný zde, jeho HTML verze se zvýrazněním syntaxe zde.
Obrázek 2: Screenshot druhého demonstračního příkladu
10. Obsah dalšího pokračování
V dalším pokračování tohoto seriálu bude uveden podrobný popis funkce gluNurbsCurve() s příklady použití. Zaměřím se zejména na popis vlastností uzlového vektoru a významu vah jednotlivých řídících bodů na tvar výsledné NURB křivky.
11. Nové funkce GLU popsané v této části
gluNewNurbsRenderer()gluDeleteNurbsRenderer()
gluNurbsProperty()
gluNurbsCallback()
gluNurbsCurve()
gluGetNurbsProperty()
gluBeginCurve()
gluEndCurve()
12. Odkazy na další zdroje na Internetu
- OpenGL evaluátory I – Úvod, reprezentace těles v počítačové grafice
- OpenGL evaluátory II – Teorie Bézierových křivek
- OpenGL evaluátory III – Teorie Bézierových ploch
- OpenGL evaluátory IV – Použití evaluátorů pro vykreslování Bézierovy křivky
- OpenGL evaluátory V – Použití evaluátorů pro vykreslování Bézierovy plochy
- OpenGL evaluátory VI – Zjednodušení vykreslování Bézierových křivek a ploch
- OpenGL evaluátory VII – Použití evaluátorů při specifikaci barev
- OpenGL evaluátory VIII – Použití evaluátorů při práci s texturami
- OpenGL evaluátory IX – Automatické a poloautomatické generování normál
- OpenGL evaluátory X – Obsah jednotlivých dílů, seznam příkladů a funkcí
13. Zkomprimovaná verze článku i s přílohami
Zkomprimovaná verze tohoto článku i s přílohami a demonstračními příklady je uložena zde.