Easy Programming
Flash-Ersatz für Programmierartisten
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.
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.
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.



