V dnešní části seriálu věnovanému nadstavbové grafické knihovně GLU si popíšeme význam nastavených hodnot uzlového vektoru a vah řídicích bodů na výsledný tvar NURB plochy. Uvedené poznatky budou prakticky ukázány na přiložených demonstračních příkladech.
NURB plochy patří do třídy parametrických ploch, u kterých musí být kromě souřadnic jejich řídicích bodů zadána i dvojice takzvaných uzlových vektorů (knot vectors), které mají na tvar NURB plochy stejně významný vliv, jako souřadnice jejich řídicích bodů. První uzlový vektor je přiřazen parametru u, druhý uzlový vektor parametru v v dvojrozměrném parametrickém prostoru U-V. Základní vlastnosti a pravidla pro tvorbu uzlového vektoru jsme si ozřejmili už v předchozích částech tohoto seriálu, zde pouze shrnu nejdůležitější informace.
Počet složek uzlového vektoru je závislý především na počtu řídicích bodů uspořádaných ve směru růstu daného parametru (u nebo v), protože řídicí body tvoří v parametrickém prostoru pravidelnou mřížku. Kromě počtu řídicích bodů také záleží na stupni plochy, který se opět udává ve směru růstu některého z parametrů a může být pro oba parametry odlišný. Počet hodnot uložených v uzlovém vektoru je roven součtu počtu příslušných řídicích bodů a stupni plochy, jež se zvětší o jedničku.
Posloupnost hodnot uložených v uzlovém vektoru musí být neklesající, jinak
by nebylo možné vyčíslit rozsah parametrů, pro který je platná každá dvojice
řídicích bodů a prostor mezi těmito body. Musí tedy platit nerovnosti:
ui<=ui+1 a
vi<=vi+1
Počet složek, které mají v uzlovém vektoru stejnou hodnotu musí být menší nebo roven stupni křivky. Pokud se složky se stejnou hodnotou v uzlovém vektoru nachází, musí ležet vedle sebe, jinak by neplatily podmínky uvedené v předchozím odstavci.
Z rekurentního vztahu pro výpočet NURB ploch dále vyplývá, že konkrétní hodnoty uložené v uzlovém vektoru nejsou shora ani zdola omezeny. Ve skutečnosti na těchto hodnotách příliš nezáleží, důležité jsou pouze rozdíly vždy mezi hodnotami dvou sousedních složek v uzlovém vektoru.
NURB plochy tvoří nadmnožinu základních B-spline ploch, které jsou neracionální a uniformní. Neracionalita značí, že všechny řídicí body B-spline plochy mají váhu nastavenou na konstantní hodnotu jedna, tj. wij=1. Uniformitou je myšleno pravidelné rozmístění řídicích bodů v parametrickém prostoru, tj. z indexu řídicího bodu Cij lze bez dalších informací vyjádřit i jeho souřadnici v parametrickém prostoru U-V, stejně jako tomu bylo i u Bézierových ploch.
Neracionální uniformní B-spline plochy lze vytvořit tím způsobem, že se do uzlového vektoru zadají hodnoty, jež se od sebe liší o konstantu. Příkladem může být uzlový vektor s hodnotami [1,2,3,4,5,6]. Příklad vytvoření B-spline plochy je uveden v následující demonstrační funkci:
//--------------------------------------------------- // Vykreslení 3D scény s B-spline plochou //--------------------------------------------------- void drawBspline(void) { #define U_POINTS 6 // počet řídicích #define V_POINTS 6 // bodů ve směru // parametrů u a v #define U_ORDER 4 // stupeň plochy #define V_ORDER 4 // ve směru // parametrů u a v #define U_KNOT (U_POINTS+U_ORDER) // počet složek #define V_KNOT (V_POINTS+V_ORDER) // uložených v // uzlových vektorech // uzlové vektory GLfloat knots1[]={0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9}; GLfloat knots2[]={0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9}; // začátek specifikace NURB plochy gluBeginSurface(nurbs); // nastavení parametrů NURB plochy gluNurbsSurface(nurbs, U_KNOT, // uzlový vektor knots1, // pro parametr u V_KNOT, // uzlový vektor knots2, // pro parametr v V_POINTS * 3, // vzdálenost mezi 3, // položkami pole &ctlpoints[0][0][0], // řídicí body U_ORDER, V_ORDER, // stupeň plochy+1 GL_MAP2_VERTEX_3); // typ řídicích bodů // konec specifikace NURB plochy gluEndSurface(nurbs); }
Obrázek 1: B-spline plocha vykreslená pomocí NURBS
Při práci s B-spline křivkami i plochami se často používají tzv. násobné řídicí body, což jsou sousední řídicí body, které jsou umístěny na stejné souřadnici v ploše či prostoru. Pomocí násobných řídicích bodů lze na křivce/ploše vytvářet zlomy či úseky, které se k řídicím bodům více přimykají (tím se částečně nahrazují váhy řídicích bodů). Také lze zajistit, aby křivka/plocha procházela svými krajními body; u B-spline totiž tato vlastnost běžně splněna není, narozdíl od Bézierových křivek a ploch, které vždy svými krajními body prochází. Příklad B-spline plochy s násobnými řídicími body je uveden na druhém ilustračním obrázku.
Obrázek 2: B-spline plocha s násobnými řídicími body
V uzlových vektorech se některé hodnoty mohou opakovat. Toho se využívá zejména pro zajištění průchodu plochy svými krajními řídicími body. NURB plocha se v tomto případě svými vlastnostmi podobá spíše Bézierovým plátům, než B-spline plochám. Příklad vytvoření NURB plochy, která prochází svými krajními body, je uvedený v následující funkci, obrázek s vytvořenou plochou je zobrazen na třetím obrázku.
//--------------------------------------------------- // Vykreslení 3D scény s NURB plochou, která // prochází svými krajními body //--------------------------------------------------- void drawBspline(void) { #define U_POINTS 6 // počet řídicích #define V_POINTS 6 // bodů ve směru // parametrů u a v #define U_ORDER 4 // stupeň plochy #define V_ORDER 4 // ve směru // parametrů u a v #define U_KNOT (U_POINTS+U_ORDER) // počet složek #define V_KNOT (V_POINTS+V_ORDER) // uložených v // uzlových vektorech // uzlové vektory GLfloat knots1[]={0.0, 0.0, 0.0, 0.0, 0.33, 0.66, 1.0, 1.0, 1.0, 1.0}; GLfloat knots2[]={0.0, 0.0, 0.0, 0.0, 0.33, 0.66, 1.0, 1.0, 1.0, 1.0}; // začátek specifikace NURB plochy gluBeginSurface(nurbs); // nastavení parametrů NURB plochy gluNurbsSurface(nurbs, U_KNOT, // uzlový vektor knots1, // pro parametr u V_KNOT, // uzlový vektor knots2, // pro parametr v V_POINTS * 3, // vzdálenost mezi 3, // položkami pole &ctlpoints[0][0][0], // řídicí body U_ORDER, V_ORDER, // stupeň plochy+1 GL_MAP2_VERTEX_3); // typ řídicích bodů // konec specifikace NURB plochy gluEndSurface(nurbs); }
Obrázek 3: NURB plocha, která prochází svými krajními body
Jak je z výše uvedeného kódu patrné, opakují se v uzlovém vektoru první a poslední čtyři hodnoty. Tento počet opakování není náhodný, ale vychází ze stupně použité NURB plochy. Pokud by byl počet stejných sousedních hodnot vyšší než stupeň křivky zvětšený o jednotku, generovala by se chyba - v důsledku by se při rekurzivním výpočtu dělilo v posledním kroku nulou.
Váhy řídicích bodů mají na tvar NURB plochy velký vliv, protože lokálně ovlivňují chování plochy v okolí řídicích bodů. Implicitně je nastaveno, že řídicí body mají svoji váhu rovnu jedné. Váha však může nabývat libovolných hodnot. Specifikace vah jednotlivých řídicích bodů se provádí ve funkci gluNurbsSurface(), ve které musí být poslední parametr type nastaven na hodnotu GL_MAP2_VERTEX_4 a předávané pole s řídicími body musí pro každý bod obsahovat čtyři složky - x, y, z a váhu w.
Pokud je váha řídicích bodů nastavena na hodnotu větší než jedna, bude NURB křivka k těmto bodům více přitahována. Toho se využívá v situacích, kdy je zapotřebí vytvořit ostřejší zlomy na ploše. U Bézierových ploch a neracionálních B-spline ploch musela být tato problematika řešena buď použitím většího množství řídicích bodů, nebo použitím násobných řídicích bodů.
Obě zmíněné techniky však vedou k nárustu dat (tj. samotných řídicích bodů) a ke komplikované editaci ploch. Proto je změna vah řídicích bodů v mnoha případech ideálním řešením. Ukázka vlivu kladných vah na průběh NURB plochy je ukázána na čtvrtém a pátém ilustračním obrázku.
Extrémní případ nastane, pokud je váha řídicích bodů nekonečná. V tomto případě bude NURB plocha bodem procházet a bude se v něm případně lomit - to ovšem záleží na poloze ostatních řídicích bodů.
Obrázek 4: NURB plocha, u které mají všechny řídicí body jednotkovou váhu
Obrázek 5: NURB plocha, u které mají některé řídicí body váhu zvětšenou
Váhy řídicích bodů mohou být i záporné. V tomto případě je však NURB plocha od těchto bodů lokálně "odtlačována", což se hodí například při vytváření modelů s promáčklinami (páteř u člověka, karoserie automobilů apod.).
Nulové váhy řídicích bodů mají zajímavý efekt: bod s takto nastavenou vahou NURB plochu nijak neovlivní, tj. plocha k němu není ani přitahována ani odpuzována. Na první pohled by se mohlo zdát, že zadávat řídicí body s nulovou vahou je nesmyslné.
V mnoha případech tomu tak opravdu je, někdy však nastane situace, kdy je zapotřebí modelovat plochu, která má v některých místech požadavek na velkou hustotu řídicích bodů a v jiných místech má být naopak hustota velmi malá. V takovém případě lze vytvořit body s nulovou vahou, které nemají na vytvářenou plochu žádný vliv, musí však být uvedeny, protože NURB plocha je specifikována mřížkou řídicích bodů bez vynechaných míst.
Pokud mají všechny řídicí body NURB plochy nastavenou kladnou váhu, leží celá NURB plocha v konvexní obálce těchto bodů, tj. v minimálním konvexním tělese, které těsně NURB plochu obepíná. Tato vlastnost je velmi důležitá, protože pomocí konvexní obálky lze řešit například kolize pohybujících se těles.
Postup při řešení kolizí je následující: nejprve se zkontroluje, zda nastala kolize konvexních obálek (to je výpočetně jednoduché, protože obálka je tvořena několika málo ploškami) a teprve při kolizi obálek se testují kolize NURB ploch, což je výpočetně mnohem složitější a samozřejmě také zdlouhavější.
Konvexní obálku lze mimochodem také využít při zobrazování NURB ploch metodou zpětného sledování paprsku (raytracingem), kdy lze průsečík paprsku prvotně řešit s komplexní obálkou a teprve při protnutí konvexní obálky paprskem s vlastní NURB plochou. Tuto metodu lze zkombinovat i s dalšími typy tzv. obalových těles (koule, osově orientované kvádry atd.).
Po spuštění prvního demonstračního příkladu se zobrazí osvětlená NURB plocha specifikovaná pomocí 36ti řídicích bodů uspořádaných do matice 6x6 bodů. Spolu s řídicími body jsou specifikovány i uzlové vektory, které tvoří bázi pro B-spline plochu. Pro ilustraci jsou znázorněny i řídicí body NURB plochy.
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 6: Screenshot prvního demonstračního příkladu
Ve druhém demonstračním příkladu je ukázáno, jakým způsobem mohou být použity násobné body pro vytváření křivky s prudkými zlomy.
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 7: Screenshot druhého demonstračního příkladu
Třetí příklad ilustruje použití uzlového vektoru, ve kterém jsou na začátku a konci zadány stejné hodnoty. Ty zapříčiní, že plocha prochází svými krajními body, podobně jako Bézierův plát.
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 8: Screenshot třetího demonstračního příkladu
V dalším pokračování tohoto seriálu bude vysvětleno, jakým způsobem se dají do NURB plochy vytvářet otvory. Jedná se o takzvané trimování, pomocí něhož lze tvořit složité modely těles (s dírami, konstrukčně složitými spoji apod.) složenými z NURB ploch.
Zkomprimovaná verze tohoto článku i s přílohami a demonstračními příklady je uložena zde.