Obsah
1. Implementace algoritmu Fractal Flame
2. Nelineární funkce – variace
3. Logaritmická závislost při výpočtu plošného histogramu
4. Monochromatické obrázky
5. Vícebarevné obrázky
6. Funkce pro překreslení fraktálu
7. Popis demonstračního příkladu určeného pro vykreslování algoritmem Fractal Flame
8. Obsah dalšího pokračování tohoto seriálu
1. Implementace algoritmu Fractal Flame
V předchozím pokračování tohoto seriálu jsme si uvedli teoretické informace o velmi úspěšném algoritmu Fractal Flame. Již tedy víme, že se ve své podstatě jedná o generalizaci „klasických“ systémů iterovaných funkcí Michaela Barnsleye. Vlastní princip generování obrázku však zůstal zachován – stále se používá chaotická hra (Chaos Game) neboli algoritmus náhodné procházky (RWA – Random Walk Algorithm), i když i zde došlo k několika rozšířením. Dnes na teoretický úvod navážeme a ukážeme si praktickou implementaci některých částí algoritmu Fractal Flame. Předesílám, že dále implementované algoritmy jsou mé vlastní, a z tohoto důvodu zcela přesně neodpovídají algoritmům použitým například v aplikaci Apophysis. V případě zájmu o originální algoritmy je dobré nejprve pročíst článek od Scotta Dravese (http://flam3.com/flame_draves.pdf) a posléze navštívit další stránky, například http://flam3.com/ a http://www.apophysis.org/.
Obrázek 1: Fraktál vytvořený Scottem Dravesem pomocí algoritmu Fractal Flame
2. Nelineární funkce – variace
Nejvýraznějším rozdílem mezi klasickými systémy iterovaných funkcí IFS a fraktály typu Fractal Flame je kombinace lineárních a nelineárních funkcí pro každou transformaci. V následující tabulce jsou zobrazeny všechny nelineární funkce navržené Scottem Dravesem, které jsou používány (spolu s lineárními transformacemi) pro výpočet nových souřadnic bodů:
Označení funkce | Výrazy pro výpočet souřadnic | Originální název |
---|---|---|
V0(x,y) | (x,y) | linear |
V1(x,y) | (sin x, sin y) | sinusoidal |
V2(x,y) | (x/r2, y/r2) | spherical |
V3(x,y) | (r×cos(φ+r), r×sin(φ+r)) | swirl |
V4(x,y) | (r×cos(2φ), r×sin(2φ)) | horseshoe |
V5(x,y) | (φ/π, r-1) | polar |
V6(x,y) | (r×sin(φ+r), r×cos(φ-r)) | handkerchief |
V7(x,y) | (r×sin(φr), -r×cos(φr)) | heart |
V8(x,y) | (φ×sin(πr)/π, φcos(πr)/π) | disc |
V9(x,y) | ((cos φ+sin r)/r, (sin φ-cos r)/r) | spiral |
V10(x,y) | ((sin φ)/r, (cos φ)r) | hyperbolic |
V11(x,y) | ((sin φ)(cos r), (cos φ)(sin r)) | diamond |
V12(x,y) | (r×sin3(φ+r), r×cos3(φ-r)) | ex |
V13(x,y) | (r1/2×cos(φ/2+Ω), r1/2×sin(φ/2+Ω)) | julia |
V16(x,y) | (2r/(r+1)x, 2r/(r+1)y) | fisheye |
V20(x,y) | (cos(πx)×cosh(y), -sin(πx)×sinh(y)) | cosine |
V programovacím jazyku C jsou vytvořeny dvě funkce nazvané jednoduše vx() a vy(). Každá z těchto funkcí akceptuje tři parametry. Prvním parametrem je číslo variace, tj. celočíselná hodnota v rozsahu 0..20. Druhým a třetím parametrem je poloha bodu Xn v rovině, tj. jeho souřadnice x a y. Funkce vx() vrátí x-ovou polohu nového bodu Xn+1, zatímco funkce vy() vrátí jeho y-ovou souřadnici. Implementace obou zmiňovaných funkcí je poměrně jednoduchá (všimněte si výpočtu pomocných hodnot na začátcích obou funkcí):
//-----------------------------------------------------------------------------
// Výpočet x-ové souřadnice pomocí funkce Vn()
//-----------------------------------------------------------------------------
double vx(int type, double x, double y)
{
double r=sqrt(x*x+y*y); // vzdálenost od počátku
double phi=atan2(y,x); // úhel od x-ové osy
double result;
switch (type) {
case 0: // linear
result=x;
break;
case 1: // sinusoidal
result=sin(x);
break;
case 2: // spherical
result=x/(r*r);
break;
case 3: // swirl
result=r*cos(phi+r);
break;
case 4: // horseshoe
result=r*cos(2*phi);
break;
case 5: // polar
result=phi/M_PI;
break;
case 6: // handkerchief
result=r*sin(phi+r);
break;
case 7: // heart
result=r*sin(phi*r);
break;
case 8: // disc
result=phi*sin(M_PI*r)/M_PI;
break;
case 9: // spiral
result=(cos(phi)+sin(r))/r;
break;
case 10: // hyperbolic
result=sin(phi)/r;
break;
case 11: // diamond
result=sin(phi)*cos(r);
break;
case 12: // ex
result=r*pow(sin(phi+r),3);
break;
case 13: // Julia
result=sqrt(r)*cos(phi/2);
break;
case 16: // fisheye
result=2*r/((r+1)*x);
break;
case 20: // cosine
result=cos(M_PI*x)*cosh(y);
break;
default:
result=x;
break;
};
return result;
}
//-----------------------------------------------------------------------------
// Výpočet y-ové souřadnice pomocí funkce Vn()
//-----------------------------------------------------------------------------
double vy(int type, double x, double y)
{
double r=sqrt(x*x+y*y); // vzdálenost od počátku
double phi=atan2(y,x); // úhel od x-ové osy
double result;
switch (type) {
case 0: // linear
result=y;
break;
case 1: // sinusoidal
result=sin(y);
break;
case 2: // spherical
result=y/(r*r);
break;
case 3: // swirl
result=r*sin(phi+r);
break;
case 4: // horseshoe
result=r*sin(2*phi);
break;
case 5: // polar
result=r-1;
break;
case 6: // handkerchief
result=r*cos(phi-r);
break;
case 7: // heart
result=-r*cos(phi*r);
break;
case 8: // disc
result=phi*cos(M_PI*r)/M_PI;
break;
case 9: // spiral
result=(sin(phi)-cos(r))/r;
break;
case 10: // hyperbolic
result=cos(phi)/r;
break;
case 11: // diamond
result=cos(phi)*sin(r);
break;
case 12: // ex
result=r*pow(cos(phi-r),3);
break;
case 13: // Julia
result=sqrt(r)*sin(phi/2);
break;
case 16: // fisheye
result=2*r/((r+1)*y);
break;
case 20: // cosine
result=-sin(M_PI*x)*sinh(y);
break;
default:
result=y;
break;
};
return result;
}
Obrázek 2: Další fraktál vytvořený Scottem Dravesem pomocí algoritmu Fractal Flame
3. Logaritmická závislost při výpočtu plošného histogramu
Pro dosažení zdánlivého trojrozměrného vzhledu obrázků je důležitá změna lineární závislosti při výpočtu barev pixelů v plošném histogramu na závislost logaritmickou. Samotný výpočet histogramu je velmi jednoduchý – v dvourozměrném poli jsou uchovávány hodnoty čítačů příslušejících jednotlivým pixelům. Při každém „zásahu“ pixelu je čítač zvýšen o jedničku. V následujících dvou kapitolách jsou ukázány implementace algoritmů pro výpočet barev v monochromatických obrázcích i obrázcích vícebarevných.
Obrázek 3: Fraktál vytvořený ve známém grafickém editoru GIMP za pomoci filtru GFlare
4. Monochromatické obrázky
Práce s monochromatickými obrázky je poměrně jednoduchá. Pixely se přímo nezapisují do pixmapy určené pro vykreslování, ale do pomocného pole obsahujícího položky typu float. Toto pole uchovává hodnoty čítačů, ve kterých se mění hodnota po zavolání funkce addfloat(). Tato funkce má tvar:
//-----------------------------------------------------------------------------
// Přírůstek barvy pixelu na zadaných souřadnicích ve floatové monochromatické
// pixmapě
//-----------------------------------------------------------------------------
void addfloat(const unsigned int x, const unsigned int y)
{
// kontrola, zda není překročena velikost pixmapy
// (záporné hodnoty není díky převodu na unsigned int zapotřebí
// brát v potaz)
if (x>=PIXMAP_WIDTH || y>=PIXMAP_HEIGHT) return;
// zvýšit hodnotu čítače
floatMap[y][x]++;
}
Po vygenerování zadaného počtu bodů se na základě hodnot uložených v jednotlivých čítačích vybere hodnota maximální a následně se provede logaritmování a převod hodnot do rozsahu 0..255; tyto hodnoty se již mohou zapsat do cílové pixmapy, která je určena pro vykreslení na obrazovce pomocí příkazů grafické knihovny OpenGL. Funkce provádějící všechny převody mezi oběma typy pixmap vypadá následovně:
//-----------------------------------------------------------------------------
// Kopie pixelu z floatové pixmapy do pixmapy kompatibilní s OpenGL spolu
// s logaritmickým převodem měřítka
//-----------------------------------------------------------------------------
void convertFloatMap(void)
{
float maxp=0;
float pixelFactor; // faktor konverze
int i, j; // čítače smyček
for (j=0; j<PIXMAP_HEIGHT; j++) // zjistit maximální hodnotu uloženou
for (i=0; i<PIXMAP_WIDTH; i++) // ve floatové pixmapě
if (maxp<floatMap[j][i]) maxp=floatMap[j][i];
pixelFactor=255.0/log(maxp); // vypočítat faktor konverze
for (j=0; j<PIXMAP_HEIGHT; j++) { // konverze a změna na logaritmické měřítko
for (i=0; i<PIXMAP_WIDTH; i++) { // s tím, že výsledné barvové složky jsou
float pixel=log(floatMap[j][i])*pixelFactor; // v rozsahu 0..255
putpixel(pixFractalFlame, i, j, (int)pixel, (int)pixel, (int)pixel);
}
}
}
Obrázek 4: Monochromatický fraktál vytvořený ve známém grafickém editoru GIMP za pomoci filtru GFlare
5. Vícebarevné obrázky
Vícebarevné obrázky se od obrázků monochromatických liší pouze tím, že místo jednoho barevného kanálu obsahují kanály tři; pro každou základní barvovou složku jeden. Z toho důvodu se nepatrně pozmění jak funkce pro zápis „zásahu“ jednoho pixelu, tak i funkce provádějící převod na logaritmické měřítko. Na rozdíl od Scotta Dravese ve svých funkcích každou barvovou složku převádím zvlášť, originální algoritmy používaly pouze jeden faktor konverze. Funkce, která je zavolána pro zápis „zásahu“ pixelu, má následující tvar:
//-----------------------------------------------------------------------------
// Přírůstek barvy pixelu na zadaných souřadnicích ve floatové pixmapě
// typu RGB
//-----------------------------------------------------------------------------
void addfloatRGB(const unsigned int x, const unsigned int y, int r, int g, int b)
{
// kontrola, zda není překročena velikost pixmapy
// (záporné hodnoty není díky převodu na unsigned int zapotřebí
// brát v potaz)
if (x>=PIXMAP_WIDTH || y>=PIXMAP_HEIGHT) return;
// zvýšit hodnotu všech tří čítačů
floatMapRGB[y][x][0]+=r;
floatMapRGB[y][x][1]+=g;
floatMapRGB[y][x][2]+=b;
}
V parametrech r, g a b jsou předány přírůstky, které se mají přičíst k hodnotám uloženým v jednotlivých čítačích. Pro většinu IFS systémů je vhodné hodnoty zvyšovat o jednotku, tj. všechny zmiňované parametry budou rovny r=g=b=1. V některých případech však může být vhodné některou barvovou složku více zvýraznit a nastavit například parametr r na trojku. Funkce pro přepočet hodnot z původní pixmapy do pixmapy vhodné pro vykreslení, je také složitější, neboť místo jedné hodnoty platné pro daný pixel se vždy počítá s vektorem tří hodnot. Tomu také odpovídají použité datové typy a vložené smyčky:
//-----------------------------------------------------------------------------
// Kopie pixelů v pixmapě tak, aby se změnila lineární závislost mezi počtem
// zásahů pixelů na závislost logaritmickou
//-----------------------------------------------------------------------------
void convertFloatMapRGB(void)
{
float max[3]={0, 0, 0}; // vektor maximálních hodnot
float factor[3]; // vektor konverzních faktorů
int i, j, k;
for (j=0; j<PIXMAP_HEIGHT; j++) // zjistit maximální hodnoty uložené
for (i=0; i<PIXMAP_WIDTH; i++) // ve floatové pixmapě
for (k=0; k<3; k++)
if (max[k]<floatMapRGB[j][i][k]) max[k]=floatMapRGB[j][i][k];
for (k=0; k<3; k++) // vypočítat vektor faktorů konverze
factor[k]=255.0/log(max[k]);
for (j=0; j<PIXMAP_HEIGHT; j++) { // převod pixmapy
for (i=0; i<PIXMAP_WIDTH; i++) {
float pixel[3];
for (k=0; k<3; k++)
pixel[k]=log(floatMapRGB[j][i][k])*factor[k];
putpixel(pixFractalFlame, i, j, (int)pixel[0], (int)pixel[1], (int)pixel[2]);
}
}
}
Obrázek 5: Trojice fraktálů typu Fractals Flames vytvořená v grafickém editoru GIMP (sloučení provedeno pomocí vrstev)
6. Funkce pro překreslení fraktálu
Funkce, která provádí překreslení fraktálu podle algoritmu „Fractal Flames“, využívá všechny výše zmíněné céčkovské funkce. Každý systém iterovaných funkcí je pro jednoduchost popsán polem, přičemž každý řádek pole obsahuje informace o jedné transformaci (počet transformací je vždy roven třem, je však možné provést rozšíření na větší či naopak menší počet transformací). Každá transformace je popsána sedmisložkovým vektorem; úvodní šestice složek popisuje lineární transformaci:
(xn+1, yn+1)=(aixn+biyn+ci, dixn+eiyn+fi)
zatímco v poslední složce vektoru je uložen index nelineární transformace (variace), která rozšiřuje výše uvedenou transformaci lineární:
(xn+1, yn+1)=(aixn+biyn+ci, dixn+eiyn+fi)
Přepočet vypadá následovně:
//-----------------------------------------------------------------------------
// Překreslení fraktálu typu FractalFlame
//-----------------------------------------------------------------------------
void recalcFractalFlame( pixmap *pix, // pixmapa pro vykreslování
int maxiter, // maximální počet iterací
double scale, // měřítko obrazce
double xpos, // posun obrazce
double ypos,
int type, // vybraný IFS systém
int rf, int gf, int bf, // příznaky barvových složek
int dr, int dg, int db, // přírustky barvových složek
DrawType drawType) // způsob vykreslení IFS systému
{
int iter=0; // počitadlo iterací
int threshold=50; // hranice počtu iterací pro vykreslování
double x, y; // poloha iterovaného bodu
double xn, yn; // nová poloha iterovaného bodu
int k; // číslo vybraného řídicího bodu
unsigned char red=rf ? dr : 0; // reálné přírůstky barvových složek
unsigned char green=gf ? dg : 0;
unsigned char blue=bf ? db : 0;
double coefs[][3][7]={ // koeficienty jednotlivých transformací
{
{ 0.500000, 0.0000000, 0.000000, 0.5000000, 0.000000, 0.000000, 2},
{ 0.500000, 0.0000000, 0.000000, 0.5000000, 0.000000, 1.000000, 0},
{ 0.500000, 0.0000000, 0.000000, 0.5000000, 1.000000, 1.000000, 0}
},
{
{ 0.983960, 0.2983280, 0.359416, -0.5835410, -0.850590, -0.378754, 0},
{-0.900388, 0.2930630, 0.397598, 0.0225629, 0.465126, -0.277212, 9},
{-0.329863, -0.0855261, -0.369381, -0.8583790, 0.977861, 0.547595, 3},
},
{
{ 0.562482, 0.3978610, -0.539599, 0.5010880, -0.429920, -0.112404, 2},
{ 0.830039, -0.4961740, 0.162480, 0.7504680, 0.910220, 0.288389, 2},
{ 1.000000, 0.0000000, 0.000000, 1.0000000, 0.000000, 0.000000, 0},
},
{
{ 0.983960, 0.2983280, 0.359416, -0.5835410, -0.850590, -0.378754, 2},
{ 0.830039, -0.4961740, 0.162480, 0.7504680, 0.910220, 0.288389, 2},
{ 0.500000, 0.0000000, 0.000000, 0.5000000, 1.000000, 1.000000, 0}
},
{
{ 0.983960, 0.2983280, 0.359416, -0.5835410, -0.850590, -0.378754, 3},
{ 0.830039, -0.4961740, 0.162480, 0.7504680, 0.910220, 0.288389, 3},
{ 0.500000, 0.0000000, 0.000000, 0.5000000, 1.000000, 1.000000, 3}
},
{
{ 0.500000, -0.4000000, 0.000000, 0.5000000, 0.000000, 0.000000, 20},
{ 0.500000, 0.1000000, 0.000000, 0.5000000, 0.000000, 0.300000, 3},
{ 0.500000, 0.0000000, 0.100000, 0.4000000, 0.500000, 1.000000, 5}
},
{
{ 0.983960, 0.2983280, 0.359416, -0.5835410, -0.850590, -0.378754, 1},
{-0.900388, 0.2930630, 0.397598, 0.0225629, 0.465126, -0.277212, 2},
{-0.329863, -0.0855261, -0.369381, -0.8583790, 0.977861, 0.547595, 3}
},
{
{ 0.983960, 0.2983280, 0.359416, -0.5835410, -0.850590, -0.378754, 4},
{-0.900388, 0.2930630, 0.397598, 0.0225629, 0.465126, -0.277212, 5},
{-0.329863, -0.0855261, -0.369381, -0.8583790, 0.977861, 0.547595, 6}
},
{
{ 0.983960, 0.2983280, 0.359416, -0.5835410, -0.850590, -0.378754, 7},
{-0.900388, 0.2930630, 0.397598, 0.0225629, 0.465126, -0.277212, 8},
{-0.329863, -0.0855261, -0.369381, -0.8583790, 0.977861, 0.547595, 9}
},
{
{ 0.983960, 0.2983280, 0.359416, -0.5835410, -0.850590, -0.378754, 10},
{-0.900388, 0.2930630, 0.397598, 0.0225629, 0.465126, -0.277212, 11},
{-0.329863, -0.0855261, -0.369381, -0.8583790, 0.977861, 0.547595, 12}
},
};
unsigned char pal[8][3]={ // barvová paleta
{0xff, 0x00, 0x00},
{0x00, 0xff, 0x00},
{0x00, 0x00, 0xff},
{0xff, 0xff, 0x00},
{0x00, 0xff, 0xff},
{0xff, 0x00, 0xff},
{0xff, 0xff, 0xff},
{0x80, 0x80, 0x80},
};
x=0;
y=0; // nastavení počáteční polohy bodu
srand(0); // v rovině
while (iter++<maxiter*100) { // iterační smyčka
k=rand()%3; // zvolit jednu ze tří transformací
xn=x*coefs[type][k][0]+y*coefs[type][k][2]+coefs[type][k][4]; // aplikovat lineární
yn=x*coefs[type][k][1]+y*coefs[type][k][3]+coefs[type][k][5]; // transformaci
x=vx((int)coefs[type][k][6], xn, yn); // aplikovat nelineární transformaci
y=vy((int)coefs[type][k][6], xn, yn);
if (iter>threshold) { // je-li dosaženo hranice iterací
double xx=x*scale+xpos;
double yy=y*scale+ypos;
switch (drawType) { // výběr vykreslovacího režimu
case IterPutPixel:
putpixel(pix, xx, yy, rf ? 0xff:0x00, gf ? 0xff:0x00, bf ? 0xff:0x00);
break;
case IterAddPixel:
addpixel(pix, xx, yy, red, green, blue);
break;
case IterLogPixel:
addfloat(xx, yy);
break;
case TransfPutPixel:
putpixel(pix, xx, yy, pal[k&7][0], pal[k&7][1], pal[k&7][2]);
break;
case TransfAddPixel:
addpixel(pix, xx, yy, (!!pal[k&7][0])*dr, (!!pal[k&7][1])*dg, (!!pal[k&7][2])*db);
break;
case TransfLogPixel:
addfloatRGB(xx, yy, (!!pal[k&7][0]), (!!pal[k&7][1]), (!!pal[k&7][2]));
break;
default:
break;
}
}
x=xn;
y=yn;
}
// u logaritmických převodů provést finální konverzi pixmap
if (drawType==IterLogPixel) convertFloatMap();
if (drawType==TransfLogPixel) convertFloatMap2();
}
Obrázek 6: Obrázek vytvořený za pomoci dnešního demonstračního příkladu (po inverzi)
7. Popis demonstračního příkladu určeného pro vykreslování algoritmem Fractal Flame
Všechny výše uvedené funkce jsou implementovány v dnešním demonstračním příkladu. Po překladu a spuštění tohoto demonstračního příkladu se zobrazí první obrázek vytvořený pomocí algoritmu „Fractal Flame“, který má rozlišení 512×384 pixelů. Pomocí klávesnice (viz tabulka s popisem ovládání) je možné měnit lineární a nelineární funkce, pomocí nichž je obraz IFS systému definován. Také je možné měnit způsob vybarvení jednotlivých pixelů, maximální počet iterací, přírůstky barvových složek atd. Na sedmém obrázku je zobrazen screenshot spuštěného demonstračního příkladu. S demonstračním příkladem je možné laborovat i změnou koeficientů lineárních a nelineárních transformací, které jsou uloženy v poli coefs ve funkci recalcFractalFlame(). Nejjednodušší a nejvýraznější je změna posledního koeficientu, který určuje typ nelineární transformace, tj. funkci variace.
Obrázek 7: Screenshot demonstračního příkladu
Ovládání dnešního demonstračního příkladu pomocí klávesnice je sepsáno v následující tabulce:
Klávesová zkratka | Význam klávesové zkratky |
---|---|
F1 | výběr vykreslovací metody s konstantní barvou (IterPutPixel) |
F2 | výběr vykreslovací metody s plošným histogramem (IterAddPixel) |
F3 | výběr vykreslovací metody s plošným histogramem s logaritmickou charakteristikou (IterLogPixel) |
F4 | výběr vykreslovací metody s barvou pixelů závisející na transformaci (TransfPutPixel) |
F5 | výběr vykreslovací metody kombinující plošný histogram s barvou transformace (TransfAddPixel) |
F6 | výběr vykreslovací metody kombinující plošný histogram s barvou transformace, ale s logaritmickou závislostí (TransfLogPixel) |
F7 | snížení změny červené barvové složky při tvorbě plošného histogramu |
F8 | zvýšení změny červené barvové složky při tvorbě plošného histogramu |
F9 | snížení změny zelené barvové složky při tvorbě plošného histogramu |
F10 | zvýšení změny zelené barvové složky při tvorbě plošného histogramu |
F11 | snížení změny modré barvové složky při tvorbě plošného histogramu |
F12 | zvýšení změny modré barvové složky při tvorbě plošného histogramu |
S | uložení rastrového obrázku s fraktálem do externího souboru |
Q | ukončení demonstračního příkladu |
Esc | ukončení demonstračního příkladu |
, | snížení maximálního počtu iterací o hodnotu 1000 |
. | zvýšení maximálního počtu iterací o hodnotu 1000 |
< | snížení maximálního počtu iterací o hodnotu 10000 |
> | zvýšení maximálního počtu iterací o hodnotu 10000 |
R | povolení/zákaz použití červené barvové složky při vykreslování |
G | povolení/zákaz použití zelené barvové složky při vykreslování |
B | povolení/zákaz použití modré barvové složky při vykreslování |
← | posun obrazce s fraktálem o pět pixelů doleva |
→ | posun obrazce s fraktálem o pět pixelů doprava |
↑ | posun obrazce s fraktálem o pět pixelů nahoru |
↓ | posun obrazce s fraktálem o pět pixelů dolů |
Page ↑ | změna měřítka obrazce o 10% (zvětšení) |
Page ↓ | změna měřítka obrazce o 10% (zmenšení) |
0 | výběr první sady transformací IFS systému |
1 | výběr druhé sady transformací IFS systému |
2 | výběr třetí sady transformací IFS systému |
3 | výběr čtvrté sady transformací IFS systému |
4 | výběr páté sady transformací IFS systému |
5 | výběr šesté sady transformací IFS systému |
6 | výběr sedmé sady transformací IFS systému |
7 | výběr osmé sady transformací IFS systému |
8 | výběr deváté sady transformací IFS systému |
9 | výběr desáté sady transformací IFS systému |
Obrázek 8: Další obrázek vytvořený za pomoci dnešního demonstračního příkladu (po inverzi)
8. Obsah dalšího pokračování tohoto seriálu
V následujícím pokračování tohoto seriálu dokončíme poměrně rozsáhlou část věnovanou systémům iterovaných funkcí (IFS) a jejich modifikacím, tj. linearizovaným IFS a algoritmu Fractal Flame. Příště si ukážeme, jakým způsobem je možné vytvářet trojrozměrné modely těles pomocí systémů iterovaných funkcí IFS. V jednom z demonstračních příkladů také budeme vytvářet trojrozměrné scény určené pro známý raytracer POV-Ray.
Obrázek 9: Téma příštího pokračování – trojrozměrné IFS