Das ist der erste Teil der Serie über 3D-Computergraphik, der sich speziell mit Rasterung/Schattierung beschäftigt. Obwohl es natürlich Überschneidungen gibt, möchte ich hier nicht auf spezielle Bibliotheken wie OpenGL oder Direct3D eingehen. Es wird aber wahrscheinlich noch eine Unterserie zu WebGL geben.
Die Standardkamera
Bevor wir etwas rastern können, müssen wir zunächst Punkte im Raum auf unsere Kamera projizieren. Fürs Erste verwenden wir dazu die in Abb. 1 gezeigte inverse Lochkamera (s. Teil 0).

Das Loch unserer inversen Lochkamera – der eye point – liegt im Ursprung unseres Koordinatensystems. Der Schirm ist ein Quadrat der Seitenlänge 2 und parallel zur xy-Ebene. Er schneidet die z-Achse bei z = -1. Die z-Achse geht genau durch seinen Mittelpunkt und zeigt aus dem Schirm heraus. Mit dieser Kamera schauen wir gegen die z-Richtung. Das entspricht dem Standard von OpenGL, mit Direct3D schaut man in z-Richtung.
Ich habe mir kurz überlegt, die z-Achse wie aus der Schule gewohnt nach oben zeigen zu lassen. Dann würde aber die y-Achse in die Tiefe der Szene hinein zeigen und der Begriff z-Buffer für den Speicher der Tiefenwerte wenig Sinn ergeben. Wer seine Punkte lieber mit der z-Koordinate nach oben angibt, kann sie durch eine Drehung um um die x-Achse in unser Koordinatensystem überführen (s. ein späterer Teil).
Die Wahl unserer Standardkamera ist natürlich völlig willkürlich. Wir werden später noch sehen, wie wir sie anders positionieren können … Also, eigentlich wird sie immer gleich bleiben; wir werden den Rest der Szene nur so manipulieren, dass es aussieht, als hätten wir die Kamera verändert.
Kamerakoordinaten
Ein Lichtstrahl, der vom Punkt im Raum ausgeht, muss durch das Loch unserer Lochkamera, also den Ursprung gehen (dicke grüne Linie in Abb. 2). Dabei schneidet er den Schirm unserer Kamera im Punkt
, weil sich der Schirm in der Ebene z = -1 befindet.

Dieser Schnittpunkt ist die Projektion unseres Punktes P. Wie erhalten wir aber dessen Kamerakoordinaten (camera bzw. view coordinates)
?
Die x– und y-Koordinaten des Punktes P liegen in der Ebene z = const; die Koordinaten des Punktes liegen in der Ebene z = -1. Weil zwei Ebenen mit konstanten z-Werten parallel zueinander sind, und zwei Punkte eine Gerade eindeutig festlegen, sind auch die roten Linien zueinander parallel und die blauen Linien ebenfalls. Daher können wir den Strahlensatz anwenden und erhalten
.
Umformen liefert dann die camera coordinates
(Um vor der Kamera zu liegen, muss die z-Koordinate negativ, ja sogar kleiner als -1 sein. Zur Erinnerung: -2 ist kleiner als -1!)
Die Kamerakoordinaten des projizierten Punktes sind also im Wesentlichen die x– und y-Koordinaten des ursprünglichen Punktes P, dividiert durch dessen z-Koordinate. Je weiter ein Punkt vor der Kamera liegt, desto näher zur Mitte des Schirms wandern die Kamerakoordinaten (bei sonst gleichem x und y).
Das ist für die typischen perspektivischen Effekte verantwortlich, z.B. parallele Schienen, die Richtung Horizont einander immer näher zu kommen scheinen. Tatsächlich bleibt ihr Abstand immer gleich (hoffentlich!), und nur die Bildpunkte weiter entfernter Schienenteile sind näher zusammen.
Durch unsere Projektion haben wir aus drei Koordinaten nur noch zwei gemacht. Durchs Projizieren geht immer Information verloren. De facto werden alle Punkte auf der grünen Geraden in Abb. 2 auf denselben Punkt abgebildet. Unsere Zentralprojektion macht also aus jeder Geraden durch den Ursprung einen Punkt am Schirm. Der Zweig der Mathematik, der sich damit beschäftigt, heißt projektive Geometrie.
Bildschirmkoordinaten
Wenn wir einen Bildschirm mit unendlich feiner Auflösung hätten, wären wir jetzt fertig – haben wir aber nicht. Jeder Bildschirm besteht aus einem Raster endlich großer Pixel wie in Abb. 3 gezeigt, und wir müssen die camera coordinates noch in die Pixelkoordinaten (screen coordinates)
am Bildschirm umrechnen.

Nachdem unser Bildschirm ein Quadrat der Seitenlänge 2 ist, sollten wir das Pixelraster auch quadratisch wählen, mit n Pixeln pro Seite. Ein Pixel hat also die Breite bzw. Höhe 2/n (in willkürlichen Längeneinheiten). In der Computergraphik liegt der Ursprung des Pixelrasters in der linken oberen Ecke. Die -Achse zeigt dabei in dieselbe Richtung wie die
-Achse, die
-Achse entgegen der Richtung der
-Achse.
Wenn wir die – bzw.
-Koordinate durch die Breite bzw. Höhe eines Pixels dividieren, wissen wir, wie viele Pixel wir vom Ursprung entfernt sind. Dieses Ergebnis müssen wir noch zur Anzahl der Pixel bis zum Ursprung des Kamerakoordinatensystems addieren (
) bzw. davon subtrahieren (
):
Die floor-Funktion liefert die größte ganze Zahl nicht größer als x, weil nur ganze Zahlen Pixelkoordinaten sein können.
Setzen wir jetzt noch unsere Kamerakoordinaten ein, erhalten wir schließlich
Weil die screen coordinates nicht negativ sein können, braucht man die floor-Funktion eigentlich nicht. Eine einfache Typumwandlung von Dezimalzahl in Ganzzahl leistet in den meisten Programmiersprachen dasselbe.
Punkte am linken bzw. oberen Rand eines Pixels gehören zu diesem Pixel. Punkte am rechten bzw. unteren Rand gehören zu den Nachbarpixeln. Wenn die Anzahl der Pixel wie üblich gerade ist, liegt der Ursprung des Kamerakoordinatensystems am Rand eines Pixels. Der Punkt (0|0) in camera coordinates würde also das Pixel rechts unterhalb des Ursprungs aufleuchten lassen (Pixel (4|4) in Abb. 3).
Fragmente
Durch die endliche Größe eines Pixels gibt es einen ganzen Raumbereich, aus dem Punkte auf dieses eine Pixel abgebildet werden. Alle Punkte einer Oberfläche, die auf dasselbe Pixel abgebildet werden, nennt man ein Fragment (s. Abb. 4). So ein Fragment kann viel größer als ein Pixel selber sein.

Beispiel
Nehmen wir als Beispiel die Eckpunkte eines Würfels der Seitenlänge 1 (blaue Kreise in Abb. 5). Die Vorderseite ist bei z = -1.5 und die Hinterseite bei z = -2.5. In x-/y-Richtung sind die Koordinaten ±0.5. Projizieren wir diese Eckpunkte mit unserer Standardkamera, ergeben sich die grünen Pixel auf dem 32×32-Pixel Schirm. Man erkennt die typische perspektivische Verzerrung, weil die Punkte der Hinterseite näher zur Bildschirmmitte hin abgebildet werden.

Diskussion
Das richtige Einfärben der Pixel des Pixelrasters je nach Szene hat dieser Methode den Namen Rasterung gegeben (die Schattierung wird noch etwas dauern).
Die Projektion erfolgt im Wesentlichen mittels Division durch die z-Koordinate eines Punktes (später werden wir die w-Koordinate verwenden). Das ist eine nichtlineare Operation. Obwohl z.B. OpenGL Projektionsmatrizen kennt (und wir die auch noch verwenden werden), die tatsächliche Zentralprojektion kann nicht durch eine Matrix-Punkt-Multiplikation erreicht werden.
Eigentlich wollte ich auch noch den entsprechenden Java-Code besprechen, aber das verschiebe ich auf den nächsten Teil.
Benötigte Mathematik bisher:
Strahlensatz, Grundrechnungsarten, Abrunden von Dezimalzahlen zu Ganzzahlen.