OpenGL a nadstavbová knihovna GLU (15)

9. 11. 2004
Doba čtení: 8 minut

Sdílet

V dnešní části seriálu věnovaného nadstavbové grafické knihovně GLU si popíšeme význam nastavených hodnot uzlového vektoru a vah řídící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.

Obsah

1. Význam uzlového vektoru NURB ploch
2. Vytvoření B-spline ploch z NURB ploch
3. Opakující se hodnoty v uzlovém vektoru
4. Váhy řídících bodů
5. Kladné váhy řídících bodů
6. Záporné a nulové váhy řídících bodů
7. Konvexní obálka NURB plochy a její význam
8. Demonstrační příklady
9. Obsah dalšího pokračování
10. Seznam funkcí OpenGL, GLU a GLUT zmíněných v této části
11. Zkomprimovaná verze článku i s přílohami
 

1. Význam uzlového vektoru NURB ploch

NURB plochy patří do třídy parametrických ploch, u kterých musí být kromě souřadnic jejich řídících bodů zadána i dvojice takzvaných uzlových vektorů (knot vectors), které mají na tvar NURB ploch stejně významný vliv jako souřadnice jejich řídící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 řídících bodů uspořádaných ve směru růstu daného parametru (u nebo v), protože řídící body tvoří v parametrickém prostoru pravidelnou mřížku. Kromě počtu řídící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 řídící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 řídící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ázejí, 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.

2. Vytvoření B-spline ploch z NURB ploch

NURB plochy tvoří nadmnožinu základních B-spline ploch, které jsou neracionální a uniformní. Neracionalita značí, že všechny řídící body B-spline plochy mají váhu nastavenou na konstantní hodnotu jedna, tj. wij=1. Uniformitou je myšleno pravidelné rozmístění řídících bodů v parametrickém prostoru, tj. z indexu řídící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 řídící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],   // řídící body
        U_ORDER, V_ORDER,          // stupeň plochy+1
        GL_MAP2_VERTEX_3);         // typ řídících bodů

    // konec specifikace NURB plochy
    gluEndSurface(nurbs);
}

Obrázek 1: B-spline plocha vykreslená pomocí 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é řídící body, což jsou sousední řídící body, které jsou umístěny na stejné souřadnici v ploše či prostoru. Pomocí násobných řídících bodů lze na křivce/ploše vytvářet zlomy či úseky, které se k řídícím bodům více přimykají (tím se částečně nahrazují váhy řídící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í, na rozdí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 řídícími body je uveden na druhém ilustračním obrázku.

Obrázek 2: B-spline plocha s násobnými řídícími body
Obrázek 2: B-spline plocha s násobnými řídícími body

3. Opakující se hodnoty v uzlovém vektoru

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 řídící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 a vytvořenou plochu můžete vidět 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 řídící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],   // řídící body
        U_ORDER, V_ORDER,          // stupeň plochy+1
        GL_MAP2_VERTEX_3);         // typ řídících bodů

    // konec specifikace NURB plochy
    gluEndSurface(nurbs);
}

Obrázek 3: NURB plocha, která prochází svými krajními body
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ý, nýbrž 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.

4. Váhy řídících bodů

Váhy řídících bodů mají na tvar NURB plochy velký vliv, protože lokálně ovlivňují chování plochy v okolí řídících bodů. Implicitně je nastaveno, že řídící body mají svoji váhu rovnu jedné. Váha však může nabývat libovolných hodnot. Specifikace vah jednotlivých řídících bodů se provádí ve funkci gluNurbsSurfa­ce(), ve které musí být poslední parametr type nastaven na hodnotu GL_MAP2_VERTEX4 a předávané pole s řídícími body musí pro každý bod obsahovat čtyři složky – x, y, z a váhu w.

5. Kladné váhy řídících bodů

Pokud je váha řídící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í řídících bodů, nebo použitím násobných řídících bodů.

Obě zmíněné techniky však vedou k nárustu dat (tj. samotných řídících bodů) a ke komplikované editaci ploch. Proto je změna vah řídící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 na čtvrtém a pátém ilustračním obrázku.

Extrémní případ nastane, pokud je váha řídící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 řídících bodů.

Obrázek 4: NURB plocha, u které mají všechny řídící body jednotkovou váhu
Obrázek 4: NURB plocha, u které mají všechny řídící body jednotkovou váhu

Obrázek 5: NURB plocha, u které mají některé řídící body váhu zvětšenou
Obrázek 5: NURB plocha, u které mají některé řídící body váhu zvětšenou

6. Záporné a nulové váhy řídících bodů

Váhy řídící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 řídící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 od něj není odpuzována. Na první pohled by se mohlo zdát, že zadávat řídící 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 řídící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 řídících bodů bez vynechaných míst.

7. Konvexní obálka NURB plochy a její význam

Pokud mají všechny řídící 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é NURB plochu těsně 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.).

8. Demonstrační příklady

Po spuštění prvního demonstračního příkladu se zobrazí osvětlená NURB plocha specifikovaná pomocí 36 řídících bodů uspořádaných do matice 6×6 bodů. Spolu s řídícími body jsou specifikovány i uzlové vektory, které tvoří bázi pro B-spline plochu. Pro ilustraci jsou znázorněny i řídící 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.

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

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

Screenshot třetího demonstračního příkladu
Obrázek 8: Screenshot třetího demonstračního příkladu

ict ve školství 24

9. Obsah dalšího pokračování

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é z NURB ploch.

10. Seznam funkcí OpenGL, GLU a GLUT zmíněných v této části

gluBeginSurface()
gluNurbsSurface()
gluEndSurface()
 

11. 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.

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.