Hlavní navigace

OpenGL evaluátory (3)

25. 5. 2004
Doba čtení: 7 minut

Sdílet

Dnešní pokračování seriálu o OpenGL evaluátorech je věnováno popisu Bézierových ploch, které stále mají velké uplatnění v počítačové grafice, zejména při plátování - pokrývání stěn trojrozměrných těles na sebe navazujícími parametrickými plochami. Při popisu Bézierových ploch se zaměříme zejména na popis Bézierových bikubických plátů, které jsou v OpenGL přímo podporovány.

Obsah

Použití Bézierových ploch
Teorie Bézierových ploch
Navazování Bézierových ploch
Zobrazování Bézierových ploch
Programové zobrazení Bézierova bikubického plátu
Demonstrační příklad
Obsah dalšího pokračování
Seznam funkcí OpenGL zmíněných v této části
Zkomprimovaná verze článku i s přílohami

Použití Bézierových ploch

Pro jednodušší modelovací systémy, kde je prioritou rychlost vykreslování, lze povrch těles reprezentovat pomocí sady Bézierových ploch, které se intuitivně modelují a jsou snadno diferencovatelné, což je důležité zejména pro jejich jednoduché navazování a případné fyzikální simulace. Mezi jejich další výhody patří jednoduchý a rychlý výpočet bodů ležících na ploše, což Bézierovy plochy předurčuje pro použití v aplikacích, kde je důležitá rychlost zobrazování trojrozměrných scén.

Bézierovy (neracionální) plochy však neumožňují přesně modelovat povrch základních kvadrik (mezi něž patří například i koule, elipsoid, válec a kužel), nelze vytvořit offsetovou plochu (offsetová plocha je plocha kopírující v určité vzdálenosti svou tvořicí plochu. Příkladem může být objekt vytvořený z plechu, kde plech by se modeloval právě pomocí dvojice offsetových ploch.) a nejsou invariantní vůči perspektivnímu promítání.

Také podmínky pro hladké navázání jednotlivých plátů mohou být v některých případech poněkud omezující. Mimo jiné i z tohoto důvodu se jako nejjednodušší parametrické plochy pro modelování těles používají Bézierovy bikubické pláty (stupně 3), protože bikvadratické Bézierovy pláty (stupně 2) neposkytují dostatečný stupeň volnosti při modelování. Proto se Bézierovy plochy používají pouze v jednodušších modelovacích systémech, popřípadě v systémech virtuální reality pro vykreslování těles s využitím LOD (Level Of Detail).

Teorie Bézierových ploch

Bézierova plocha nm-tého stupně je určena (n+1)x(m+1) řídícími body Pi, ) a vztahem:

R(t)=\sum_{i=0}^nP_iB_{i}^n(t)

Kde indexy i resp. j probíhají přes intervaly i=0, …, n a j=0, …, m. Bázové funkce Bni(u) a Bmj(v) jsou představovány Bernsteinovými polynomy n-tého resp. m-tého stupně.

Nejpoužívanějším typem těchto ploch jsou v návrhových aplikacích Bézierovy bikubické pláty, u kterých jsou použity Bernsteinovy polynomy třetího stupně. Tyto parametrické plochy jsou zadány pomocí šestnácti řídících bodů, které tvoří mřížku o velikosti 4×4 body. Bernsteinovy polynomy vyšších stupňů lze sice také použít (počet řídících bodů roste kvadraticky se stupněm polynomu), ale zvyšuje se výpočetní složitost a při modelování by mohlo nastat nežádoucí zvlnění (oscilace) jednotlivých plátů. Na prvním obrázku je zobrazeno šestnáct řídících bodů použitých při vytváření Bézierova bikubického plátu.

Obrázek 1: Šestnáct řídících bodů Bézierova bikubického plátu
Obrázek 1: Šestnáct řídících bodů Bézierova bikubického plátu

Na druhém obrázku je zobrazen Bézierův bikubický plát, který je zadaný pomocí šestnácti řídících bodů uspořádaných v mřížce o velikost 4×4 body. Mřížka řídících bodů také tvoří konvexní obal, ve kterém celý plát leží. Tato vlastnost Bézierových ploch je často využívána, například při zobrazování ploch metodou sledování paprsku (raytracing) nebo při testování kolizí dvou těles.

Obrázek 2: Bézierův bikubický plát specifikovaný šestnácti řídícími body
Obrázek 2: Bézierův bikubický plát specifikovaný šestnácti řídícími body

Navazování Bézierových ploch

Při plátování je velmi důležité zajistit hladké napojení jednotlivých Bézierových plátů na sebe. Při napojování plátů se může podle parametrů aplikace požadovat různý stupeň spojitosti. Pokud mají dva pláty společnou alespoň jednu hranu, mají napojení typu C0. Pokud mají dva pláty společnou jednu hranu a současně jsou shodné i parciální derivace ve všech bodech společné hrany, jedná se o napojení typuC1. Někdy je dostačující napojení typu G1, u kterého je zapotřebí zachovat spojitou změnu tečen – tečné vektory musí být kolineární.

U Bézierových bikubických plátů je možné při jejich navazování využít jejich specifických vlastností. Okraje bikubických plátů jsou tvořeny Bézierovými křivkami, jejichž řídící body jsou určeny čtveřicí řídících bodů bikubického plátu. Na samotném plátu také existuje několik dalších Bézierových křivek. Ty jsou určeny vždy čtveřicí řídících bodů, které leží v jedné řadě či v jednom sloupci (tj. mění vždy pouze jeden index řídících bodů):
B1=(P0,0, P0,1, P0,2, P0,3),
B2=(P1,0, P1,1, P1,2, P1,3),
B3=(P2,0, P2,1, P2,2, P2,3),
B4=(P3,0, P3,1, P3,2, P3,3),
B5=(P0,0, P1,0, P2,0, P3,0),
B6=(P0,1, P1,1, P2,1, P3,1),
B7=(P0,2, P1,2, P2,2, P3,2),
B8=(P0,3, P1,3, P2,3, P3,3),

Obrázek 3: Význam okrajů Bézierova bikubického plátu
Obrázek 3: Význam okrajů Bézierova bikubického plátu

Bézierův bikubický plát prochází svými čtyřmi rohovými body, což je naznačeno na čtvrtém obrázku. Pokud je zaručeno, že dva pláty mají společnou hranu, tj. jejich čtyři krajní body jsou totožné, má výsledná plocha spojitost C0 – mezi plochami nejsou mezery ani přesahy. Pokud je zaručena i kolinearita tečných vektorů na okraji ploch (ty jsou zadány vždy dvojicí řídících bodů Px,0-Px,1 nebo P0,y-P1,y), má výsledná plocha spojitostG0, což je pro většinu úloh počítačové graficky dostačující.

Obrázek 4: Krajní body, kterými prochází Bézierův bikubický plát
Obrázek 4: Krajní body, kterými prochází Bézierův bikubický plát

Zobrazování Bézierových ploch

Bézierovy plochy lze zobrazovat například převodem na síť trojúhelníků (TIN) s následným vykreslením této sítě pomocí grafických akcelerátorů. Existují dvě nejpoužívanější metody převodu: polygonizace postupným dosazením hodnot u a v do předchozího vztahu, nebo rekurzivní dělení plátu algoritmem de Casteljau.

Druhá metoda je většinou pro implementaci výhodnější, protože umožňuje provádět adaptivní dělení křivky a při výpočtu se používá celočíselné aritmetiky pouze s operacemi sčítání, odečítání a aritmetickým posunem. U adaptivního dělení je zapotřebí zajistit, aby se sousední pláty rozdělily na stejný počet dílů, jinak může nastat vizuální zlomení plochy vlivem takzvaných T-spojů.

Dalším způsobem, jímž je možné zobrazovat Bézierovy plochy, je použití metody zpětného sledování paprsku (raytracingu), protože je možné numerickými postupy spočítat průsečík paprsku s Bézierovou plochou. Tento způsob, který je použit například v programu POVRay, však není kvůli své časové složitosti a možnosti vzniku viditelných chyb na zobrazované ploše často využíván. My se jím v tomto článku nebudeme dále zabývat.

Evaluátory vytvořené v OpenGL používají pro výpočet křivek a ploch první možnost, tj. postupné dosazování hodnot u a v do vztahu pro Bézierovu plochu a vyčíslení hodnoty Q(u, v). Pokud je grafický procesor (GPU) na grafickém akcelerátoru schopen provádět výpočty poloh bodů na Bézierově křivce či ploše, jedná se o jednu z nejrychlejších možností zobrazení parametrických ploch. Při programové implementaci evaluátorů však mohou nastat situace, ve kterých je výhodnější si napsat vlastní funkce pro výpočet Bézierových křivek či ploch.

Ukázka použití Bézierových ploch s grafickou knihovnou OpenGL je na následujícím obrázku, na kterém je zobrazena čajová konvička vytvořená pomocí několika Bézierových bikubických plátů.

Obrázek 5: Trojrozměrný objekt vytvořený z Bézierových ploch
Obrázek 5: Trojrozměrný objekt vytvořený z Bézierových ploch

Programové zobrazení Bézierova bikubického plátu

Při programovém vykreslení Bézierova bikubického plátu je použita funkce pro výpočet Bernsteinova polynomu třetího řádu. Tuto funkci, kterou jsme si již popsali v minulé části, si zde pro jistotu znovu uvedeme:

//--------------------------------------------------
// Tato funkce provede výpočet Bernsteinova polynomu
// třetího řádu. V parametru "ij" je předán index
// řídícího bodu, který musí nabývat celočíselných
// hodnot 0-3, v parametru "uv" je předána reálná
// hodnota z rozsahu 0.0-1.0.
//--------------------------------------------------
GLfloat B(GLint ij, GLfloat uv)
{
// náhrada složitého výpočtu faktoriálu rozeskokem
    switch (ij) {
      case 0:
          return pow(1.0-uv, 3.0);
      case 1:
          return 3.0*uv*pow(1.0-uv, 2.0);
      case 2:
          return 3.0*uv*uv*(1.0-uv);
      case 3:
          return uv*uv*uv;
      default:
          return 0;
    }
}

S využitím funkce B() je možné napsat program pro výpočet a zobrazení bodů, které leží na Bézierově bikubickém plátu. Pro jednoduchost bude plát zobrazen pouze pomocí bodů, které nejsou navzájem propojeny plochami. Při praktické implementaci by se samozřejmě musela vykreslit plocha celého plátu, přičemž by bylo pro rychlejší vykreslování možné využít například pruhy trojúhelníků, které jsou v grafické knihovně OpenGL také podporovány. Čtyřúhelníky není možné použít, protože nelze zaručit, že všechny jejich vrcholy budou ležet v jedné rovině.

//---------------------------------------------------
// Tato funkce programově vykreslí Bézierův bikubický
// plát. Vstupem je matice o velikosti 4x4 řídící
// body. Tato matice je předána v poli points.
//---------------------------------------------------
void drawBezierSurface(GLfloat points[][4][3])
{
    // počitadla smyček
    int i, j, dim;

    // proměnné představující parametry u a v
    GLfloat u, v;

    // počítané souřadnice řídících bodů
    GLfloat p[3];

    // začátek vykreslování bodů
    glBegin(GL_POINTS);

    // průchod ve směru parametru v
    for (v=0.0f; v<1.0f; v+=0.04f) {
        // průchod ve směru parametru u
        for (u=0.0f; u<1.0f; u+=0.04f) {
            // vyčíslit každou souřadnici bodu
            // P[x, y, z] ležícího na plátu
            for (dim=0; dim<3; dim++) {
                p[dim]=0;
                // výpočet bodu, který leží na
                // Bézierově bikubickém plátu
                for (j=0; j<4; j++) {
                    for (i=0; i<4; i++) {
                        p[dim]+=points[j][i][dim]
                                *B(i, u)
                                *B(j, v);
                    }
                }
            }
            // vykreslení vypočteného bodu
            // do okna aplikace
            glVertex3f(p[0], p[1], p[2]);
        }
    }
    glEnd();
}

Demonstrační příklad

Po úspěšném překladu a spuštění tohoto demonstračního příkladu se vykreslí Bézierova bikubická plocha, která je vypočtena programově, tj. bez použití evaluátorů. Výpočet probíhá ve funkci drawBezierSur­face(). Pohled na Bézierovu plochu je animovaný, animaci lze spustit a zastavit pomocí klávesy S. Klávesou ESC nebo Q 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 velikosti 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.

Obrázek 5: Screenshot prvního demonstračního příkladu
Obrázek 5: Screenshot prvního demonstračního příkladu

UX DAy - tip 2

Obsah dalšího pokračování

V dalším pokračování tohoto seriálu si ukážeme práci s Bézierovými kubickými křivkami s využitím OpenGL evaluátorů. Také si popíšeme význam funkcí glMap1f() a glEvalCoord1f() při vykreslování Bézierových kubických křivek.

Seznam funkcí zmíněných v této části

glBegin()
glEnd()
glVertex2f()
glMap1f()
glEvalCoord1f()
 

Zkomprimovaná verze článku i s přílohami

Zkomprimovaná verze tohoto článku je umístěna zde.

Byl pro vás článek přínosný?

Autor článku

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