Hlavní navigace

Fraktály v počítačové grafice IX

21. 12. 2005
Doba čtení: 10 minut

Sdílet

V deváté části seriálu o fraktálech používaných (nejenom) v počítačové grafice se budeme zabývat dynamickými systémy, jejichž orbity nejsou vykreslovány v rovině, ale v třírozměrném prostoru. Mezi tyto systémy patří především známý Lorenzův a Rosslerův atraktor, jejichž výpočet a následné vykreslení si ukážeme na demonstračních příkladech.

Obsah

1. Lorenzův atraktor podruhé
2. První modifikace Lorenzova atraktoru
3. Druhá modifikace Lorenzova atraktoru
4. Třetí modifikace Lorenzova atraktoru
5. Rosslerův atraktor
6. Obsah dalšího pokračování tohoto seriálu

1. Lorenzův atraktor podruhé

Lorenzův atraktor jsme si teoreticky popsali již v šesté části tohoto seriálu, procedura pro jeho vykreslení však ještě nebyla uvedena, protože se jedná o systém zobrazovaný v třírozměrném prostoru pomocí polyčar a většina předchozích příkladů byla zaměřena spíše na vykreslování bodů v rovině či 3D prostoru. Vzhledem k tomu, že jednotlivé body umístěné na orbitu Lorenzova atraktoru mohou být od sebe značně vzdálené (zejména při bližším přiblížení pozorovatele k atraktoru nebo při „vhodném“ zadání počátečních podmínek), jsou vždy dva po sobě vypočtené body při vykreslení propojeny úsečkou. V následujícím úryvku kódu je ukázán velmi jednoduchý a přímočarý způsob vykreslení Lorenzova atraktoru pomocí funkcí poskytovaných grafickou knihovnou OpenGL, jež podporují vykreslení libovolně dlouhé lomené čáry (polyčáry). V kódu se vychází z trojice vztahů pro iterativní výpočet pozic bodůPn=[xn, yn, zn] rozmístěných v prostoru:

xn+1 = xn + (-a × xn × dt) + (a × yn × dt)

yn+1 = yn + (b × xn × dt) – (yn × dt) – (zn × xn × dt)

zn+1 = zn + (-c × zn × dt) + (xn × yn × dt)

Původní diferenciální rovnice pro Lorenzův atraktor měly před svým převodem do diskrétní podoby tvar:

dx/dt = -ax+ay
dy/dt = bx-y-zx
dz/dt = -cz+xy

//-----------------------------------------------------------------------------
// Překreslení Lorenzova atraktoru v prostoru (původní Lorenzův atraktor)
//-----------------------------------------------------------------------------
void recalcLorenz(    double a,                 // parametry fraktálu
                      double b,
                      double c,
                      double dt,                // použito při numerické integraci
                      int    maxiter,           // maximální počet iterací
                      double scale)             // měřítko obrazce
{
    double x=0.1, y=0, z=0;                     // pozice bodu v prostoru
    double x2, y2, z2;
    int iter=maxiter;

    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_LINE_STRIP);                     // začátek vykreslování polyčáry
    while (iter--) {                            // iterační smyčka
        glColor3f(x/10.0,y/10.0,z/10.0);
        x2 = x+(-a*x*dt)+(a*y*dt);
        y2 = y+(b*x*dt)-(y*dt)-(z*x*dt);
        z2 = z+(-c*z*dt)+(x*y*dt);
        x=x2;                                   // přepis nových souřadnic
        y=y2;
        z=z2;
        glVertex3d(x*scale, y*scale, z*scale);  // vykreslení úsečky
    }
    glEnd();                                    // konec vykreslování polyčáry
} 
Fraktály 09 - 1

Obrázek 1: První varianta originálního Lorenzova atraktoru

Zdrojový kód demonstračního příkladu určeného pro vykreslení Lorenzova atraktoru je uložený ke stažení, HTML verze se zvýrazněním syntaxe je také dostupná. Při překladu a následném spuštění prvního demonstračního příkladu je možné měnit pohled na atraktor pomocí myši. Při stlačení levého tlačítka myši se atraktorem rotuje (zhruba) ve směru pohybu myši, při stlačení pravého tlačítka se atraktor přibližuje ke kameře (pozorovateli), nebo se od něj naopak vzdaluje (entity, které se nachází blízko ke kameře, jsou ořezány). Pomocí kláves [1][6] se mění vstupní parametry dynamického systému a, b, c, klávesami[7] a [8] je možné upravit hodnotu kroku dt. Čím menší je hodnota kroku, tím kratší jsou vykreslované úsečky a tím přesněji je atraktor vykreslován. Na druhou stranu se spolu se zmenšováním kroku musí zvětšovat počet iterací, protože je vykreslována menší část atraktoru. Klávesou [Esc] nebo [Q] se popisovaná demonstrační aplikace ukončí.

Fraktály 09 - 2

Obrázek 2: Druhá varianta originálního Lorenzova atraktoru

Fraktály 09 - 3

Obrázek 3: Třetí varianta originálního Lorenzova atraktoru

2. První modifikace Lorenzova atraktoru

Při použití původních rovnic pro Lorenzův atraktor je vykreslen obrazec, ve kterém jsou patrné dvě charakteristické smyčky, přičemž dráha počítaných bodů chaoticky mezi oběma smyčkami přeskakuje. Autoři Rick Miranda a Emily Stone vytvořili několik modifikací původních rovnic Lorenzova atraktoru tak, aby se při jejich aplikaci vytvořily obrazce s obecně různým počtem smyček. Při použití následující trojice modifikovaných rovnic se vytvoří atraktor, ve kterém je patrná pouze jedna smyčka:

xn+1 = xn + (-a × dt-dt) × xn+(a × dt – b × dt) × yn + (dt-a × dt) × norm + yn × dt × zn

yn+1 = yn + (b × dt-a × dt) × xn – (a × dt+dt) × yn + (b × dt+a × dt) × norm-xn × dt × zn – norm × zn × dt

zn+1 = zn + yn × dt/2.0 – c × dt × zn

Pomocná proměnná norm se vypočte z hodnot xn a yn:

norm = sqrt(xn2 + yn2)

Procedura, která využívá výše zmíněné vztahy, bude v céčku vypadat následovně:

//-----------------------------------------------------------------------------
// Překreslení modifikovaného Lorenzova atraktoru (první modifikace)
//-----------------------------------------------------------------------------
void recalcLorenz2(   double a,                 // parametry fraktálu
                      double b,
                      double c,
                      double dt,                // použito při numerické integraci
                      int    maxiter,           // maximální počet iterací
                      double scale)             // měřítko obrazce
{
    double x=1.0, y=1.0, z=1.0;                 // počáteční pozice bodu
    double x2, y2, z2;                          // v prostoru
    double norm;
    int iter=maxiter;

    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_LINE_STRIP);                     // začátek vykreslování polyčáry
    while (iter--) {                            // iterační smyčka
        glColor3f(x/10.0,y/10.0,z/10.0);
        norm=sqrt(x*x+y*y);                     // výpočet pomocné proměnné
        x2 = x+(-a*dt-dt)*x+(a*dt-b*dt)*y+(dt-a*dt)*norm+y*dt*z;
        y2 = y+(b*dt-a*dt)*x-(a*dt+dt)*y+(b*dt+a*dt)*norm-x*dt*z-norm*z*dt;
        z2 = z+y*dt/2.0-c*dt*z;
        x=x2;                                   // přepis nových souřadnic
        y=y2;
        z=z2;
        glVertex3d(x*scale, y*scale, z*scale);  // vykreslení úsečky
    }
    glEnd();                                    // konec vykreslování polyčáry
} 
Fraktály 09 - 4

Obrázek 4: První varianta modifikovaného Lorenzova atraktoru

Procedura recalcLorenz2() je použita ve druhém demonstračním příkladu, jehož zdrojový kód je uložen ke stažení, popř.  jako HTML verze se zvýrazněnou syntaxí. Ovládání tohoto demonstračního příkladu je obdobné prvnímu demonstračnímu příkladu, tj. myš slouží k otáčení atraktoru a jeho přibližování či vzdalování od pozorovatele, klávesami [1][8] se mění parametry dynamického systému a klávesy [Esc] a[Q] aplikaci ukončí.

Fraktály 09 - 5

Obrázek 5: Druhá varianta modifikovaného Lorenzova atraktoru

3. Druhá modifikace Lorenzova atraktoru

Druhá modifikace Lorenzova atraktoru vytváří při vykreslení orbitů obrazec, ve kterém jsou patrné tři smyčky. Autoři této modifikace jsou opět Rick Miranda a Emily Stone. Modifikované rovnice pro výpočet bodů na orbitu mají tvar:

xn+1 = xn + (-(a × dt+dt) × xn + (a × dt – b × dt+zn × dt) × yn)/3 + ((dt – a × dt) × (xn2 – yn2) + 2 × (b × dt + a × dt – zn × dt) × xn × yn)/(3 × norm)

yn+1 = yn + ((b × dt-a × dt-zn × dt) × xn – (a × dt+dt) × yn)/3
+ (2 × (a × dt-dt) × xn × yn

+ (b × dt + a × dt – zn × dt) × (xn2 – yn2))/(3 × norm)

zn+1 = zn + (3 × xn × dt × xn × yn – yn × dt × yn2)/2 – c × dt × zn

Pomocná proměnná norm se, podobně jako v předchozím případě, vypočte z hodnot xn a yn:

norm = sqrt(xn2 + yn2)

A výsledná procedura pro výpočet bodů na orbitu má po převedení do céčka tvar:

//-----------------------------------------------------------------------------
// Překreslení modifikovaného Lorenzova atraktoru (druhá modifikace)
//-----------------------------------------------------------------------------
void recalcLorenz3(   double a,                 // parametry fraktálu
                      double b,
                      double c,
                      double dt,                // použito při numerické integraci
                      int    maxiter,           // maximální počet iterací
                      double scale)             // měřítko obrazce
{
    double x=1.0, y=1.0, z=1.0;                 // počáteční pozice bodu
    double x2, y2, z2;                          // v prostoru
    double norm;
    int iter=maxiter;

    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_LINE_STRIP);                     // začátek vykreslování polyčáry
    while (iter--) {                            // iterační smyčka
        glColor3f(x/10.0,y/10.0,z/10.0);
        norm=sqrt(x*x+y*y);
        x2 = x +(-(a*dt+dt)*x + (a*dt-b*dt+z*dt)*y)/3.0
               + ((dt-a*dt)*(x*x-y*y)
               + 2.0*(b*dt+a*dt-z*dt)*x*y)/(3.0*norm);
        y2 = y +((b*dt-a*dt-z*dt)*x - (a*dt+dt)*y)/3.0
               + (2.0*(a*dt-dt)*x*y
               + (b*dt+a*dt-z*dt)*(x*x-y*y))/(3.0*norm);
        z2 = z +(3.0*x*dt*x*y-y*dt*y*y)/2.0 - c*dt*z;
        x=x2;                                   // přepis nových souřadnic
        y=y2;
        z=z2;
        glVertex3d((x+0.35)*scale, (y+1.5)*scale, (z-8.0)*scale); // vykeslení úsečky
    }
    glEnd();                                    // konec vykreslování polyčáry
} 
Fraktály 09 - 6

Obrázek 6: První varianta modifikovaného Lorenzova atraktoru

Procedura recalcLorenz3() je použita ve třetím demonstračním příkladu, k němuž je k dispozici opět jak zdrojový kód, tak i HTML verze se zvýrazněnou syntaxí. Ovládání třetího demonstračního příkladu je totožné s předchozími demonstračními příklady, takže ho zde již nebudu popisovat.

Fraktály 09 - 7

Obrázek 7: Druhá varianta modifikovaného Lorenzova atraktoru

Fraktály 09 - 8

Obrázek 8: Třetí varianta modifikovaného Lorenzova atraktoru

4. Třetí modifikace Lorenzova atraktoru

Třetí a současně poslední modifikace Lorenzova atraktoru vytváří při zobrazení orbitů obrazec, ve kterém jsou patrné čtyři charakteristické smyčky. Modifikované rovnice mají již dosti komplikovaný tvar:

z(0) = y(0) = z(0) = 1
xn+1 = xn +(-a × dt × xn3

+ (2 × a × dt+b × dt-zn × dt) × xn2 × yn + (a × dt-2 × dt) × xn × yn2

+ (zn × dt-b × dt) × yn3) / (2 × (xn2+yn2))

yn+1 = yn +((b × dt-zn × dt) × xn3 + (a × dt-2 × dt) × xn2 × yn

+ (-2 × a × dt-b × dt+zn × dt) × xn × yn2

– a × dt × yn3) / (2 × (xn2+yn2))

zn+1 = zn +(2 × xn × dt × xn2 × yn – 2 × xn × dt × yn3 – c × dt × zn)

A céčkovská implementace těchto rovnic v proceduře určené pro výpočet a vykreslení atraktoru může vypadat následovně:

//-----------------------------------------------------------------------------
// Překreslení modifikovaného Lorenzova atraktoru (třetí modifikace)
//-----------------------------------------------------------------------------
void recalcLorenz4(   double a,                 // parametry fraktálu
                      double b,
                      double c,
                      double dt,                // použito při numerické integraci
                      int    maxiter,           // maximální počet iterací
                      double scale)             // měřítko obrazce
{
    double x=1.0, y=1.0, z=1.0;                 // počáteční pozice bodu
    double x2, y2, z2;                          // v prostoru
    double norm;
    int iter=maxiter;

    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_LINE_STRIP);                     // začátek vykreslování polyčáry
    while (iter--) {                            // iterační smyčka
        glColor3f((x+5.0)/10.0, (y+5.0)/10.0, z/62.0);
        norm=sqrt(x*x+y*y);
        x2= x +(-a*dt*x*x*x
            + (2*a*dt+b*dt-z*dt)*x*x*y + (a*dt-2*dt)*x*y*y
            + (z*dt-b*dt)*y*y*y) / (2 * (x*x+y*y));
        y2 = y +((b*dt-z*dt)*x*x*x + (a*dt-2*dt)*x*x*y
             + (-2*a*dt-b*dt+z*dt)*x*y*y
             - a*dt*y*y*y) / (2 * (x*x+y*y));
        z2= z +(2*x*dt*x*x*y - 2*x*dt*y*y*y - c*dt*z);
        x=x2;                                   // přepis nových souřadnic
        y=y2;
        z=z2;
        glVertex3d((x-0.1)*scale, (y-0.1)*scale, (z-31)*scale);
    }
    glEnd();                                    // konec vykreslování polyčáry
} 
Fraktály 09 - 9

Obrázek 9: První varianta modifikovaného Lorenzova atraktoru

I aplikace třetí modifikace Lorenzova atraktoru je ukázána na demonstračním příkladu (zdrojový kód, HTML verze). Způsob ovládání tohoto demonstračního příkladu se v ničem neliší od předchozích příkladů.

Fraktály 09 - 10

Obrázek 10: Druhá varianta modifikovaného Lorenzova atraktoru

Fraktály 09 - 11

Obrázek 11: Třetí varianta modifikovaného Lorenzova atraktoru

5. Rosslerův atraktor

Dynamický systém s velmi zajímavým atraktorem publikoval lékařOtto Rossler. Jeho dynamický systém je, podobně jako u Lorenzova atraktoru, tvořen trojicí diferenčních rovnic:

xn+1 = xn – yn × dt – zn × dt

yn+1 = yn + xn × dt + a yn × dt
zn+1 = zn + b × dt + xn × zn × dt – c × zn × dt

s počáteční podmínkou x0=y0=z0=1. Atraktor tohoto dynamického systému vytváří v prostoru zajímavý obrazec, který připomíná několik do sebe vložených a ohnutých smyček. Procedura, která provádí přepočet a následné vykreslení Rosslerova atraktoru, vypadá následovně:

//-----------------------------------------------------------------------------
// Překreslení Rosslerova atraktoru v prostoru
//-----------------------------------------------------------------------------
void recalcRossler(   double a,                 // parametry fraktálu
                      double b,
                      double c,
                      double dt,                // použito při numerické integraci
                      int    maxiter,           // maximální počet iterací
                      double scale)             // měřítko obrazce
{
    double x=1.0, y=1.0, z=1.0;                 // pozice bodu v prostoru
    double x2, y2, z2;
    int iter=maxiter;

    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_LINE_STRIP);                     // začátek vykreslování polyčáry
    while (iter--) {                            // iterační smyčka
        glColor3f(x/15.0+(float)iter/maxiter, y/10.0, z/10.0+(float)iter/maxiter/2.0);
        x2 = x-y*dt-z*dt;
        y2 = y+x*dt+a*y*dt;
        z2 = z+b*dt+x*z*dt-c*z*dt;
        x=x2;                                   // přepis nových souřadnic
        y=y2;
        z=z2;
        glVertex3d(x*scale, y*scale, z*scale);  // vykreslení úsečky
    }
    glEnd();                                    // konec vykreslování polyčáry
} 
Fraktály 09 - 12

Obrázek 12: První varianta Rosslerova atraktoru

Zdrojový kód programu provádějícího vykreslení Rosslerova atraktoru je uložen ke stažení, dostupná je i HTML verze se zvýrazněním syntaxe. Tento demonstrační příklad se ovládá naprosto stejným způsobem, jako všechny čtyři předešlé demonstrační příklady.

Fraktály 09 - 13

Obrázek 13: Druhá varianta Rosslerova atraktoru

Fraktály 09 - 14

Obrázek 14: Třetí varianta Rosslerova atraktoru

root_podpora

6. Obsah dalšího pokračování tohoto seriálu

V dalším pokračování tohoto seriálu se budeme zabývat velmi zajímavým tématem – zobrazováním map vybraných dynamických systémů v komplexní rovině. Mezi známé dynamické systémy, se kterými se pracuje v komplexní rovině, patří i Juliovy množiny a k nim příslušnáMandel­brotova množina, kterou je možné považovat za prakticky nejznámější fraktální útvar.

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.