Standardmäßig werden bereits von Ultra Fractal eine Vielzahl von Kolorierungsalgorithmen zur Verfügung gestellt.
Im dritten Teil wenden wir uns diesen Algorithmen zu, die Eure berechneten Fraktale interpretieren und farblich darstellen.
Im Gegensatz zu direkten Kolorierungsalgorithmen, die sofort eine Farbe für das Pixel zurückgeben, berechnen normale Algorithmen die Farbe nicht unmittelbar selbst, sondern erzeugen einen Fließkomma-Indexwert, der in eine Farbe des Farbverlaufs umgerechnet wird.
Somit ist es möglich, Farben durch Bearbeiten des Farbverlaufs zu ändern. Andererseits sind die Farben, die in einer Ebene auftauchen können, auf die Farben des Farbverlaufs begrenzt.
Der Kolorierungsalgorithmus wird im Karteireiter Innen (Inside) bzw. Außen (Outside) des Werkzeugfensters Ebenen-Eigenschaften (Layer Properties) aufgerufen.
Zu Beginn sollen einige Eckpunkte vorab für unseren Kolorierungsalgorithmus definiert werden.
- er soll eine Dateneingabe durch den Nutzer ermöglichen,
- drei Funktionen sollen ausgewählt werden können und
- es sollen vom Nutzer Zusatzfunktionen aktiviert und eingeblendet werden können.
Okay, dann lasst uns loslegen.
Kolorierungsdatei erstellen
Zunächst erstellt Ihr Euch eine neue Kolorierungsdatei (Coloring Algorithm File). Dazu wählt Ihr im Datei (File) Menü den Punkt Neu (New) aus.
Daraufhin öffnet sich im Editor ein leeres Fenster mit den Namen Coloring1.
Dieses Fenster bzw. diese Formeldatei nimmt nun nach und nach Eure Programmanweisungen auf. Damit Ihr nicht alles von Hand eingeben müsst, sind im Menüpunkt Einfügen (Insert) viele Anweisungen hinterlegt, die Ihr mit Klick einfügen könnt.
Die Formeln beginnen immer mit dem Eintrag-Identifikator, gefolgt von dessen Inhalt, der in geschweiften Klammern steht. Ihr solltet beachten, dass Leerzeichen und Tabulatoren nicht erlaubt sind. Ebenso darf der Eintrag-Identifikator innerhalb der Formeldatei nicht doppelt auftreten.
Mein-erster-Farbalgorithmus {
; Inhalt
}
Kommentare in der Formel werden mit vorangestellten Semikolon gekennzeichnet. Zusätzliche globale Kommentare könnt Ihr mit dem speziellen ‘{ }
‘-Kommentar kennzeichnen.
Auch hier schreibe ich wieder einen globalen Kommentar, der folgende Inhalte aufweist:
comment {
File: Coloring1.ucl
Version: 1.0
Author: Oliver Konow, 2013
Last Modification:
}
Als nächstes folgt der Identifikator in dem Abschnitte, Funktionen und Parameter sowie weitere Einträge stehen können.
Im Menü Einfügen (Insert) findet Ihr den Punkt Neue Formel (New Formula…)
Es öffnet sich anschließend ein Fenster, in dem Ihr den Titel Noise eingeben könnt.
Im Gegensatz zur Fraktalformel, steht beim Kolorierungsalgorithmus keine Symmetrie, sondern nur der Bereich Usage zur Verfügung. Hier könnt Ihr festlegen, ob der Algorithmus sowohl für Innen (Inside), Außen (Outside) oder beides gelten soll.
Der entsprechende optional ausgewählte Parameter wird in der Formel in Klammern hinter dem Eintrags-Identifikator angezeigt.
Noise(OUTSIDE) {...}
bzw. Noise(INSIDE) {...}
Den Haken am Punkt: Insert global section könnt Ihr entfernen. Falls Ihr für die verbleibenden Abschnitte keine Kommentare haben wollt, so entfernt den Haken auch am Punkt: Insert comments for each section. Drückt anschließend auf OK.
Folgende Abschnitte sollten jetzt vorhanden sein:
Noise {
init:
loop:
final:
default:
title = "Noise"
}
Damit ist das Grundgerüst Eurer Formel fertig, welches Ihr an dieser Stelle speichern solltet. Im nächsten Schritt werde ich die Abschnitte näher erläutern bevor wir sie anschließend mit Variablen befüllen.
Die Abschnitte der Formel
Abschnitt: global
In der Fraktalformel ist dies der erste Abschnitt und wird nur einmal pro Bild ausgeführt. Er kann dazu verwendet werden, Suchtabellen zu füllen und Nur-Lese-Variablen zu initialisieren. Somit können viele wiederholte Berechnungen vermeiden werden.
Abschnitt: init
In diesem Abschnitt wird die Hauptvariable z
initialisiert. Sie ist ein vordefiniertes Symbol, weshalb sie korrekterweise ‘#z
‘ bezeichnet werden müsste. In Fraktalformeln kann das #
-Präfix vor ‘#z
‘ weggelassen werden. In Kolorierungs-Algorithmen wird es jedoch benötigt.
Dieser Abschnitt wird pro Pixel nur einmal ausgeführt und eignet sich, um Variablen zu initialisieren.
Abschnitt: loop
Hier steht unsere Hauptgleichung, die nur einmal pro Iteration ausgeführt wird. Der Abschnitt soll den Wert der vordefinierten komplexen Variable #z
unter Berücksichtigung des alten Wertes von ‘z
‘ aktualisieren.
Abschnitt: final
Anschließend wird dieser Abschnitt ausgeführt, um den aktuellen Index in den Farbverlauf umzusetzen, der im weiteren Verlauf durch die verschiedenen Einstellungen im Karteireiter Innen (Inside) und Außen (Outside) weiter transformiert werden kann. Dieser Index ist ein Fließkommawert, der in das vordefinierte Symbol #index
geschrieben werden sollte.
Falls die Einstellungen auf den Karteireitern Innen (Inside) und Außen (Outside) auf die voreingestellten Werte gesetzt sind (Density = 1
, Transfer = Normal
und Offset = 0
), korrespondiert der Farbverlaufsbereich mit den Werten 0..1
aus dem Indexwert.
Solltet Ihr den direkten Kolorierungsalgorithmus nutzen, dann ist das vordefinierte Symbol #color
anstelle von #index
zu verwenden.
Darüber hinaus ist es möglich, dem vordefinierte Symbol #solid
den Wert true
zuzuweisen, um dem Pixel die aktuelle Hintergrundfarbe der Karteireiter Innen (Inside) und Außen (Outside) zu übergeben.
Abschnitt: default
Grundeinstellungen unserer Formel betreffend sind in diesem Abschnitt zu finden. Er kann Einstellungen wie title
, render
, precision
, helpfile
und/oder helptopic
beinhalten. Parametereinstellungen innerhalb der Blöcke param
und endparam
können ebenfalls verwendet werden.
Weitere Einstellungen sind in der Hilfedatei zu finden.
Einsetzen der Variablen in die Formel
Nachdem das Grundgerüst steht, können nun Variablen, Ausdrücke und Formeln in die entsprechenden Abschnitte eingesetzt werden.
Hinweis! Hinsichtlich der Parameter möchte ich auf den Artikel Formel schreiben – Teil 1 verweisen.
Inhalt des init-Abschnitts
float rmin = 1.0e12 ; minimale Distanz zum Färben des Pixels
float radius = 0
int num = 0 ; Numerator
Zunächst werden die Variablen rmin
, radius
und num
initialisiert.
Der ‘Numerator‘ wird benötigt, um die Abbruchbedingung der repeat-until
-Schleife im nächsten Abschnitt festzulegen, da sie sonst unendlich durchlaufen werden würde.
Inhalt des loop-Abschnitts
complex a = @myfunc1(@myfunc2(@myfunc3(#z)))
if @iter > 0
repeat
if @e_opt == 1
if @operator == "+"
a = @morphfunc((@power * a - @off / (a^@power))) + (@power + @off)
elseif @operator == "-"
a = @morphfunc((@power * a - @off / (a^@power))) - (@power + @off)
elseif @operator == "*"
a = @morphfunc((@power * a - @off / (a^@power))) * (@power + @off)
elseif @operator == "/"
a = @morphfunc((@power * a - @off / (a^@power))) / (@power + @off)
elseif @operator == "^"
a = @morphfunc((@power * a - @off / (a^@power))) ^ (@power + @off)
endif
else
a = (@power * a - @off / (a^@power)) / (@power + @off)
endif
num = num + 1
until num >= @iter
endif
b = a * (@twist + @noise * #random)
if @radius == "Normal"
radius = cabs(#z - b + @dist)
elseif @radius == "Variation +"
radius = cabs(#z - b + @dist) + cabs(@dist + #z)
elseif @radius == "Variation -"
radius = cabs(#z - b + @dist) - cabs(@dist + #z)
elseif @radius == "Variation *"
radius = cabs(#z - b + @dist) * cabs(@dist + #z)
elseif @radius == "Variation /"
radius = cabs(#z - b + @dist) / cabs(@dist + #z)
elseif @radius == "Variation ^"
radius = cabs(#z - b + @dist) ^ cabs(@dist + #z)
endif
if (radius < rmin)
rmin = radius
endif
Die komplexe Variable a
wird mit Hilfe dreier benutzerdefinierter Funktionen, @myfunc1
bis @myfunc3
, aus #z
berechnet.
Im sich anschließenden if
-Statement wird zunächst abgefragt, ob der eingegebene Iterationswert größer Null
ist, um daraufhin die repeat-until
-Schleife solange zu durchlaufen, bis die Abbruchbedingung num >= @iter
, also der 'Numerator' größer oder gleich dem Iterationswert, erfüllt ist.
Innerhalb dieser Schleife befinden sich zwei weitere if
-Abfragen, eine die prüft, ob das Kontrollkästchen für die erweiterten Optionen aktiviert wurde und die Andere, die überprüft, welcher Operator gewählt wurde und somit die dazugehörige Formel zum Berechnen verwendet.
Ist das Kontrollkästchen für die erweiterte Option aktiviert, werden die Auswahlmöglichkeiten Operator, Morph Funktion und Radiusvariation angezeigt, ansonsten wird auf eine Standardformel zurückgegriffen.
Die Variable b
errechnet sich aus der eingangs ermittelten komplexen Variable a
, der Verdrehung sowie dem mit einem komplexen Zufallswert (#random
) multiplizierten Rauschfaktor.
Danach erfolgt eine Auswahl zum Variieren der Formel für das Berechnen des Radius. Sollte der ermittelte Radius kleiner als die minimale Distanz sein, so entspricht der Radius der minimalen Distanz.
Hinweis! Statt die Farbe eines Pixels sofort zu berechnen, ermittelt Ultra Fractal zunächst einen vorläufigen Indexwert als Fließkommazahl, der anschließend vom Farbverlauf in Farben umgesetzt wird. Da nur Indexwerte gespeichert werden, können Farben verändert werden, ohne das Fraktal selbst neu berechnen zu müssen.
Der Kolorierungsalgorithmus bestimmt die Farbverteilung, der Farbverlauf definiert die Farbe.
Inhalt des final-Abschnitts
#index = rmin
Mit Hilfe dieser Formelauswahl und den entsprechenden Dateneingaben wird nun geprüft, ob das Pixel eingefärbt werden muss oder nicht. Die so ermittelte Fließkommazahl wird jetzt dem vordefiniertem Symbol #index
übergeben.
Inhalt des default-Abschnitts
title = "Noise"
heading
caption = "Dateneingabe"
endheading
param @noise
caption = "Rauschfaktor"
default = 0.01
endparam
param @twist
caption = "Verdrehung"
default = 0.5
endparam
param @dist
caption = "Distanz"
default = 2.0
endparam
param @power
caption= "Newton Power"
default = (-0.075,1.0375)
endparam
param @iter
caption= "Newton Iteration"
default = 50
endparam
param @off
caption= "Newton Offset"
default = (1,0)
endparam
heading
caption = "Funktionsauswahl"
endheading
func @myfunc1
caption = "Erste Funktion"
default = ceil()
endfunc
func @myfunc2
caption = "Zweite Funktion"
default = cosh()
endfunc
func @myfunc3
caption = "Dritte Funktion"
default = cabs()
endfunc
heading
caption = "Zusatzfunktionen"
endheading
param @e_opt
caption = "Erweiterte Optionen"
hint = "Zusätzliche Optionen mit denen die Funktionsgleichungen \
unterschiedlich berechnet werden."
default = false
endparam
param @operator
caption = "Operator"
enum = "+""-""*""/""^"
default = 4
visible = @e_opt
endparam
func @morphfunc
caption = "Morph Funktion"
default = abs()
visible = @e_opt
endfunc
param @radius
caption = "Radiusvariation"
default = 0
enum = "Normal" "Variation +" "Variation -" "Variation *" "Variation /" "Variation ^"
hint = "Radiusvariation"
visible = @e_opt
endparam
Wie bereits weiter oben beschrieben, werden die Parameter der Zusatzfunktionen nur eingeblendet, wenn durch die if
-Anweisung (if @e_opt == 1
) festgestellt wurde, dass das Kontrollkästchen aktiviert ist.
Das Einblenden erfolgt mit visible = @e_opt
.
Die unterschiedlichen Auswahlmöglichkeiten zum Berechnen der Operatoren sowie der Radiusvariationen werden mittels enum
festgelegt und erscheinen anschließend in einer Dropdownliste.
Alle weiteren Einstellungen in den Parameterblöcken sind bereits im Artikel Formel schreiben – Teil 1 beschrieben und sollen an dieser Stelle nicht weiter erläutert werden.
Direkte Kolorierungsalgorithmen schreiben
Anstatt eines Indexwertes geben diese Kolorierungsalgorithmen direkt einen Wert für die Farbe aus, die dem vordefinierten Symbol #color
zugewiesen wird.
Für das Berechnen können die color-Ausdrücke, die color-Variablen sowie die color-Arithmetik verwendet werden. Hinweise sind in der Hilfedatei zu finden.
Die verfügbaren Farbumwandlungs- und Farbmischfunktionen sind im Archiv in der Tabelle Farbfunktionen zu finden.
Hier die Datei coloring1.ucl.
Ich wünsche Euch viel Spaß beim Experimentieren!
Formeln schreiben – Teil 3 by Oliver Konow is licensed under CC BY-NC-ND 4.0
Schreibe einen Kommentar