niedziela, 25 lipca 2010

Buddhabrot

Każdy chyba zna taki fraktal jak zbiór Mandelbrota. W 1993 został znaleziony inny fraktalo-podobny obraz, o wiele moim zdaniem ładniejszy ;)

Zbiór Mandelbrota to zbiór takich liczb zespolonych c, że ciąg zn definiowany jako
 z0 = 0
 zn+1 = (zn)2 + c
nie dąży do nieskończoności przy n -> ∞.

W rzeczywistych rozwiązaniach sprawdza się, czy w określonej liczbie iteracji (np. 1000) ciąg ten nie wykroczy poza okrąg o środku w punkcie (0, 0) i promieniu równym 2 - jeżeli kolejna liczba zespolona w ciągu ma moduł większy niż 2, to wiadomo już, że na pewno dla tej wartości c ciąg zn dąży do nieskończoności

Kiedy liczby c przedstawimy na płaszczyźnie zespolonej dostaniemy taki oto, znajomy obrazek:


W 1993 pani Melinda Green zadała sobie pytanie:
A co się dzieje z ciągiem zn, kiedy dąży on do nieskończoności? Jaką ścieżkę przebywa zanim "wyskoczy" na odległość większa niż 2 od środka płaszczyzny?

Odpowiedź jest niezwykle ładna.

Zaczynamy mając zwykłą funkcję potrzebną do zbioru Mandelbrota - zwraca ona nam w której iteracji punkt o współrzędnych (c_x, c_y) "uciekł" z okręgu o promieniu 2:

private static int Mandelbrot(double c_x, double c_y, int max_iter)
{
  double x = 0;
  double y = 0;
  int iter = 0;

  while (x * x + y * y <= 4 && iter < max_iter)
  {
    double xtemp = x * x - y * y + c_x;
    y = 2 * x * y + c_y;
    x = xtemp;
    iter++;
  }
  return iter;
}


Chcąc wygenerować zbiór Mandelbrota bierzemy każdy piksel z ekranu, wyliczamy jego współrzędne na płaszczyźnie zespolonej (czyli (c_x, c_y)) i jeżeli zwrócona liczba iteracji równa jest podanej maksymalnej to kolorujemy na czarno, w innym wypadku wybieramy kolor z palety ;)

Obrazek pani Green tworzymy trochę inaczej:
1. Dla każdej piksela obrazu wynikowego tworzymy licznik, na początku równy 0.

2. Losujemy jakąś liczbę zespoloną c. Nasze losowe (c_x, c_y) powinno znajdować się w odległości nie większej niż 2 od środka układu współrzędnych.

3. Wyliczamy wartość funkcji Mandelbrot dla liczby c i ustalonej z góry maksymalnej liczby iteracji max_iter. Jeżeli liczba c znajduje się w zbiorze Mandelbrota, to idziemy do kroku 5. Jeżeli "wyskoczyła" z niego, to idziemy dalej.

4. Dla liczby zespolonej c i maksymalnej liczby iteracji max_iter wywołujemy funkcję MandelbrotTrace, (zmodyfikowaną funkcję Mandelbrot):

private static void MandelbrotTrace(double c_x, double c_y, int max_iter)
{
  double x = 0;
  double y = 0;
  int iter = 0;

  while (x * x + y * y <= 4 && iter < max_iter)
  {
    UpdateCounters(x, y);
    double xtemp = x * x - y * y + c_x;
    y = 2 * x * y + c_y;
    x = xtemp;
    iter++;
  }
}


Dodane wywołanie funkcji UpdateCounters modyfikuje liczniki ustawione na zero w kroku 1. Dla danego punktu (x, y) ustala który to piksel w obrazie wynikowym i zwiększa odpowiadający mu licznik o 1.

5. Kroki 2-4 powtarzamy ile razy nam pasuje, parenaście milionów da już bardzo dobre efekty.

6. Generujemy obraz wynikowy na podstawie wartości liczników.

Kiedy wybierzemy maksymalną wartość licznika i przyjmiemy jasność tego piksela za 1.0, a reszcie pikseli przypiszemy jasność proporcjonalnie do wartości ich liczników, to... dostaniemy 1 biały piksel i resztę czarnych.

Ale jeżeli jako jasność 1.0 weźmiemy piksel o drugiej największej wartości (ten najjaśniejszy z definicji na 1.0) i tak samo proporcjonalnie przypiszemy jasność reszcie otrzymamy...


Wow. Można to lekko podbarwić Photoshopem czy innym Paint.NET - ja lubię zmodyfikować krzywą dla niebieskiego tak aby przechodziła przez punkt (168, 255):


Obraz ten nazywany jest Buddhabrot. Dlaczego? No cóż...


Ja już mam nową tapetę (http://wojtekm.ovh.org/buddhabrot_wallpaper.jpg) ;)


Obraz ten można generować w paru odmianach. Popularna jest odmiana zwana Nebulabrot:


Obraz nazwano tak, ponieważ przypomina zdjęcia mgławic kosmicznych. A przypomina je, ponieważ jest kolorowany w bardzo podobny sposób do kolorowania tak naprawdę czarno-białych zdjęć astronomicznych. Zamiast jednego zestawu liczników mamy trzy - dla czerwieni, zieleni i błękitu. Każdy z nich wypełniamy podobnie jak w wersji czarno-białej, ale dla różnych kolorów podstawowych stosujemy różną wartość parametru max_iter. Powyższy obrazek powstał dla następujących wartości granicznej liczby iteracji: 1000 dla czerwonego, 400 dla zielonego, 200 dla niebieskiego.

Można też ująć problem jeszcze inaczej. Oryginalnie śledzimy drogę ciągu zn dla tych wartości parametru c, które nie należą do zbioru Mandelbrota. Anti-buddhabrot powstaje przez śledzenie ciągu dla wartości parametru c należących do zbioru Mandelbrota.

Wadą Buddhabrot i pochodnych jest trudność w ich powiększaniu. Zbiór Mandelbrota można powiększać w nieskończoność, natomiast jedynym sposobem na ujrzenie detali Buddhabrot jest... wygenerowanie większego obrazka.

Wszystkie obrazki fraktali tu zaprezentowane zostały generowane prostym programem w C# mojego autorstwa ;)

Więcej o Buddhabrot: http://en.wikipedia.org/wiki/Buddhabrot

1 komentarz:

  1. ja tam wolałem tapetę, którą miałeś ustawioną jak chodziliśmy do Tuzina, a nie jakiś Buddabrot :D

    OdpowiedzUsuń