Obsah
1. Stručné zopakování postupu vytváření NURB plochy2. Podrobnější popis funkcí pro specifikaci NURB plochy
2.1 Vytvoření objektu pro NURB plochu
2.2 Nastavení a zjištění atributů NURB ploch
2.3 Registrace callback funkce, která se volá v případě výskytu chyby
2.4 Začátek vytváření NURB plochy
2.5 Zadání řídících bodů a uzlového vektoru
2.6 Konec vytváření NURB plochy
2.7 Zrušení objektu s NURB plochou
3. Vlastnosti NURB ploch a jejich nastavování
4. Stupeň NURB plochy
5. Demonstrační příklady
6. Obsah dalšího pokračování
7. Nové funkce z knihovny GLU popsané v této části
8. Zkomprimovaná verze článku i s přílohami
1. Stručné zopakování postupu vytváření NURB plochy
Podobně jako při práci s NURB křivkami, i při práci s NURB plochami se interně využívají evaluátory z grafické knihovny OpenGL. NURB plocha je tedy před vykreslením v grafickém vykreslovacím řetězci OpenGL rozložena na trojúhelníky a plošné čtyřúhelníky, a teprve tato grafická primitiva jsou do vykreslovacího řetězce poslána, tam jsou rozložena na fragmenty a následně vykreslena.
Vývojář aplikace se však těmito detaily nemusí zabývat (pokud samozřejmě nechce nebo nepotřebuje), jelikož funkce z knihovny GLU poskytují možnost pracovat s NURB plochami na vyšší úrovni – stačí pouze specifikovat souřadnice řídících bodů v prostoru spolu s jejich vahami, stupně ploch a uzlové vektory. Celý postup pro práci s NURB plochami lze stručně shrnout do několika bodů:
- Nejprve se musí v operační paměti počítače vytvořit programový objekt, který reprezentuje zvolenou NURB plochu. Vytvoření se provede pomocí funkce gluNewNurbsRenderer(), která je podrobněji popsána v podkapitole 2.1.
- Při vytváření a následném vykreslování NURB plochy se bere do úvahy poměrně velké množství atributů, které se nastavují pomocí funkce gluNurbsProperty() popsané v podkapitole 2.2.
- Následně je možné provést registraci callback funkce, která se zavolá v případě výskytu nějaké chyby při vytváření či renderování NURB ploch. Pro registraci callback funkce je zapotřebí zavolat funkcigluNurbsCallback(). Tato funkce je popsána v podkapitole 2.3.
- Počátek vykreslování NURB plochy, tj. zadávání řídících bodů spolu s jejich vahami a uzlovými vektory, se specifikuje zavoláním funkce gluBeginSurface() – viz podkapitola 2.4.
- Specifikace jednotlivých řídících bodů se provádí pomocí funkce gluNurbsSurface(), která je podrobněji popsána v podkapitole 2.5.
- Konec vykreslování NURB plochy se provede zavoláním funkce gluEndSurface() – viz text podkapitoly 2.6.
- Po specifikaci všech řídících bodů je možné objekt NURB plochy odstranit z operační paměti počítače zavoláním funkce gluEndSurface(), jež je popsána v podkapitole 2.7.
2. Podrobnější popis funkcí pro specifikaci NURB plochy
V této části článku budou podrobněji vysvětleny funkce z nadstavbové knihovny GLU, které je možné nebo nutné volat při specifikaci a následném vykreslení NURB ploch. Některé funkce mají při práci s NURB plochami stejný význam jako v případě NURB křivek, nicméně vzhledem k ucelenosti tohoto článku uvedu tyto funkce znovu i s jejich úplným popisem.
2.1 Vytvoření objektu pro NURB plochu
Prakticky vždy první operací, kterou je nutné při práci s NURB plochami provést, je vytvoření programového objektu, který reprezentuje NURB plochu v operační paměti počítače. Tento objekt se vytváří pomocí funkcegluNewNurbsRenderer(), jedná se tedy o stejnou funkci, jaká byla použita při práci s NURB křivkami. Hlavička této funkce vypadá následovně:
GLUnurbs * gluNewNurbsRenderer( void );
Jak je z hlavičky této 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.
2.2 Nastavení a zjištění atributů NURB ploch
NURB plochy se mohou vytvářet a vykreslovat s různými vlastnostmi, které se nastavují pomocí funkce gluNurbsProperty(). Tato funkce má následující hlavičku:
void gluNurbsProperty( GLUnurbs *nurb, GLenum property, GLfloat value );
V prvním parametru nurb musí být předán ukazatel na objekt (interní paměťovou strukturu) NURB křivky či plochy. Ve druhém parametruproperty je pomocí symbolické konstanty 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 plochou jsou její atributy nastaveny tak, aby se vykreslila „rozumně“, tj. s poměrně malou chybou, ale se zachováním vysoké rychlosti vykreslování. Z toho je patrné, že se knihovna GLU chová k NURB křivkám a plochám prakticky stejně.
Zjištění nastavených atributů NURB plochy 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ží. Všechny atributy jsou typu GLfloat, i když v některých případech mají význam pouze celočíselné hodnoty.
2.3 Registrace callback funkce, která se volá v případě výskytu chyby
Podobně jako při práci s kvadrikami a NURB křivkami, i při specifikaci či vykreslování NURBS ploch mohou vzniknout různé neošetřené stavy a chyby. Z tohoto důvodu poskytuje nadstavbová grafická knihovna GLU možnost registrace callback funkcí, které jsou v případě vzniku nějaké chyby vyvolány. 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 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ů – konkrétní chyby si můžete otestovat vhodnou modifikací demonstračních příkladů).
Registrace callback funkce se provádí zavoláním funkce gluNurbsCallback(), která má následující hlavičku:
void gluNurbsCallback( GLUnurbs * nurb, GLenum which, GLUfuncptr callBackFunc );
V prvním parametru nurb 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říkazugluNewNurbsRenderer(). Ve druhém parametru which musí být předána konstanta GLU_ERROR Třetí parametr callBackFunc 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 nebo pouze 0 (nula).
2.4 Začátek vytváření NURB plochy
Začátek vykreslování NURB plochy se specifikuje zavoláním funkce gluBeginSurface() s hlavičkou:
void gluBeginSurface( GLUnurbs * nurb );
a jediným parametrem nurb, ve kterém je předán ukazatel na objekt NURB plochy. Tato funkce neočekává žádné další parametry, měla by však být uvedena před funkcí gluEndSurface() a gluNurbsSurface(), v opačném případě se generuje chyba.
2.5 Zadání řídících bodů a uzlového vektoru
řídící body NURB plochy jsou spolu se složkami uzlového vektoru předány pomocí funkce gluNurbsSurface(), která má následující hlavičku:
void gluNurbsSurface( GLUnurbs *nurb, GLint sKnotCount, GLfloat *sKnots, GLint tKnotCount, GLfloat *tKnots, GLint sStride, GLint tStride, GLfloat *control, GLint sOrder, GLint tOrder, GLenum type );
První parametr nurm musí obsahovat ukazatel na objekt NURB plochy v operační paměti počítače.
V dalších dvou parametrech je uložena délka uzlového vektoru a ukazatel na pole hodnot uzlového vektoru ve směru růstu parametru s. Následující dva parametry obsahují podobné informace, nyní ale pro uzlový vektor vytvořený ve směru růstu parametru t.
V parametru sStride je specifikována vzdálenost (počet hodnot typu GLfloat) mezi dvěma souřadnicemi řídících bodů ve směru růstu parametru s. V následujícím parametru tStride je uvedena obdobná informace, která se týká řídících bodů ve směru růstu parametru t. V demonstračních příkladech je ukázáno, jak lze všechny řídící body uložit do jednoho pole a jak se v závislosti na tvaru tohoto pole nastavují oba zmíněné parametry.
Přes parametr control je předán ukazatel na pole, které obsahuje souřadnice řídících bodů, kde každá souřadnice musí být typuGLfloat.
Následující dva parametry sOrder a tOrder obsahují stupeň NURB plochy, který je možné nastavovat nezávisle pro směr růstu parametru s i parametru t.
Poslední parametr type obsahuje typ předávaných řídících bodů. Význam hodnoty tohoto parametru je stejný jako v případě NURB křivek. Jediné rozšíření NURB ploch oproti křivkám je možné použít při trimmingu, který si popíšeme v některém z dalších pokračování tohoto seriálu.
2.6 Konec vytváření NURB plochy
Konec vytváření NURB plochy se specifikuje jednoduše – zavolá se funkce gluEndSurface(), která má hlavičku:
void gluEndSurface( GLUnurbs *nurb );
Jediný parametr této funkce má stejný význam jako u funkce gluBeginSurface().
2.7 Zrušení objektu s NURB plochou
Zrušení NURB plochy 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 plocha (a s ní pevně 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, jinak by byla generována chyba (která ovšem nemůže být odchycena callback funkcí, protože objekt s touto funkcí je již zrušen).
3. Vlastnosti NURB ploch a jejich nastavování
U NURB ploch lze nastavit poměrně značné množství vlastností. Pro vykreslování plochy je důležitý především výběr grafických primitiv, na která bude plocha před vykreslením rozdělena. Jsou implementovány dvě možnosti: plocha je buď vykreslena pomocí lomených čar (polyčar), nebo pomocí vyplněných plošných polygonů.
Další vlastností NURB ploch je specifikace způsobu rozdělení plochy na grafická primitiva. Buď se mohou spočítat délky hran vykreslovaných polygonů či délky čar, které nesmí překročit stanovenou hodnotu. Druhým způsobem je výpočet vzdálenosti bodů na polygonu od plochy. Opět se nesmí překročit předem stanovená hodnota. Třetí možností je specifikace počtu vytvořených bodů ve směru růstu parametru s nebo t. Výběr vhodné metody pro určení dalšího dělení plochy má samozřejmě vliv na kvalitu a rychlost vykreslování.
Mezi pokročilejší vlastnosti patří způsob práce s transformačními maticemi při výpočtu pozic řídících bodů NURB plochy. Buď jsou použity aktuálně nastavené transformační matice, nebo je možné pro každou NURB plochu specifikovat samostatné a nezávislé transformační matice. Toho lze využít například při specifikaci vah jednotlivých řídících bodů.
4. Stupeň NURB plochy
Jak jsem již napsal v popisu funkce gluNurbsSurface(), je možné u NURB plochy zadávat její stupeň nezávisle pro směr růstu parametru s i parametru t. To má svůj význam například při vytváření kvadrik či podobných těles. Zde je možné například v jednom směru vytvářet „kubickou NURB“ a ve směru druhém „lineární NURB“, tj. sOrder=4, tOrder=2, protože zadaná hodnota je o jednotku větší než požadovaný stupeň křivky.
Při ručním zadávání NURB ploch jsou většinou oba stupně shodné, ve velkém množství aplikací se používají bikvadratické či bikubické NURB plochy, jejichž stupeň je v obou směrech roven dvěma resp. třem.
Ukázka vykreslení NURB plochy, u které se v jednotlivých směrech v parametrickém prostoru liší její stupně, je uvedena ve druhém demonstračním příkladu.
5. Demonstrační příklady
Po spuštění prvního demonstračního příkladu se zobrazí osvětlená NURB plocha, která je specifikována pomocí šestnácti řídících bodů uspořádaných do mřížky 4×4 body. Při rozdělování NURB plochy na jednotlivé plošky je nastavena velmi nízká tolerance, proto může rendering trvat i na výkonných počítačích poměrně dlouhou dobu.
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
Po překladu a spuštění druhého demonstračního příkladu se zobrazí osvětlená NURB plocha, jež je specifikovaná pomocí dvanácti řídících bodů. Ve směru jednoho parametru se jedná o plochu stupně tři, ve směru parametru druhého o plochu stupně dva. Pro ilustraci jsou znázorněny i řídící body NURB plochy.
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
Třetí demonstrační příklad ukazuje možnost práce s uzlovými vektory, které mají pro oba dva směry v parametrickém prostoru nastaveny jiné hodnoty svých složek.
Zdrojový kód třetího demonstračního příkladu je dostupný zde, jeho HTML verze se zvýrazněním syntaxe zde.
Obrázek 3: Screenshot třetího demonstračního příkladu
6. Obsah dalšího pokračování
V dalším pokračování tohoto seriálu uvedu příklady cílené změny uzlového vektoru a jejich dopad na celkový tvar NURB křivky.
7. Nové funkce z knihovny GLU popsané v této části
gluNewNurbsRenderer()gluDeleteNurbsRenderer()
gluNurbsProperty()
gluNurbsCallback()
gluNurbsSurface()
gluBeginSurface()
gluEndSurface()
gluGetNurbsProperty()
8. 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.