Aufgabe: Programmieren Sie ein „Apfelmännchen“ Quelle: Xiang, Plastock: Computergrafik 2.8 Beispiel: Bildliche Darstellung der Mandelbrot-Menge Ein elegantes und anschauliches Beispiel, das den Aufbau schöner Bilder durch das Setzen von Farbattributen für einzelne Pixel direkt aus der Anwendung heraus verdeutlicht, ist die bildliche Darstellung der Mandelbrot-Menge. Diese bemerkenswerte Menge beruht auf der folgenden Transformation: Xn+1 = Xn2 + Z wobei sowohl x als auch z komplexe Zahlen sind. Für Leser, die mit komplexen Zahlen nicht vertraut sind, reicht es zu wissen, dass eine komplexe Zahl in der Form a + bi festgelegt wird. Hier handelt es sich bei a und b um reelle Zahlen; a wird als Realteil der komplexen Zahl und b als Imaginärteil (der durch das spezielle Symbol i gekennzeichnet ist) bezeichnet. Der Betrag von a + bi, angegeben in der Form \a + bi\, entspricht der Quadratwurzel von a2 + b2. Die Summe der beiden komplexen Zahlen a + bi und c + di wird als (a + c) + (b + d) i definiert, das Produkt als (ac - bd) + (ad + bc)i definiert. Das Quadrat von a + bi entspricht daher (a2 - b2) + 2abi. Die Summe von 0,5 + 2,0i und 1,0 - 1,0i beträgt beispielsweise 1,5 + 1,0i. Als Produkt ergibt sich 2,5 + 1,5i. Das Quadrat von 0,5 + 2,0i ergibt -3,75 + 2,0i und das Quadrat von 1,0 - 1,0i beträgt 0,0 - 2,0i. Bei der Mandelbrot-Menge handelt es sich um eine Menge komplexer Zahlen z, die unter der oben genannten Transformation mit X0 = 0 nicht divergieren. (Sowohl der Real- als auch der Imaginärteil von x0 sind 0). Mit anderen Worten: Um festzustellen, ob eine bestimmte komplexe Zahl z ein Element der Menge ist, beginnen wir mit x0 = 0, gefolgt von x1 = x02 + z,x2 = x12 + z,..., xn+l = xn2 + z,... Wenn |x| bei der Erhöhung von n gegen unendlich geht, dann ist z kein Element. Andernfalls gehört z zur Mandelbrot-Menge. Abbildung 2.11 zeigt, wie man eine diskrete Momentaufnahme der Mandelbrot-Menge erstellt. Auf der linken Seite befindet sich die komplexe Ebene, wo die horizontale Achse Re den Realund die vertikale Achse Im den Imaginärteil komplexer Zahlen angibt. Daher entspricht eine beliebige komplexe Zahl z einem Punkt auf der komplexen Ebene. Unser Ziel ist es, ein Bild in Breite mal Höhe (in Anzahl der Pixel) zu erzeugen, das die z-Werte in einem rechteckigen Bereich abbildet, der durch (Re_min, Im_min) und (Re_max, Im_max) definiert wird. Dieser rechteckige Bereich weist dasselbe Seitenverhältnis wie das Bild auf, um geometrische Verzerrungen auszuschließen. Zur Anpassung an das Pixelraster des Bilds unterteilen wir den Raum. Die Farbe eines Pixels, das als kleines Quadrat im Pixelraster dargestellt wird, wird durch die komplexe Zahl z bestimmt, die der unteren linken Ecke des kleinen Quadrats entspricht. Obwohl in der komplexen Ebene nur Punkte in der Anzahl (Breite x Höhe) für die Bildberechnung verwendet werden, erzeugt dieser relativ direkte Ansatz der diskreten Abtastung halbwegs gute Näherungen für die bildliche Darstellung der Menge. Abb. 2.11: Bildliche Darstellung der Mandelbrot-Menge Es gibt viele Wege, die Farbe eines Pixels auf der Grundlage der entsprechenden komplexen Zahl z zu bestimmen. Hier erzeugen wir ein Graustufenbild, bei dem die Helligkeit eines nicht schwarzen Pixels proportional die Anzahl der Iterationen darstellt, die nötig sind, damit |x| größer als 2 wird. Wir verwenden 2 als Schwellenwert für die Divergenz, da x unter der vorgegebenen Transformation schnell divergiert, wenn |x| den Wert 2 erst einmal überschritten hat. Bleibt |x| nach einer vorgegebenen maximalen Anzahl von Iterationen kleiner oder gleich 2, setzen wir den Pixelwert einfach auf 0 (Schwarz). Der folgende Pseudocode führt das aus, was wir in den vorherigen Absätzen erläutert haben. Wir verwenden N zur Darstellung der maximalen Anzahl von Iterationen, z.real als Real- und z.imag als Imaginärteil von z. Außerdem gehen wir von einer Graustufentabelle mit 256 Einträgen aus, in der (i, i, i) der Farbwert in Eintrag i ist. Mit der Formel im zweiten Aufruf von setCol or wollen wir eine proportionale Abbildung von [0; N] auf [1; 255] erzielen: int i, j, count; float delta = (Re_max-Re_min)/breite; for (i = 0, z.real = Re_min; i < breite; i ++ , z.real+ = delta) for (j = 0, z.imag = Im_min; j < höhe; j++, z.imag+ = delta) { count = 0; komplexe Zahl x = 0; while ( |x| <= 2 , 0 && count < N) { compute x = x 2 + z; count++; } if ( | x | <= 2,0) setColor(0); else setColor(1+254*count/N); setPixel (i, j ) ; } Das Bild in Abb. 2.12 zeigt ein Phänomen, das den Spitznamen Apfelmännchen trägt. Es stellt einen Bereich dar, in dem -2,0 <= z.real <= 0,5 und -1,25 <= z.imag <= 1,25 bei N = 64 ist. Die meisten der außerhalb dieses Bereichs liegenden z-Werte führen zu einer schnellen Divergenz von x,während die z-Werte in dem schwarzen Bereich zur Mandelbrot-Menge gehören. Entlang der Kontur des Apfelmännchens sehen wir die meisten dynamischen Änderungen zwischen Divergenz und Nichtdivergenz zusammen mit den signifikantesten Schwankungen der im Divergenztest verwendeten Anzahl von Iterationen. Je heller ein Pixel ist, desto länger dauert es, Schlussfolgerungen über die Divergenz des entsprechenden z-Werts zu ziehen. Im Prinzip kann der rechteckige Bereich unendlich verkleinert werden, um aktive Regionen zu vergrößern und damit kompliziertere Details aufzuzeigen. Abb. 2.12: Die Mandelbrot-Menge