Flash-Ersatz für Programmierartisten

Aus LinuxUser 08/2008

Flash-Ersatz für Programmierartisten

Easy Programming

Die Java-Software Processing verwandelt auch Nicht-Programmierer in Computerkünstler: Damit erzeugen Sie schnell und einfach bewegliche Figuren und stellen sie als Flash-ähnliches Applet ins Netz.

Processing schafft etwas, was gewöhnliche Programmiersprachen wie Java, C und C++ nicht können – es produziert schnell ansehnliche Resultate. Wer schon einmal versucht hat, mit OpenGL einen rotierenden Würfel zu programmieren, fand sich wahrscheinlich schnell in einer stundenlangen Fehlersuch-Orgie wieder. Fehlende Bibliotheken und falsch deklarierte Variablen machen dem Hobby-Programmierer das Leben schwer.

Processing will genau das ändern: Es richtet sich etwa an Künstler, die Ideen haben, aber keine Ahnung vom Programmieren. Und es richtet sich an Leute, die ihre Daten einfach optisch aufbereiten wollen, ohne auf einschläfernde Diagramme und eintönige Mehrfarbtorten zurückzugreifen. Das Projekt Code-Swarm [1] verwendet Processing beispielsweise, um die Entwicklung diverser Open-Source-Projekte über den Lauf der Zeit zu visualisieren. Die faszinierenden Ergebnisse erinnern an einen Bienenstock, den mal viele aufgeregte, mal eine handvoll fleißige Bienen zum Wachsen bringen.

Die in Java geschriebene Software macht es Ihnen einfach: Sie schreiben ein Programm, drücken auf Play und dann tut der Code – oder nicht. Im zweiten Fall gibt es vergleichsweise verständliche Rückmeldungen für die Fehlersuche. Wollen Sie das Endprodukt im Netz zeigen, spuckt die Software per Knopfdruck ein fertiges Java-Applet aus, das Sie einfach auf Ihren gemieteten Webspace respektive Webserver kopieren.

Zwar wird Processing, das um 2001 herum in den MIT-Labs entstand, gern mit Flash verglichen – allerdings handelt es sich im Gegensatz zu Adobes Produkt um Open-Source-Software. Anstelle des Flash-Plugins brauchen die Betrachter lediglich ein Java-Plugin für den Browser, das sich (meist) sehr zügig installieren lässt.

Installation

Um die 3D-Fähigkeiten der Software zu nutzen, brauchen Sie entweder einen installierten 3D-Treiber für die Grafikkarte, oder Sie verwenden die in die Java-Anwendung eingebaute Software-3D-Engine P3D. Letztere braucht etwas mehr Ressourcen als OpenGL – sie hilft aber, wenn unter Linux ein funktionierender 3D-Treiber für die Grafikkarte fehlt.

Die Software selbst finden Sie auf der Heft-DVD oder laden Sie von der Webseite des Projekts [2] herunter. Entpacken Sie das TGZ-Archiv in einen Ordner im Home-Verzeichnis. Öffnen Sie eine Konsole, wechseln Sie in das neu entstandene Unterverzeichnis und geben Sie ./processing ein, um die Anwendung zu starten.

Nach dem Start erscheint ein leeres Feld, in das Sie den Code eingeben (Abbildung 1). Probieren Sie es doch gleich mal aus: Tippen Sie das Programm aus Listing 1 in das Fenster und drücken Sie auf das Icon mit dem Dreieck oben links. Sie sehen dann die Figur aus Abbildung 2 (links).

Abbildung 1: Die paar Zeilen Code in Listing 1 genügen, um mit Processing eine einfache Figur zu zeichnen.

Abbildung 1: Die paar Zeilen Code in Listing 1 genügen, um mit Processing eine einfache Figur zu zeichnen.

Listing 1
size(200, 200);
background(255);
stroke(0);
noFill();
smooth();
for(int i = 0; i < 200; i += 10) {
  ellipse(100, 100, i, i);
}

Nun sollte sich ein kleines Fenster öffnen, das eine Reihe konzentrisch angeordneter Kreise abbildet. Eine Erklärung der einzelnen Funktionen folgt gleich – Sie können diese aber auch selbst nachschlagen. Dazu klicken Sie in der Processing-GUI auf den Menüpunkt Help | Reference. Die Befehlsreferenz erklärt kurz und knapp, was die einzelnen Funktionen bewirken. Wer es anschaulicher mag, wählt unter dem Menüpunkt File | Examples eines der zahlreichen Beispielprogramme aus, die den Umgang mit Processing anschaulich demonstrieren, wobei im Code einige Anmerkungen stehen. Nicht zuletzt gibt es Processing-Bücher, empfehlenswert ist etwa der Wälzer von Ira Greenberg [3], der sich auch explizit an Künstler und Nicht-Programmierer richtet.

Nun aber zum Beispielprogramm von Listing 1. Das öffnet in den ersten beiden Zeilen zunächst eine 200 mal 200 Pixel große Arbeitsfläche mit einem weißen Hintergrund (background(255)). Geben Sie in der Klammer nur einen Wert an, wählen Sie zwischen 255 Grautönen von 0 (Schwarz) bis 255 (Weiß). Setzen Sie hingegen drei durch ein Komma getrennte Werte ein, stehen diese für den sRGB-Farbraum. Der Eintrag background(255,0,0) färbt den Hintergrund zum Beispiel knallrot. Nach demselben Schema setzen Sie einen schwarzen Pinsel ein (stroke(0)).

Die Funktion noFill() sorgt dafür, dass Processing die Figuren nicht ausfüllt – andernfalls würde der größte Kreis alle anderen überdecken. Für die glatten Kanten der Kreise sorgt ein Anti-Aliasing-Effekt, den Sie über smooth() aktivieren, das sich auf alle nachfolgenden Figuren auswirkt. Abschließend folgt eine for()-Schleife, die eine bestimmte Funktion so oft ausführt, bis eine in der Schleife definierte Bedingung eintritt (hier: wenn i den Wert 200 erreicht).

In der Schleife wird die Ganzzahl-Variable i zunächst auf Null gesetzt (int i =0) und dann in 10er-Schritten hochgezählt (i+=10). So lange i unter 200 (i < 200) bleibt, läuft die Schleife weiter – erreicht sie den Wert, endet sie. Jeder Durchgang führt dabei die Funktion ellipse() in Zeile 7 aus: Sie zeichnet einen Kreis, dessen Eckdaten in der Klammer stehen. Die Werte 100,100 platzieren den Mittelpunkt des Kreises in der Mitte der 200 x 200 Pixel großen Fläche. Die zwei Variablen i bestimmen jeweils den vertikalen und horizontalen Durchmesser des Kreises. Da i in 10er-Schritten wächst, malt Processing erst einen Kreis mit 10 Pixeln Durchmesser, dann einen mit 20 Pixeln, und so weiter.

Um den Kreis kreisen

Kleine Veränderungen entfachen beim Programmieren häufig große Wirkungen. Ändern Sie das zweite i in der Klammer hinter ellipse und ersetzen es durch 100, also:

ellipse(100, 100, i, 100)

dann transformieren Sie den Kreis in eine Ellipse (Abbildung 2). Während sich der horizontale Durchmesser dank des verbliebenen i ständig vergrößert, bleibt der vertikale konstant bei 100 Pixeln.

Abbildung 2: Ändern Sie nur einen kleinen Parameter, wirkt sich das deutlich auf die Figur aus.

Abbildung 2: Ändern Sie nur einen kleinen Parameter, wirkt sich das deutlich auf die Figur aus.

Im nächsten Schritt bringen Sie den Zufall ins Spiel. Tauschen Sie die for()-Schleife aus Listing 1 gegen jene aus Listing 2 aus.

Listing 2
for(int i = 0; i < 200; i += 10) {
  float r = random(200);
  ellipse( 100, 100, r, 100);
}

Die neue Schleife erhält mit der Zufallsvariable r ein neues Element. Bei jedem Durchgang erzeugt die Zeile float r = random(200); eine Gleitkommazahl (float) zwischen 0 und 200 und legt sie in der Variablen r ab. Diese sich ständig ändernde Zahl verursacht in der gezeichneten Figur die unregelmäßigen horizontalen Abstände (Abbildung 3). Noch krummer wird es, wenn Sie die Schleife um eine weitere Zufallszahl bereichern (Listing 3) und auch den vertikalen Durchmesser dem Zufall überlassen (Abbildung 4). Die Figur sieht zwar schon etwas räumlich aus, dreidimensional ist sie aber noch nicht.

Abbildung 3: Über zufällig generierte Zahlen bringen Sie etwas Unruhe in strenge geometrische Figuren…

Abbildung 3: Über zufällig generierte Zahlen bringen Sie etwas Unruhe in strenge geometrische Figuren…

Abbildung 4: …setzen Sie zwei Zufallszahlen ein, erhält die Figur allmählich dreidimensionale Züge.

Abbildung 4: …setzen Sie zwei Zufallszahlen ein, erhält die Figur allmählich dreidimensionale Züge.

Listing 3
for(int i = 0; i < 200; i += 10) {
  float r = random(200);
  float s = random(200);
  ellipse( 100, 100, r, s);
}

Aufbruch in die dritte Dimension

Auch die dritte Dimension lässt sich mit Processing recht einfach erschließen. Um das zu zeigen, erschaffen wir in Listing 4 einen einfachen Würfel. Das tolle daran: Er reagiert auf die Maus – Sie können ihn problemlos über die definierte Fläche schieben und ziehen (Abbildung 5). Leider zeigt Gnomes Screenshot-Tool die Maus nicht mit an, sie befindet sich aber auf allen drei Bildern etwa in der Mitte des Würfels.

Abbildung 5: Der Würfel folgt Ihren Mausbewegungen und lässt sich so einfach über den Bildschirm ziehen – natürlich auch online.

Abbildung 5: Der Würfel folgt Ihren Mausbewegungen und lässt sich so einfach über den Bildschirm ziehen – natürlich auch online.

Listing 4
void setup() {
  size(400, 400, P3D);
  frameRate(30);
}
void draw() {
  background(200);
  pushMatrix();
  translate(mouseX,mouseY,10);
  color c1 = color(180);
  fill(c1);
  stroke(128);
  box(150);
  popMatrix();
}

Der Code besteht aus den beiden Grundfunktionen setup() und draw(), die verschiedene andere Funktionen enthalten. Die Setup-Funktion legt einige Grundparameter für das Programm fest. Die Draw-Funktion zeichnet ein bestimmtes Objekt und arbeitet die Befehle innerhalb der geschweiften Klammern systematisch ab und beginnt anschließend wieder neu.

Die erste Funktion in Zeile 2 initialisiert die Arbeitsfläche, hinter der Ausdehnung steht jedoch diesmal ein ominöses P3D. Das initialisiert die eingebaute, softwarebasierte 3D-Engine von Processing. Die berechnet die 3D-Grafiken und sendet sie dann an die Grafikkarte, welche sie auf den Bildschirm zeichnet. Um P3D durch OpenGL zu ersetzen und die 3D-Grafik von der schnelleren Hardware der Grafikkarte rendern zu lassen, fügen Sie ganz an den Anfang des Codes folgende Zeile ein:

import processing.opengl.*;

Dann ersetzen Sie P3D durch OPENGL. Auf schnelleren Rechnern merken Sie bei einfachen Figuren in der Regel keinen Unterschied. Im zweiten Fall brauchen Sie allerdings eine 3D-beschleunigte Grafikkarte, müssen also den Nvidia-, ATI- oder Intel-Treiber installieren. In Zeile 3 legen Sie dann fest, wie viele Frames pro Sekunde das Programm anzeigt. Der Wert 30 gilt als akzeptabel, um kein Ruckeln mehr zu bemerken.

Der nächste Schritt widmet sich den Eigenschaften des Würfels. Als Hintergrundfarbe soll ein helles Grau zum Einsatz kommen (background(200)), die Funktionen pushMatrix() und popMatrix() in den Zeilen 8 und 14 bilden quasi das Gerüst um die Figur. Während pushMatrix() ein neues Koordinatensystem schafft und dieses auf dem so genannten Matrix Stack (Kasten “Was ist die Matrix?”) ablegt, stellt popMatrix() die zuvor genutzte Matrix wieder her. Das kleine Programm funktioniert auch ohne diese beiden Funktionen, die aber im nächsten Beispiel sinnvoll in Erscheinung treten.

Innerhalb der Matrix tritt dann zunächst die translate-Funktion auf. Sie positioniert den Würfel dank der drei Parameter auf einem Schnittpunkt von X-, Y- und Z-Achse, also im virtuellen Raum. Als Initialwert nimmt die Funktion den Punkt 0,0 oben links auf der Arbeitsfläche und positioniert dort den Mittelpunkt der Figur. Folgen weitere Translate-Funktionen innerhalb der Draw-Funktion, wählen diese hingegen jeweils die vorherigen Translate-Koordinaten als Bezugspunkt. Sie können den Würfel daher gut mit der Maus bewegen, denn mouseX,mouseY orientieren sich immer an den vorherigen X/Y-Koordinaten des Mauszeigers.

Was ist die Matrix?

Der Matrix Stack ist schwierig zu erklären – unter [4] versucht es jemand in einem Forum. Grob gesprochen: Wenn Sie nacheinander drei Sequenzen aus jeweils mehreren Bewegungen erzeugen, beginnen Sie jede Sequenz mit der Funktion pushMatrix(), die ein neues Koordinatensystem erschafft. Um zur vorherigen Sequenz mit dem zuvor genutzten Koordinatensystem zurückzukehren, genügt ein popMatrix(). Das Ganze funktioniert also wie eine Art Rücksprungmarke; vorwärts springen können Sie dabei allerdings nicht.

Als nächstes definieren Sie für die Variable c1 eine Farbe, in diesem Fall ein helles Grau – auch sRGB-Werte können Sie hier einsetzen. Sie füllen den Würfel in Zeile 11 mit dieser Farbe, aber seine Kanten zeichnen Sie via stroke() in einem dunklen Grau. Erst jetzt dann bauen Sie in Zeile 13 den Würfel und verpassen ihm eine Seitenlänge von 150 Pixel. Um einen Quader zu zeichnen, tragen Sie hier drei Werte für Länge, Breite und Höhe ein.

Der Todesstern

Zum Abschluss präsentiert Listing 5 noch ein etwas aufwändigeres Skript. Es zeigt zwei gegeneinander rotierende, grüne Würfel (Abbildung 6). Kurze Kommentare machen den Code etwas lesbarer, hier interessieren vor allem der Einsatz von pushMatrix() und popMatrix() sowie die Drehung der Figuren.

Abbildung 6: Die zwei gegeneinander drehenden Würfel strahlt ein virtueller Scheinwerfer an.

Abbildung 6: Die zwei gegeneinander drehenden Würfel strahlt ein virtueller Scheinwerfer an.

Listing 5
import processing.opengl.*;
float ydirection1 = 1;
float xdirection1 = 1;
float ydirection2 = -1;
float xdirection2 = -1;
void setup() {
  size(400, 400, OPENGL);
  frameRate(30);
}
void draw() {
  background(0);
  directionalLight(255,255,128,0,0,-1);
/* Wuerfel 1 */
  pushMatrix();
  translate(200,200,100);
  color c1 = color(102, 102, 0);
  fill(c1);
  stroke(204,102,0);
  rotateY(radians(ydirection1));
  rotateX(radians(xdirection1));
  box(100);
  popMatrix();
/* Wuerfel 2 */
  pushMatrix();
  translate(200,200,100);
  color c2 = color(102, 102, 0);
  fill(c2);
  stroke(204,102,0);
  rotateY(radians(ydirection2));
  rotateX(radians(xdirection2));
  box(100);
  popMatrix();
/* Wuerfel 1 im Uhrzeigersinn */
  ydirection1 = ydirection1 + 1;
  xdirection1 = xdirection1 + 1;
/* Wuerfel 2 gegen Uhrzeigersinn */
  ydirection2 = ydirection2 - 1;
  xdirection2 = xdirection2 - 1;
}

Zunächst initialisieren Sie in den Zeilen 3 bis 6 für jeden Würfel jeweils die zwei Variablen xdirection und ydirection mit dem Wert 1 beziehungsweise -1. Die Setup-Funktion kennen Sie bereits, Änderungen gibt es an der Draw-Funktion. In ihr beleuchtet zuerst die Funktion directionalLight() die Würfel. Sie bringt sechs verschiedene Parameter mit, von denen die ersten drei einen sRGB- oder HSV-Wert darstellen und die letzten drei einen Punkt im räumlichen Koordinatensystem von X-, Y- und Z-Achse. Die ersten drei Werte legen also die Farbe des Lichts fest, die letzten drei die Richtung, aus der es kommt.

Danach bestimmen Sie zwischen den Funktionen pushMatrix() und popMatrix() jeweils die Position, Größe, Farbe und die Drehung der beiden Würfel. Die Funktionen gleichen sich für die beiden Würfel, bis auf ein Detail: Die Funktionen rotateX() und rotateY sorgen für entgegengesetzte Drehungen.

Die Zeilen 40 und 41 drehen Würfel Nummer zwei auf der X- und Y-Achse jeweils ein Grad gegen den Uhrzeigersinn. Beide Variablen starten mit dem Wert -1. In die umgekehrte Richtung dreht sich Würfel Nummer 1. Da beide dieselbe Position einnehmen, drehen sie sich also gegeneinander. Im Anschluss an diese minimale Drehbewegung erhalten die Variablen in den Zeile 46 bis 52 neue Werte.

Das Drehmoment für Würfel 1 steigt um einen Zähler, das für Würfel 2 sinkt hingegen. Processing führt nun die Draw-Funktion erneut aus, wodurch beide Würfel jeweils ein weiteres Grad in entgegengesetzte Richtungen rotieren. Da die Draw-Funktion 30 Frames pro Sekunde zeichnet, entsteht eine flüssige Drehung der Würfel.

Und noch ein weiterer Punkt ist interessant: Entfernen Sie im Beispiel-Code die Funktionen pushMatrix() und popMatrix(), dann kreist der zweite Würfel plötzlich wie ein Planet um den ersten. Hier braucht also jeder Würfel sein eigenes Koordinatensystem – es sei denn, Sie arbeiten an einem virtuellen Planetarium.

Speichern und ab ins Netz

Standardmäßig legt Processing gespeicherten Versuche im Ordner sketchbook (dt.: Skizzenbuch) in Ihrem Home-Verzeichnis ab. Speichern Sie eine Eigenkreation zum Beispiel unter dem Namen experiment_0815, finden Sie diese später im Ordner ~/sketchbook/experiment_0815/ wieder.

Um die Figur Freunden und Bekannten zu präsentieren, stellen Sie sie am besten ins Netz. Der Export funktioniert über den Menüpunkt File | Export. Processing erstellt dann im eben genannten Pfad einen Unterordner namens applet und lagert dort alle benötigten Dateien ein. Öffnen Sie die Datei index.html im lokalen Browser, sollten Sie die Figur sehen. Um sie auf Ihre Homepage zu stellen, verschieben Sie den applet-Ordner einfach mit Hilfe eines FTP-Client auf den Server, der auch Ihre Webseite beherbergt, und verlinken die Datei index.html mit Ihrer Startseite. Oder Sie greifen direkt auf die Datei zu, etwa über http://www.meinedomain.de/applet/index.html. Nach einer Sicherheitsabfrage erscheint Ihrer Figur (Abbildung 7) – einfacher geht’s wirklich nicht.

Abbildung 7: Vor dem Anzeigen des Java-Applets muss der Anwender eine Frage absegnen, dann erscheint die angefragte Figur.

Abbildung 7: Vor dem Anzeigen des Java-Applets muss der Anwender eine Frage absegnen, dann erscheint die angefragte Figur.

Glossar

MIT

Massachusetts Institute of Technology. Universität in Cambridge/USA, gilt als eine der weltweit führenden Unis im Bereich von technologischer Forschung und Lehre.

sRGB-Farbraum

Farbraum für additive Farbmischung, in dem jede Farbe durch die Anteile von Rot, Grün und Blau mit einer Tiefe von 8 Bit pro Kanal definiert wird.

HSV

Farbraum, bei dem die Farbe über Farbton (engl.: “hue”), Farbsättigung (engl.: “saturation”) und Helligkeitswert (engl.: “value”) festgelegt wird.

Infos

[1] Das Code-Swarm-Projekt setzt auf Processing: http://code.google.com/p/codeswarm/

[2] Downloadseite für Processing: http://processing.org/download/index.html

[3] Ira A. Greenberg, “Processing: Creative Coding and Computational Art”, Computer Bookshops, New York 2007.

[4] pushMatrix() und popMatrix() erklärt: http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1177279317

LinuxUser 08/2008 KAUFEN
EINZELNE AUSGABE
ABONNEMENTS
TABLET & SMARTPHONE APPS
E-Mail Benachrichtigung
Benachrichtige mich zu:

Hinweis: Dieser Artikel ist älter als ein Jahr, enthaltene Informationen sind möglicherweise veraltet.

0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben