Die neue Computergeneration schaffte neue Sehgewohnheiten in Form von oft atemraubenden 3D-Grafiken und -Animationen. In diesem vierteiligen Kurs lernen Sie, wie Sie Ihrem Atari ST zum Sprung in die dritte Dimension verhelfen.
Als Handwerkszeug benötigen Sie lediglich das Turbo-C-Entwicklungspaket von Borland, mit dem alle Beispielprogramme entstanden sind. Diese arbeiten in allen Grafikauflösungen. Das Entwicklungspaket ist jedoch nicht bindend erforderlich, da sich alle Programme auch ablauffähig auf der TOS-Diskette befinden. Neben minimalen Mathematik-Kenntnissen setzen wir auch etwas C-Know-How voraus. Es wurde bewußt weitgehend auf die komplizierte Matrizendarstellung und mathematische Herleitungen verzichtet, auch das komplizierte Raytracing klammern wir aus. In diesem Kursteil weihen wir Sie in die Grundlagen der dreidimensionalen Grafik ein, besprechen die Realisierung einfacher Vektorgrafiken und zeigen diese anhand eines kleinen Programms, das übrigens die im Artikel »Genormte Grafikwelt« (TOS 10 und 11 /90) besprochenen BGI-Grafikfunktionen verwendet.
In der Welt der Computergrafik bewegen wir uns auf drei Achsen: links/rechts, vor/zurück und hoch/ runter. Möchten wir eine bestimmte Position in dieser Welt beschreiben, so müssen wir die Stellungen auf jeder der drei Achsen eindeutig definieren. Hierzu legen wir an jeder Achse eine Skala an. Die drei Skalenwerte sind dann die Koordinaten der Position.
Die dreidimensionalen Grafiken, die wir in diesem Lehrgang entwerfen, bestehen stets aus einer Reihe von Objekten, die sich wiederum aus einer Anzahl von Kanten bzw. Flächen zusammensetzen. Deren Endpunkte bzw. Ecken sind jeweils eindeutig durch Koordinaten festgelegt.
Kommen wir nochmals auf die drei Dimensionen zurück. Wie Sie vielleicht noch aus dem Mathematikunterricht wissen, wird jede der drei Achsen mit einem Buchstaben gekennzeichnet. Die links/rechts-Dimension ist die x-Achse, hoch/ runter die y-Achse und vor/zurück die z-Achse. Ein Punkt P wird dann in der Form P(x;y;z) festgelegt, wobei wir für x, y, und z die entsprechenden Koordinaten einsetzen. Diese können auch negativ sein, zum Beispiel P(2;-4;11). Der Mittelpunkt des dreidimensionalen Universums mit den Koordinaten (0;0;0) heißt »Ursprung«. Möchten wir von ihm zum Punkt P(2; -4;11) gelangen, so müssen wir zwei Schritte nach rechts, vier nach unten und elf nach vorne in die Tiefe gehen.
Wie aber können wir dreidimensionale Positionen zeichnerisch darstellen? Die ersten beiden Dimensionen lassen sich problemlos auf dem Bildschirm oder einem Blatt Papier zeichnen, indem wir ein rechtwinkliges Koordinatensystem einführen, bei welchem die x-Achse von links nach rechts und die rechtwinklig angeordnete y-Achse von unten nach oben verläuft. Damit sind die zwei Dimensionen unseres Darstellungsmediums allerdings schon ausgelastet, die dritte Achse müßte quasi in den Bildschirm bzw. in das Papier hinein verlaufen.
In der Mathematik hilft man sich mit dem dreidimensionalen, kartesischen Koordinatensystem. In diesem verläuft die z-Achse diagonal zwischen den x - und y-Achsen von links unten nach rechts oben. Möchten Sie beispielsweise den Punkt P(2;1;3) darstellen, so starten Sie im Ursprung, bewegen den Stift um zwei Einheiten nach rechts, eine Einheit nach oben, drei Einheiten nach oben rechts und tragen nun den Punkt ein. Einfache Objekte wie Dreioder Vierecke stellen wir dar, indem wir die Eckpunkte auf die genannte Weise eintragen und die entsprechenden Ecken durch Kanten verbinden. Stellen wir zwei Flächen dar, die sich nur durch ihre z-Koordinaten unterscheiden, so bemerken wir, daß eine der Flächen nach oben rechts versetzt ist.
Wir erhalten also einen Aufblick von rechts oben auf unseren Körper. Das dreidimensionale kartesische Koordinatensystem ist leicht durchschaubar und eignet sich daher sehr gut zur manuellen Darstellung auf dem Papier und Entwurf von Objekten. Bei der Bildschirmdarstellung nimmt uns der Computer die Arbeit ab. Deshalb nutzen wir ein anderes, komplizierteres Koordinatensystem, das viel mehr Realismus vermittelt. Hierbei orientieren wir uns an den üblichen Sehgewohnheiten. Wir wissen, daß ein entferntes Objekt kleiner erscheint. Unterstützt von den stereoskopischen Sehfähigkeiten können wir sehr genau feststellen, wie weit ein Körper entfernt ist. Während stereoskopische Bilder nur mit größerem Aufwand zu realisieren sind, läßt sich eine Tiefendarstellung mit entfernungsabhängiger Darstellungsgrösse, die sogenannte Zentralperspektive, leicht realisieren.
Werfen wir hierzu einen Blick auf Bild 2, das die Szenerie in Vogelperspektive zeigt. Wir sehen Kamera K, die auf dem Bildschirm B die Projektion des Objektes O aufnimmt. Deutlich ist der fiktive Lichtstrahl vom Objekt O über den Bildschirm B zur Kamera K zu sehen. Dieser bildet zusammen mit der z-Achse ein spitzes Dreieck. Nehmen wir an, uns wären die x- und z-Koordinaten des Objektes und die (negative) z-Koordinate der Kamera (Augabstand) bekannt. Nun möchten wir wissen, welche x-Koordinate die Projektion von O auf dem Bildschirm (z=0) besitzt. Da zwei ähnliche Dreiecke vorliegen, bedienen wir uns zur Lösung dieses Problemes des Strahlensatzes. Dieser besagt, daß die Seitenverhältnisse zweier ähnlicher Dreiecke stets identisch sind. Betrachten wir zunächst das kleine Dreieck: Eine Seitenlänge ist die x-Koordinate des Bildes B, nämlich xB, die zweite der Abstand zwischen Ursprung und der Kamera -z«, das Verhältnis ist also xB/-zK. Die entsprechenden Seitenlängen des großen Dreiecks sind die x-Koordinate des Objektes xO und der Abstand zwischen Objekt und Kamera zO-zK, woraus sich das Verhältnis xO/(zO-zK) ergibt. Laut Strahlensatz gilt:
xB/-zK = xO/(zO-zK)
Die x-Koordinate des Bildes ist also:
xB = -(xO*zK)/(zO-zK)
In der yz-Ebene ergibt sich die abgewandelte Formel:
yB = -(yO*zK)/(zO-zK)
Aus dieser Formel ist zu erkennen, daß bei wachsendem Abstand des Körpers zO der Nenner des Bruches größer wird, weshalb die Projektionskoordinate xB bzw. yB geringer wird, das Bild also kleiner erscheint. Somit ist die Zentral Perspektive realisiert.
Betrachten wir das auf der TOS-Diskette enthaltene Demoprogramm »3D_1.C«. Starten Sie zunächst die zO Programmdatei »3D_1.PRG«. Auf dem Bildschirm erscheint, wie in Bild 3 zu sehen, eine vierseitige Pyramide in Zentralperspektive. Mit den Tasten a bzw. A können wir den Augabstand verringern bzw. erhöhen. Wie Sie sehen, erscheint das Bild bei kleinerem Augabstand stärker verzerrt, es entsteht ein »Weitwinkeleffekt« wie beim Fotografieren. Mit dem Augabstand, der in unserem Beispiel anfangsaufeinen »Normalwert« von -450 gesetzt wird, verändern wir das Erscheinungsbild der Grafik. Mit den Tasten 4 und 6 auf der Zahlentastatur können Sie die Pyramide nach links bzw. rechts bewegen (x-Achse), mit 8 und 2 nach oben bzw. unten (y-Achse) und mit - und ] weiter in die Ferne bzw. Nähe verschieben (z-Achse). Bei Änderung der z-Position bemerken Sie die Größenänderung.
Werfen wir nun einen ersten Blick auf den Programmtext. Die Pyramide besteht einfach aus sechs Kanten, die wiederum jeweils durch die x-, y - und z-Koordinaten ihrer beiden Eckpunkte festgelegt wurden. Dies geschah in dem zweidimensionalen double-Feld »k[KANTEN][6]«. So bestimmen die ersten sechs Koordinaten [ -40,-20,-10,30,-30,-20 ] die Kante von P1 (-40,-20,-10) zu P2(30,-30,-20). Legen Sie doch einmal einen neuen Körper im Quelltext fest. Die Koordinaten sollten jeweils im Bereich von -50 bis +50 liegen. Auch die Kantenzahl ändern Sie, indem Sie »#define KANTEN 6«-Deklaration entsprechend abwandeln und neue Koordinatenzeilen hinzufügen. Die Position des Objektes wird in den Variablen »xpos«, »ypos« und »zpos« gespeichert, die »k[]«-Koordinaten bleiben stets unangetastet. In der »projection«-Funktion erfolgt die Verschiebung des Objektes durch Addition der Koordinaten mit den »..pos«-Werten und die Projektion in das 2D-System, wobei wir folgende Gleichungen verwenden:
distance = z+zpos — (double) auge;
/* Abstand des Punktes */
*px=xcenter + (int)(((double)-auge*x/distance)+xpos)*xscale;
*py=ycenter -- (int) (((double)-auge*y/distance)+ypos)*yscale;
Zunächst ermitteln wir den Abstand zwischen Kamera und Auge, zu dem wir die z-Position des Objektes »zpos« addieren, und wenden darauf den Strahlensatz an. Auch hierbei werden jeweils die aktuellen Positions-Koordinaten »xpos« bzw. »ypos« addiert, damit das Objekt am rechten Ort erscheint. Die Multiplikation mit »..scale« dient der Anpassung an alle Grafikauflösungen. Anschließend addieren wir »..center«, damit der Ursprung in der Bildschirmmitte liegt. Diese Variablen sind in der Funktion »init_all« initialisiert.
Die Darstellung des kompletten Objektes ist denkbar einfach. In der »draw_all«-Funktion wandelt das Programm in einer for-Schleife alle 3D-Koordinaten per »projection«-Aufruf in 2D-Werte um und zeichnet die zugehörigen Kanten per »line«-Funktion. Schon sind wir imstande, dreidimensionale Grafiken aus einzelnen Kanten zu erzeugen, oft als Vektorgrafiken bezeichnet. Im nächsten Teil werden wir diese drehen, komplexere Objekte aufbauen und eine fiktive Kamera einführen, mit der wir uns in der 3D-Welt bewegen. (ah)
Teil 1: Grundlagen □ Gittergrafik □ einfaches Programmbeispiel
Teil 2: 3D-Datenstruktur □ Kamera □ scriptfähiges Programmgerüst
Teil 3: Versteckte Linien □ Schattierung □ Programmerweiterung
Teil 4: Generator für komplexe Objekte □ Ausblick