Skript, entstanden im Rahmen des Pro-Seminars
Transcription
Skript, entstanden im Rahmen des Pro-Seminars
Pro-Seminar Computergrafik Christopher Keiner, Kai Lawonn, Tobias Pfeiffer, Jacqueline Spexard, Christoph Sackl, Jonas Fehr, Selimkhan Achmerzaev Betreuer: Dr. Ingrid Hotz, Cornelia Auer, Jan Reininghaus, Andrea Kratz Berlin, 18. Januar 2008 Inhaltsverzeichnis 1 Raster-Algorithmen am Beispiel der digitalen Typografie 6 1.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.2 Ausgabegeräte . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.2.1 Klassifizierung . . . . . . . . . . . . . . . . . . . . . . . 8 1.2.2 Framebuffer . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3 Fitting-Algorithmen . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.4 Liniensegment-Rasterung . . . . . . . . . . . . . . . . . . . . . . 10 1.4.1 Bresenham Algorithmus . . . . . . . . . . . . . . . . . . 11 1.4.2 Symmetric Double Step Algorithmus von Wu . . . . . . . 14 Füll-Algorithmen . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.5.1 Boundary Fill-Algorithmus . . . . . . . . . . . . . . . . . 15 1.5.2 Flood Fill-Algorithmus . . . . . . . . . . . . . . . . . . . 16 Polygon-Rasterung . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.6.1 Charakterisierung von Polygonen . . . . . . . . . . . . . 16 1.6.2 Scan Line-Algorithmus . . . . . . . . . . . . . . . . . . . 17 Transformation eines Bildes . . . . . . . . . . . . . . . . . . . . 18 1.7.1 Skalierung . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.7.2 Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Dithering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 1.8.1 Farbrepräsentation . . . . . . . . . . . . . . . . . . . . . 23 1.8.2 Color Look Up Table . . . . . . . . . . . . . . . . . . . . 23 1.8.3 Ordered Dithering mit Fehlerstreuung . . . . . . . . . . . 23 Aliasing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 1.9.1 Objektbasiertes Anti-Aliasing . . . . . . . . . . . . . . . 25 1.9.2 Subpixel Rendering . . . . . . . . . . . . . . . . . . . . . 26 1.5 1.6 1.7 1.8 1.9 1 INHALTSVERZEICHNIS 2 Shading 29 2.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 2.2 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.2.1 Lichtausbreitung . . . . . . . . . . . . . . . . . . . . . . 30 2.2.2 Lichtquellenmodelle . . . . . . . . . . . . . . . . . . . . 33 Lokale Beleuchtungsmodelle . . . . . . . . . . . . . . . . . . . . 34 2.3.1 Lambert-Beleuchtungsmodell . . . . . . . . . . . . . . . 34 2.3.2 Phong-Beleuchtungsmodell . . . . . . . . . . . . . . . . 34 Schattierungsverfahren . . . . . . . . . . . . . . . . . . . . . . . 35 2.4.1 Flat-Shading . . . . . . . . . . . . . . . . . . . . . . . . 35 2.4.2 Gouraud-Shading . . . . . . . . . . . . . . . . . . . . . . 37 2.4.3 Phong-Shading . . . . . . . . . . . . . . . . . . . . . . . 41 2.4.4 Berechnung . . . . . . . . . . . . . . . . . . . . . . . . . 43 2.4.5 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . 44 Cool-to-Warm Shading . . . . . . . . . . . . . . . . . . . . . . . 45 2.5.1 Berechnung . . . . . . . . . . . . . . . . . . . . . . . . . 45 2.5.2 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . 47 Diskussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 2.6.1 Geschichte des Lichtes . . . . . . . . . . . . . . . . . . . 47 2.6.2 Problematik . . . . . . . . . . . . . . . . . . . . . . . . . 48 2.6.3 Warum nicht physikalisch exakt? . . . . . . . . . . . . . 48 2.6.4 Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Anhang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 2.7.1 Vektoren . . . . . . . . . . . . . . . . . . . . . . . . . . 49 2.7.2 Farbwerte . . . . . . . . . . . . . . . . . . . . . . . . . . 50 2.7.3 Baryzentrische Koordinaten . . . . . . . . . . . . . . . . 51 2.3 2.4 2.5 2.6 2.7 3 2 Raytracing 53 3.1 Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.2 Grundlagen des Renderings . . . . . . . . . . . . . . . . . . . . . 53 3.3 Das Raytracing-Verfahren . . . . . . . . . . . . . . . . . . . . . 55 3.3.1 Schnittpunkt- und Normalenbestimmung . . . . . . . . . 56 3.3.2 Farbbestimmung eines Punktes . . . . . . . . . . . . . . . 59 Laufzeitbetrachtungen und Optimierung . . . . . . . . . . . . . . 67 3.4.1 Analyse der Laufzeit . . . . . . . . . . . . . . . . . . . . 67 3.4.2 Verbesserungen der Laufzeit . . . . . . . . . . . . . . . . 67 3.4 2 INHALTSVERZEICHNIS 3.5 4 Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Geometric Modelling: Approximation und Interpolation von Kurven und Flächen. Von Flächen zu Objekten 72 4.1 Bezierkurven . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 4.1.1 Renault auf dem Vormarsch . . . . . . . . . . . . . . . . 72 4.1.2 Wie entstehen Bezierkurven? . . . . . . . . . . . . . . . . 73 4.1.3 Nachteile der Bezierkurven . . . . . . . . . . . . . . . . . 78 B-Splines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 4.2.1 Mit Schiffen fing alles an . . . . . . . . . . . . . . . . . . 79 4.2.2 Definition von B-Splines . . . . . . . . . . . . . . . . . . 79 4.2.3 Uniform-B-Splines . . . . . . . . . . . . . . . . . . . . . 80 4.2.4 Non-uniform B-Splines . . . . . . . . . . . . . . . . . . . 82 4.2.5 Zusammengefasst . . . . . . . . . . . . . . . . . . . . . . 85 4.3 NURBS (non-uniform rational B-Splines) . . . . . . . . . . . . . 86 4.4 Von Kurven zu Flächen . . . . . . . . . . . . . . . . . . . . . . . 87 4.4.1 Biliniar Patches . . . . . . . . . . . . . . . . . . . . . . . 87 4.4.2 Bilinearly Blended Surfaces . . . . . . . . . . . . . . . . 90 Von Flächen zu Objekten . . . . . . . . . . . . . . . . . . . . . . 91 4.2 4.5 5 3 Grafikkarten und GPU-Programmierung 92 5.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 5.2 Die Grafikkarte . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 5.2.1 Entwicklung der Grafikkarte . . . . . . . . . . . . . . . . 93 5.2.2 Eine moderne Highend-Grafikkarte . . . . . . . . . . . . 94 5.3 Grafik-Programmierung . . . . . . . . . . . . . . . . . . . . . . . 96 5.4 Koordinatensysteme . . . . . . . . . . . . . . . . . . . . . . . . . 97 5.4.1 Object Space . . . . . . . . . . . . . . . . . . . . . . . . 97 5.4.2 World Space und Eye Space . . . . . . . . . . . . . . . . 97 5.4.3 Clip Space . . . . . . . . . . . . . . . . . . . . . . . . . 98 5.4.4 Window Space . . . . . . . . . . . . . . . . . . . . . . . 99 Die klassische Grafik-Pipeline . . . . . . . . . . . . . . . . . . . 99 5.5 5.6 5.5.1 Geometrieoperationen . . . . . . . . . . . . . . . . . . . 100 5.5.2 Pixeloperationen . . . . . . . . . . . . . . . . . . . . . . 102 Die Unified-Shader Architektur . . . . . . . . . . . . . . . . . . . 103 5.6.1 Das Shader Model . . . . . . . . . . . . . . . . . . . . . 105 5.6.2 Shader Programmierung . . . . . . . . . . . . . . . . . . 106 3 INHALTSVERZEICHNIS 5.7 5.8 6 4 5.6.3 Vertex- und Fragment-Shader . . . . . . . . . . . . . . . 107 5.6.4 Geometry-Shader . . . . . . . . . . . . . . . . . . . . . . 109 General Purpose Computation on GPUs . . . . . . . . . . . . . . 110 5.7.1 Nutzung des skalaren Prozessor Designs . . . . . . . . . . 111 5.7.2 GPGPU in der Praxis . . . . . . . . . . . . . . . . . . . . 112 5.7.3 Compute Unified Device Architecture . . . . . . . . . . . 113 5.7.4 Diskussion . . . . . . . . . . . . . . . . . . . . . . . . . 114 Fazit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 Computer Animation 6.1 6.2 116 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 6.1.1 Was ist Animation? . . . . . . . . . . . . . . . . . . . . . 116 6.1.2 Klassische Animationstechniken . . . . . . . . . . . . . . 116 Computer Animation - Einleitung zur 3D-Animation . . . . . . . 118 6.2.1 Rigid Body Animation . . . . . . . . . . . . . . . . . . . 119 6.3 Key-Framing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 6.4 Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 6.4.1 Interpolation von parametrischen Kurven . . . . . . . . . 123 6.4.2 Dynamik von Bewegungen . . . . . . . . . . . . . . . . . 125 6.5 Animations-Zyklen . . . . . . . . . . . . . . . . . . . . . . . . . 126 6.6 Hierarchische Modelle und Kinematik . . . . . . . . . . . . . . . 127 6.7 Charakter Animation mit Skelett-Modell . . . . . . . . . . . . . . 131 6.8 Kollisions-Erkennung . . . . . . . . . . . . . . . . . . . . . . . . 132 6.9 Deformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 6.9.1 Globale Deformation . . . . . . . . . . . . . . . . . . . . 134 6.9.2 Free Form Deformation . . . . . . . . . . . . . . . . . . 135 6.9.3 Animierte Deformation . . . . . . . . . . . . . . . . . . . 136 6.10 Gesichts-Animation . . . . . . . . . . . . . . . . . . . . . . . . . 136 7 Image-Based Rendering 138 7.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 7.2 Light Field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 7.3 7.2.1 Sampling . . . . . . . . . . . . . . . . . . . . . . . . . . 141 7.2.2 Technische Probleme . . . . . . . . . . . . . . . . . . . . 142 7.2.3 Resampling / Erzeugen von neuen Bildern . . . . . . . . . 143 7.2.4 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . 143 View Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . 144 4 INHALTSVERZEICHNIS 7.4 5 7.3.1 Pixel Interpolation . . . . . . . . . . . . . . . . . . . . . 145 7.3.2 Probleme . . . . . . . . . . . . . . . . . . . . . . . . . . 146 7.3.3 Lösung . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 7.3.4 Beispiele . . . . . . . . . . . . . . . . . . . . . . . . . . 147 7.3.5 Beipiel aus der Filmindustrie . . . . . . . . . . . . . . . . 148 7.3.6 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . 148 Image Based Lighting mit High Dynamic Range Images . . . . . 149 7.4.1 Light Probes . . . . . . . . . . . . . . . . . . . . . . . . 152 7.4.2 Environment Mapping . . . . . . . . . . . . . . . . . . . 153 7.4.3 Beispiele . . . . . . . . . . . . . . . . . . . . . . . . . . 154 7.4.4 Einsatz von IBL in der Industrie . . . . . . . . . . . . . . 155 7.4.5 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . 156 Literaturverzeichnis 156 5 Kapitel 1 Raster-Algorithmen am Beispiel der digitalen Typografie Christopher Keiner 1.1 Einleitung Die Ausarbeitung thematisiert Raster-Algorithmen am Beispiel der digitalen Typografie. Die Rasterung ist ein Teilgebiet der Computergrafik und betrifft den Bereich der Grafikausgabe. Viele Ausgabegeräte benutzen als Grundelemente Pixel, die einen farbigen Bildpunkt repräsentieren. Ein Pixel muss aus technischen Gegebenheiten eine spezifische Größe besitzen. Die Ausgabefläche besteht aus einer Menge dieser Pixel und kann wegen der spezifischen Größe der Pixel als Raster aufgefasst werden. Dies ist das Grundproblem der Rasterung. Das Gebiet der Rasterung bietet Lösungsansätze für Probleme, die durch das Arbeiten auf diesem Raster entstehen um eine Grafik auszugeben. Die Ausarbeitung beschreibt verschiedene Probleme des Rasterns und zeigt mögliche Lösungsansätze zu den Problemen. Dabei orientiert sich die Ausarbeitung an einem Beispiel aus der digitalen Typografie. Typografie umfasst Richtlinien und Regeln, die bei der Gestaltung von Texten relevant sind. Diese Richtlinien umfassen z.B. die Schrifttypen, die Schriftgröße oder Zeichenabstände. Die Typografie beinhaltet aber auch die Wahl des Papieres oder die Gewohnheiten eines Lesers. Um diese Weitläufigkeit einzuschränken, 6 1.1. EINLEITUNG 7 unterteilt sich die Typografie in eine mikro- und eine makrotypografische Sicht. Die Makrotypografie konzentriert sich auf die Gestaltung des Textes als große Einheit. Die Mikrotypografie beschränkt sich hingegen auf die Gestaltung einzelner Zeichen und Worte. Die Richtlinien gelten ebenfalls für digitale Texte. Das Ziel der Typografie ist dabei eine optimale Lesbarkeit sowie Gestaltung eines Textes zu erreichen. Die Mikrotypografie und das Gebiet der Rasterung sind bei digitalen Texten eng verbunden. Die Lesbarkeit und Gestaltung ist dabei in erster Linie von der Qualität der Rasterung abhängig. Die Erzeugung von Zeichen wird im Computerbereich durch einen sog. Font-Rasterizer realisiert. Die zu rasternden Zeichen werden in diesem Zusammenhang als Glyphen bezeichnet. Die Aufgaben und Abläufe eines Font-Rasterizers werden nun exemplarisch anhand des TrueType-Rasterizers [Mic07] kurz vorgestellt. Die Hauptaufgabe besteht darin einen übergebenen String in ein Bitmap umzuwandeln. Dazu sind die folgenden Schritte notwendig: 1. Die Umrisse des Glyphen werden aus dem TrueType Format ausgelesen. Die Umrisse werden als Gleichungen von Liniensegmenten und Splines gespeichert. 2. Im nächsten Schritt werden die Umrisse auf die gewünschte Größe skaliert. Hierfür werden die Linien und Splines durch die mathematischen Gleichungen transformiert. 3. Die Umrisse müssen als nächstes am Raster ausgerichtet werden um eine optimale Qualität zu erreichen. Um dies zu erreichen kann ein Glyph verschoben und gestreckt werden. 4. Im letzten Schritt wird der Buchstabe als Bitmap gerastert. Die Ausarbeitung unterteilt sich in vier Themengebiete und ordnet die Themen möglichen Aufgaben eines Font-Rasterizers zu. Das erste Themengebiet umfasst Abschnitt 1.2 und stellt mögliche Ausgabegeräte vor. Es wird der Framebuffer vorgestellt, der eine Abstraktion dieser Ausgabegeräte darstellt. Das zweite Themengebiet befasst sich mit dem sogenannten Fitting-Problem, bei dem eine optimale Ausrichtung eines Objekts an das Raster gefunden werden muss. Abschnitt 1.3 stellt eine Lösung vor, die das TrueType Format benutzt. Das dritte Themengebiet beschäftigt sich mit dem Rastern von geometrischen Figuren. Die Abschnitte 1.4, 1.5, 1.6 stellen Algorithmen vor, die zum Rastern von 7 1.2. AUSGABEGERÄTE 8 Objekten benutzt werden können und korrespondiert mit dem vierten Schritt des TrueType Rasterizers. Das letzte Themengebiet umfasst die Abschnitte 1.7, 1.8, 1.9 und stellt Optimierungsansätze beim Rastern vor. Abschnitt 1.7 bietet auch Ansätze zur Transformation von Koordinaten, die im zweiten Schritt des TrueType-Rasterizers benötigt werden. 1.2 Ausgabegeräte In diesem Abschnitt werden verschiedene Ausgabegeräte vorgestellt. Um das Problem des Rasterns allgemeiner betrachten zu können, werden die Ausgabegeräte klassifiziert und anschließend durch den sogenannten Framebuffer abstrahiert. 1.2.1 Klassifizierung Eine Vielzahl von physikalischen/virtuellen Geräten kann als Ausgabegerät dienen: • Monitor (CRT, LCD) • Drucker, Pen Plotter • Beamer, Laser-Projektoren • Fernsehgeräte • Ausgabe als digitales Bild • ... Die Geräte lassen sich in zwei Klassen unterteilen, um generellere Aussagen über Ausgabegeräte zu finden. 1. Vektorbasierte Geräte Die Ausgabedaten dieser Geräteklasse liegen als Befehlsfolge vor. Durch die Abarbeitung der Befehle entsteht die Ausgabe. In diese Klasse fallen z.B Oszilloskope, Pen-Plotter oder Laserprojektoren. Der Befehlsvorrat umfasst meist verschiedene Bewegungsvorgänge, sowie das Aktivieren/Deaktivieren des Ausgabemechanismus. 8 1.2. AUSGABEGERÄTE 9 2. Pixelorientierte Geräte Die Ausgabedaten liegen in dieser Geräteklasse als Datenfolge aus Pixeln vor. Diese Daten beinhalten die Koordinaten und die Farbe an dieser Stelle. Im Gegensatz zu vektorbasierten Geräten werden die Daten sequentiell in einer festgelegten Reihenfolge sichtbar gemacht. In diese Klasse fallen z.B. Monitore, Beamer oder Bilder. Die Klasse der vektorbasierten Geräte umgeht im Gegensatz zu den pixelorientierten Geräten das Problem des Rasterns. Die Anzahl der vektorbasierten Geräte ist aber sehr gering. Geräte für den Normalbenutzer fallen in die pixelorientierte Klasse. Aus diesem Grund wird im Folgenden nur auf die Klasse der pixelorientierten Geräte eingegangen. 1.2.2 Framebuffer Es bestehen viele Gemeinsamkeiten der pixelorientierten Geräte. • Die Ausgabefläche besteht aus einer Menge von angeordneten, adressierbaren Pixel. • Die Auflösung (width × height) eines Gerätes spezifiert die Anzahl der Pixel und die Größe der Ausgabefläche. • Die Farbtiefe spezifiziert die Bitanzahl, die für die Speicherung einer Farbe verwendet werden. Die Farbtiefe gibt ebenfalls die Anzahl an Farben an, die angezeigt oder gespeichert werden können. Die Abstraktion eines Gerätes ist durch den Framebuffer gegeben. Der Framebuffer besteht aus einem Speicherbereich für width × height Pixeln. Diese Pixel lassen sich gezielt manipulieren. Dazu werden Operationen zum Erfragen und Setzen der Farbe angeboten. Der Framebuffer dient als Schnittstelle zwischen Algorithmen und Ausgabegerät, welches die Daten aus dem Framebuffer anzeigen kann. Das Raster-Problem kann nun losgelöst von den Ausgabegeräten betrachtet werden. Abschnitt 1.8 thematisiert später ein Problem, dass durch diese Loslösung entstehen kann. Das Problem entsteht, wenn eine Reduzierung der Farbanzahl zur Ausgabe auf dem Ausgabegerät notwendig ist. 9 1.3. FITTING-ALGORITHMEN 1.3 10 Fitting-Algorithmen Durch einen Fitting-Algorithmus findet eine Optimierung vor dem eigentlichen Rastern statt. Dabei wird das zu rasternde Objekt am Raster des Framebuffers ausgerichtet. Ziel des Algorithmus ist es, eine optimale Überdeckung zwischen den Punkten des Rasters und dem Objekt zu finden. Es ist wichtig, möglichst viele Punkte des Objekts in das Raster zu übertragen, da ansonsten das gerasterte Objekt stark von der Vorlage abweicht. Am Beispiel der Typografie wird durch eine schlechte Überdeckung der Glyph verzerrt und das Lesen wird dadurch erschwert. Deshalb versucht die Typografie durch das Setzen von Glyphen die Lesbarkeit eines Textes zu verbessert. Beispielsweise werden Buchstaben in bestimmten Situationen enger zusammen oder weiter auseinander gesetzt. Ein Beispiel hier für ist die Verwendung von Ligaturen oder das Vermeiden von Glyphenkollisionen. Die Ziele der Typografie und des Rasterns können im Gegensatz zueinander stehen. Es ist ein Kompromis nötig um eine gute Lesbarkeit zu gewähren. Eine Ausrichtung am Raster ist durch mathematische Berechnungen mit Hilfe einer sog. Fehlermatrix möglich. Das richtige Setzen von Glyphen hingegen ist schwierig, da durch zahlreiche unterschiedliche Situationen eine große Komplexität erreicht wird. Das TrueType-Format nutzt die Erfahrung und Intelligenz des Typographen. Der Gestalter einer Schriftart gibt explizit bei der Erstellung der Schrift Abstände von Glyphen an. Die Abstände können bei der Rasterung genutzt werden, um eine gute Qualität des Glyphen zu erreichen. 1.4 Liniensegment-Rasterung Punkte, Liniensegmente und Polygone bilden die Primitive der Computergrafik. Diese bilden die Grundlage für komplexere Modelle und Anwendungen. Jede mögliche geometrische Struktur kann in Punkte, Linien und Polygone zerlegt werden. Daher ist es wichtig diese Elemente möglichst effizient zu rastern. Meistens wird das Rastern von Primitiven durch Hardware unterstützt, die aber wiederum auf einem Algorithmus basiert. In diesem Abschnitt werden zwei Algorithmen zum Rastern von Liniensegmenten vorgestellt. Der Bresenham-Algorithmus ist ein bekannter Line-Drawing-Algorithmus, der in vielen Bereichen Anwendung findet. Der Symmetric Double Step Algorithmus soll die effiziente Ausutzung von Symmetrien zeigen. 10 1.4. LINIENSEGMENT-RASTERUNG 11 In der Einleitung wurde erläutert, dass die Umrisse aus Liniensegmenten und Splines gespeichert werden. Ein Aufgabenfeld der folgenden Algorithmen ist diese Umrisse eines Textes darzustellen. Auf die Verarbeitung von Splines wird nicht weiter eingegangen. Eine Spline-Kurve kann durch Linien approximiert werden. Somit ist es denkbar, einen Glyphen nur mit den folgenden Algorithmen zu rastern. 1.4.1 Bresenham Algorithmus Der Bresenham Algorithmus ist 1965 vom gleichnamigen Programmierer entwickelt worden. Bei der Entwicklung hat die Effizenz eine hohe Priorität eingenommen. Der Algorithmus arbeitet ausschließlich mit schnellen Integer Berechnungen und vermeidet hierbei ebenfalls weitgehend die Multiplikation und die Division. Zu Beginn soll ein allgemeines Verfahren vorgestellt werden, mit dem eine Linie gerastert werden kann. Aufbauend auf diesem Verfahren soll der BresenhamAlgorithmus erläutert werden. Allgemeine Arbeitsweise und Sampling Dieser Abschnitt stellt das allgemeine Vorgehen des Linien-Rasterns vor und wird ein allgemeines Problem aufzeigen, dass in anderen Algorithmen ebenfalls entsteht. Es wird vorausgesetzt, dass ein Liniensegment durch einen Anfangspunkt (x1 , y1 ) und einen Endpunkt (x2 , y2 ) gegeben ist. In mathematischer Sicht kann jeder Punkt, der auf der Linie liegt durch die Gleichung y = m · x + b mit m = y2 − y1 ∆x = und b = y1 − m · x1 x2 − x1 ∆y bestimmt werden. Im nächsten Schritt muss die Linie aus dem kartesischen Koordinatensystem der Mathematik auf die Koordinaten des Pixelbereichs übertragen werden. Ein Pixel besitzt im Gegensatz zum mathematischen Punkt eine spezifische Größe. Daraus folgt, dass ein Pixel einem Intervall der Linie zugeordnet ist. Es muss also für jede Pixelkoordinate stichprobenartig ein Wert zugeordnet werden. Dieser Prozess wird als Sampling bezeichnet und kann durch unterschiedliche Verfahren verbessert werden. Zur naiven Lösung genügt es zu jeder gegebenen x-Koordinate durch die Gleichung einen gerundeten Wert y zu berechnen. Jede Berechnung erfordert die Auswertung der Geradengleichung. Der Bresenham-Algorithmus umgeht dies, indem die nachfolgende Koordinate aus der 11 1.4. LINIENSEGMENT-RASTERUNG 12 Vorigen berechnet wird. Die y-Koordinaten lassen sich durch eine rekursive Gleichung beschreiben, in der die k+1-Koordinate durch Addieren der Steigung berechnet wird. 0 yk+1 = yk0 + m und y10 = y1 Abbildung 1.1: Line Rastering. Links wurde über x-Koordinate iteriert. Rechts wurde über die y-Koordinate iteriert. Eine Lösung des Linienrasterns besteht darin iterativ die Koordinaten (x1 , y10 ), ..., (xn , yn0 ) zu berechnen. Das Resultat (siehe Abb. 1.1) ist aber nicht befriedigend, da für eine Steigung m > 1 nicht genügend Sampling-Punkte vorhanden sind. Das Problem lässt sich beheben, indem für eine Steigung m > 1 über die y-Koordinate iteriert wird. Das Problem entsteht auch in anderen Zusammenhängen und wird im Folgenden nicht mehr explizit beschrieben. Ein Beispiel ist das später beschriebene Rastern von Polygonen. Vorgehen des Bresenham-Algorithmus Der Bresenham-Algorithmus baut auf dem obigen Konzept auf. Floating-PointWerte z.B. die Steigung m werden aus Effizienzgründen innerhalb der Iteration elimiert. Eine Fallunterscheidung über den Wert von m ist dazu essentiell. Exemplarisch wird die Idee des Bresenham-Algorithmus ausgehenden vom Startpunkt oder einem bereits berechnetem Punkt (xk , yk ) für 0 < m < 1 besprochen. Durch die Einschränkung der Steigung können für den Folgepunkt nur die Punkte 12 1.4. LINIENSEGMENT-RASTERUNG 13 (xk+1 , yk ) oder (xk+1 , yk + 1) in Frage kommen. Im Folgenden soll die Frage beantwortet werden, wie effizient entschieden werden kann, welcher Punkt der Orginal-Linie am nächsten liegt. d2 ? ? d1 Abbildung 1.2: Bresenham Algorithmus: Für den nächsten Pixel stehen zwei Folgepixel zur Wahl. Durch den Vergleich der Abstände d1 und d2 wird entschieden, welcher Punkt am nächsten zur Linie liegt. Dazu werden die Abstände zwischen Punkt und Linie berechnet und deren Differenz gebildet. Das Ziel wird sein, am Vorzeichen der Differenz d1 − d2 (siehe Abb. 1.2) abzulesen, welcher Punkt näher an der Linie liegt. Dazu wird ein rekursives Prädikat benötigt, dass während der Iteration aktualisiert werden kann. [HB97] ( pk+1 = pk + 2∆y für pk < 0 pk + 2∆y − 2∆x für pk ≥ 0 und p0 = 2∆y − ∆x Aus dem Prädikat pk kann die Entscheidung getroffen werden, welcher Pixel gerastert werden soll. Im Fall pk < 0 wird der untere Pixel gerastert. Der obere Pixel wird gerastert, wenn die Bedingung pk ≥ 0 erfüllt ist. Die Steigung 1 < m < ∞ kann nach dem gleichen Prinzip gerastert werden, indem die Iteration über die y-Koordinate erfolgt. Somit lassen sich alle Linien im ersten Quadranten des kartesischen Koordinatensystems rastern. Steigungen außerhalb dieses Bereichs können durch eine Vertauschung der 13 1.4. LINIENSEGMENT-RASTERUNG 14 Endpunkte, sowie durch die Ausnutzung der Symmetrie zur x-Achse auf das obige Problem zurückgeführt werden. 1.4.2 Symmetric Double Step Algorithmus von Wu In diesem Abschnitt wird ein weiterer Algorithmus zum Linien-Rastern vorgestellt. Der Double Step Algorithmus nutzt die gegebene Symmetrie einer Linie aus. Der Schwerpunkt der Betrachtung liegt auf diesem Vorgehen. Der Algorithmus basiert auf der Idee, dass ein Liniensegment auf Grund der Rasterung nur bestimmte Muster annehmen kann. Für eine Steigung 0 ≤ m ≤ 1 und einem Pixelabschnitt, der Länge 3, können nur die 4 Muster aus Abb. 1.3 in Frage kommen. Muster 1 Muster 2 Muster 3 Muster 4 Abbildung 1.3: Double Step Algorithmus: 4 mögliche Muster. Die Steigung einer Linie ist konstant. Somit kann im Vorfeld eine weitere Unterscheidung vorgenommen werden. 0 ≤ m ≤ 12 : Für diese Steigung kann Muster 4 ausgeschloßen werden. 1 2 ≤ m ≤ 1: Für diese Steigung kann Muster 1 ausgeschloßen werden. Es wird an dieser Stelle ebenfalls ein Prädikat gebraucht, das zwischen den drei verbleibenden Mustern wählt. Im Vergleich zum Bresenham-Algorithmus werden durch ein effizientes Prädikat mit einer Prädikatauswertung zwei Pixel gerastert. Der entscheidende Effizienzunterschied gegenüber dem Bresenham-Algorithmus wird durch die Ausnutzung der Symmetrie erreicht. Jedes Liniensegment ist zum Mittelpunkt drehsymmetrisch. Der Double Step Algorithmus rastert aus diesem Grund am gegenüberliegenden Endpunkt jeweils das symmetrische Gegenstück. 14 1.5. FÜLL-ALGORITHMEN 15 Die Ausnutzung der Symmetrie kann in vielen Fällen eine enorme Effizenzsteigerung bringen. In der Typografie sollte besonders auf die Symmetrien geachtet werden. Neben dem Effizenzgewinn kann das symmetrische Rastern das Schriftbild verbessern. Glyphen wirken durch das Raster nicht verzerrt und können somit die Lesbarkeit verbessern. 1.5 Füll-Algorithmen Im Anschluß an den letzten Abschnitt werden nun zwei Algorithmen vorgestellt, mit denen Flächen innerhalb der gerasterten Umrisse gefüllt werden können. Eine naive Lösung des Glyphen-Rastern könnte im Füllen der gezeichneten Umrisse bestehen. 1.5.1 Boundary Fill-Algorithmus Voraussetzung für diesen Algorithmus ist ein mit einer bekannten Farbe gerasterter Umriss. Desweiteren muss ein Startpunkt innerhalb dieser Umrisse gewählt werden. Die gesamte Fläche innerhalb der Grenzen wird neu eingefärbt. Es ist keine einheitliche Farbe der inneren Fläche vorausgesetzt. Der Algorithmus boundary fill(x,y) arbeitet nach folgendem rekursiven Schema: 1. Falls die Farbe des Pixels (x,y) mit der Farbe der Grenze oder mit der neuen Farbe übereinstimmt, wird an dieser Stelle die Methode verlassen. 2. Der Pixel (x,y) wird neu gefärbt 3. Rekursiv werden die Nachbarpixel gefärbt. boundary fill(x-1,y) boundary fill(x+1,y) boundary fill(x,y-1) boundary fill(x,y+1) Der Algorithmus kann durch rekursiven Aufruf der vier Diagonalrichtungen erweitert werden. (Siehe Abb. 1.4) 15 1.6. POLYGON-RASTERUNG 16 Abbildung 1.4: Boundary-Fill-Algorithmus: Der Algorithmus arbeitet rekursiv auf den anliegenden Nachbarn. Dabei können entweder vier oder alle acht Nachbarn benutzt werden. 1.5.2 Flood Fill-Algorithmus Der Flood-Fill Algorithmus ist eine Abwandlung des Boundary Algorithmus. Der Vorteil besteht darin, dass die zu füllende Fläche keine Umrisse besitzen muss. Der Algorithmus färbt stattdessen alle gleichfarbigen Pixel einer zusammenhängenden Fläche neu ein. Die Arbeitsweise unterscheidet sich nur im Rekursionsanker, der die Bedingung zum Abbruch der Methode darstellt. 1.6 Polygon-Rasterung Dieser Abschnitt beschäftigt sich mit dem Rastern von Polygonen und gliedert sich in zwei Unterabschnitte. Zu Beginn werden verschiedene Arten von Polygone klassifiziert. Jede Klasse von Polygonen hat bestimmte Eigenschaften. Die Einteilung in Klassen kann bei der Wahl des Algorithmus ausgenutzt werden, indem der Algorithmus die Eigenschaften des Polygons berücksichtigt und geeignet ausnutzt. Im zweiten Unterabschnitt wird ein Scan Line-Algorithmus vorgestellt, der es ermöglicht Glyphen und Polygone zu rastern. Ein Glyph kann ebenfalls als Polygon aufgefasst werden. Somit korresponiert dieser Abschnitt mit den Aufgaben des vierten Schritt des Font-Rasterizers. 1.6.1 Charakterisierung von Polygonen Ein Polygon lässt sich am einfachsten durch eine Folge von Eckpunkten beschreiben. Die Reihenfolge dieser Punkte beschreibt, zwischen welchen Punkten eine Kante verläuft. Abbildung 1.5 zeigt verschiedene Arten von Polygonen. Die verschiedenen Polygone lassen sich in Klassen einteilen. Diese sind nicht disjunkt. Eine mögliche Einteilung in verschiedene Klassen ist: 16 1.6. POLYGON-RASTERUNG 17 4 3 4 1 2 2 3 5 1 1 2 3 Abbildung 1.5: Verschiedene Polygonarten: Dreieck, nicht konvexes Polygon, konvexes Polygon (es existiert eine Verbindunglinie, die nicht innerhalb des Polygons verläuft), überlappendes Polygon Das einfachste Polygon ist das Dreieck. Jede beliebige Figur kann als Menge von Dreiecken approximiert werden. Dabei können neue Zwischenpunkte in die Figur eingefügt werden. Die Arbeit mit Dreiecken lässt sich stark optimieren, denn es gibt nur wenige Sonderfälle die beim Rastern eines Dreiecks auftreten können. DirectX lässt beispielsweise als Primitive nur Punkte, Linien und Dreiecke zu. Zwei weitere Klassen von Polygonen werden durch die Unterteilung in konvexe Polygone und nicht konvexe Polygone gebildet. Ein Polygon heißt konvex, falls alle möglichen Liniensegmente, ausgehend und endend auf dem Polygonrand, innerhalb des Polygons liegen. Ein Polygon wird als nicht-konvex bezeichnet, falls diese Bedingung nicht erfüllt ist (siehe Abb. 1.5). Eine weitere Eigenschaft eines Polygon ist die Überlappung und charakterisiert eine Klasse. Ein Polygon überlappt sich immer dann, wenn der Umriss des Polygons einen gemeinsamen Schnittpunkt besitzt. Die Menge aller Glyphen fallen in die Klassen der konvexen und nicht konvexen Polygone. Buchstaben sind aber nicht selbst überlappende Polygone. Der folgende Algorithmus ist in der Lage, diese Klasse zu rastern. 1.6.2 Scan Line-Algorithmus Ein Scan Line-Algorithmus arbeitet die Rasterung eines Polygons zeilenweise ab. Die aktuelle Zeile wird hierbei Scan Line genannt. Als erstes werden für jede Scan Line die Schnittpunkte mit dem Polygon berechnet. Die Schnittpunkte werden nach x-Koordinate sortiert. Es wird an dieser Stelle zwischen dem regulären Fall und einem Spezialfall entschieden. Im regulären Fall sind die Schnittpunkte keine 17 1.7. TRANSFORMATION EINES BILDES 18 Eckpunkte. Die Anzahl der Schnittpunkte ist gerade. Somit ist im regulären Fall an dieser Stelle klar, welches ein Eintritts- oder Austrittspunkt aus dem Polygon ist. Die Pixel zwischen Eintritts- und Austrittspunkt können nun gefärbt werden. Spezialfälle müssen erkannt und behandelt werden. Ein Spezialfall lässt sich z.B. durch die ungerade Anzahl an Schnittpunkten identifizieren. Dieser Fall tritt auf, wenn ein Schnittpunkt ebenfalls ein Eckpunkt des Polygons ist. Die Behandlung benötigt einen geeigneten Entscheidungsmechanismus. ? Pm ? Abbildung 1.6: Polygon Rasterung: Im regulären Fall (links) ist klar, welche Schnittpunkte Eintritts- oder Austrittspunkte sind. Ist ein Schnittpunkt zugleich Eckpunkt (rechts) muss durch die Monotonie entschieden werden, ob eine Linie gerastert werden soll. Eine einfache Lösung dieses Problems betrachtet die zwei angrenzenden Kanten des Punktes Pm . Diese zwei Kanten werden durch Pm und zwei weiteren Eckpunkten beschrieben. Durch einen Vergleich der y-Koordinaten dieser drei Punkte kann eine Aussage über die Monotonie der Kanten getroffen werden. Monotonie liegt vor, wenn alle drei y-Koordinaten in abnehmender oder steigender Größe vorliegen. Beim Vergleich ist die Reihenfolge der Eckpunkte relevant (siehe 1.6.1). Der Eckpunkt Pm bildet einen Extrempunkt relativ zur Scan Line, genau dann wenn keine Monotonie vorhanden ist. In diesem Fall ist Pm kein Schnittpunkt und wird zum Rastern nicht in Betracht gezogen. 1.7 Transformation eines Bildes In diesem Abschnitt werden zwei grundlegende Funktionen und Algorithmen zur Transformation eines Bildes vorgestellt. Diese Algorithmen fallen ebenfalls in den 18 1.7. TRANSFORMATION EINES BILDES 19 Bereich der Rasterung, da sie auf Pixelbereichen operieren. Eine Anwendung im typografischen Rastern liegt im Bereich der Embedded Systems. Kleine Systeme können wegen Resourcenknappheit Glyphen als vorgerasterte Bitmaps speichern. Damit entsteht die Notwendigkeit, einen Text aus diesen Bitmaps zusammenzustellen. Diese Schriften werden als Bitmap-Fonts bezeichnet. In den zwei Unterabschnitten werden die Skalierung und die Rotation vorgestellt. Die mathematischen Ansätze lassen sich auf die Koordinaten-Transformation übertragen und sind somit für den zweiten Schritt des TrueType-Rasterizers relevant. 1.7.1 Skalierung Die Skalierung eines Bildes um (sx , sy ) lässt sich durch eine skalare Multiplikation berechnen. x0 = s x · x y 0 = sy · y Diese Gleichung lässt sich in einer Matrix darstellen, die effizient vom Computer berechnet werden kann. sx 0 0 sy ! x y ! = x0 ! y0 Dieser geometrischer Ansatz setzt voraus, dass jeder Pixel einzeln transformiert wird. Die Transformation von Koordinaten ist durch die Matrixdarstellung effizient berechenbar. Die Veränderung der Farbwerte durch die Skalierung wird aber nicht beachtet. Der skalierte Pixelbereich kann dadurch große Farbflächen oder den Verlust von Informationen aufweisen (siehe Abb. 1.7). Das gleiche Problem wird im nächsten Abschnitt thematisiert. 1.7.2 Rotation Geometrischer Ansatz Die Rotation eines Bildes um einen Wert Θ lässt sich auf die Geometrie zurückführen. Eine einfache Lösung besteht darin, das Bild punktweise zu rotieren. x0 = x · cos(Θ) − y · sin(Θ) 19 1.7. TRANSFORMATION EINES BILDES 20 y 0 = y · sin(Θ) − x · cos(Θ) Diese Berechnung kann in Matrixdarstellung umgewandelt werden. cosΘ −sinΘ sinΘ ! x y cosΘ ! = x0 ! y0 Das Hauptproblem der Rotation (und auch der Skalierung) resultiert daraus, dass die meisten Ergebnisse keine Ganzzahlen sind und nicht direkt gerastert werden können. Die errechneten Pixel-Koordinaten können durch geeignete Rundungen den Koordinaten angepasst werden. Es ist jedoch darüber hinaus erforderlich die Farbwerte der Pixel entsprechend den durchgeführten Rundungen anzupassen. In Abbildung 1.7 überdeckt der rotierte Pixel vier andere Pixel auf dem Raster. Der Farbwert muss geeignet verteilt werden. Die Information des Bildes wird auf jeden Fall verfälscht. (0,0) (0,0) Abbildung 1.7: Beim Skalieren (links) entstehen große Farbflecken oder ein Fläche, die kleiner als ein Pixel sein kann. Beim Rotieren (rechts) entsteht das Problem, dass eine Farbe auf mehrere Pixel verteilt werden muss. Lösungsansätze für dieses Problem bietet die digitale Filterung. Es wird auf die Lösung nicht näher eingegangen, da dies weit aus dem Bereich der Rasterung raus führen würde. Im folgenden Algorithmus wird stattdessen exemplarisch eine Optimierung des Problems anhand der Rotation vorgestellt. 20 1.7. TRANSFORMATION EINES BILDES 21 Rotation durch Scheren Der Algorithmus basiert auf der Idee, eine Rotation durch Scher-Transformationen anzunähern. Eine Scher-Transformation kann in x- und y-Richtung geschehen. Durch die Multiplikation mit einer Streck-Matrix wird jeweils die x- oder y- Koordinate um einen Skalar a vervielfacht. Mx = 1 a ! 0 1 1 0 und My = ! a 1 Die Idee des Algorithmus ist es, durch eine gezielte Anwendung des Streckens eine Rotation anzunähern (Siehe Abb 1.8). Orginal x-shearing y-shearing x-shearing Abbildung 1.8: Durch drei Scher-Operationen wird die Rotation um 45 Grad angenähert. cosΘ −sinΘ sinΘ cosΘ ! Ziel = 1 a 0 1 ! 1 0 ! b 1 1 c ! 0 1 Eine angenäherte Lösung des Gleichungssystems ist a = c = −tan( Θ2 ) und b = sinΘ. Im Hinblick auf eine bessere Filterung werden die Werte wie folgt gewählt [Wyv93]: Θ Def 1 2n a = c = −tan( ) = : − , b = 2 n 1 + n2 Der Algorithmus arbeitet in drei Stufen. Zu Beginn wird das Bild in x-Richtung gemäß der Matrix gestreckt. Es folgt danach die Streckung in y-Richtung und anschließend nochmals eine Streckung in x-Richtung. Aus dieser Arbeitsweise lassen sich Vorteile ziehen. Eine Streckung erfolgt jeweils nur in eine Richtung. Die andere Richtung bleibt konstant. Der Vorteil 21 1.8. DITHERING 22 besteht darin, dass auf einer ganzen Reihe von Pixeln gearbeitet werden kann. In jeder Stufe des Algorithmus wird das Bild zeilenweise gefiltert und gerastert. Die aktuelle Linie wird als Scan-Line bezeichnet. Scan Line Abbildung 1.9: Der urspr̈ungliche Pixel erhält durch das Scheren die Form eines Paralellogramms. In diesem Fall überdecken zwei Parallelogramme einen Pixel. Die Farbe muss aus diesen zwei Pixeln ermittelt werden. Im Idealfall wird ein Pixel des Rasters von zwei gestreckten Pixeln überdeckt. Die Farbe muss in diesem Fall nur aus zwei Pixeln zusammengemischt werden. 1.8 Dithering In Abschnitt 1.2.2 wurde die Abstraktion des Framebuffers vorgestellt, auf dem die genannten Algorithmen arbeiten. Die Farbtiefe des Framebuffers muss nicht zwangsläufig mit der Farbtiefe des Ausgabegerätes identisch sein. Es entsteht das Problem, dass möglicherweise die Farbtiefe verringert werden muss. Das Problem betrifft nicht nur das Ausgabegerät. Bei Kopiervorgängen von verschiedenen Pixelbereichen, die relevant bei Bitmap-Fonts sind, muss ebenfalls auf verschiedene Farbtiefen reagiert werden. Im Folgenden wird ein Verfahren vorgestellt, das dieses Problem durch das sogenannte Dithering löst. Dazu betrachten die ersten zwei Unterabschnitte die Repräsentation von Farben. Unterabschnitt 1.8.3 stellt im Anschluss den Floyd-Steinberg Algorithmus vor, der ein Ordered Dithering mit Fehlerstreuung realisiert. 22 1.8. DITHERING 1.8.1 23 Farbrepräsentation Wie in Abschnitt 1.2.2 erwähnt, gibt die Farbetiefe die Anzahl der Bits an, die zur Speicherung einer Farbe zu Verfügung stehen. Es gibt verschiedene Modelle, die eine Farbe beschreiben können. Das Bekannteste ist das RGB Modell. Das RGB Modell unterteilt eine Farbe in die Komponenten Rot, Grün, Blau. Jede Komponente kann durch einen Wert gewichtet werden. Dieser Wert wird in unterteilten Bitbereichen gespeichert. Die Gesamtfarbe entsteht aus dem Mischen der drei Farbkomponenten. 1.8.2 Color Look Up Table Ein Color Look Up Table (CLUT) kann ein wichtiges und effektives Werkzeug für Dithering-Algorithmen darstellen. Durch die Reduktion der Farbanzahl muss eine Wahl der noch zu verwendenden Farben getroffen werden. Ohne Einsatz einer CLUT werden aus dem ursprünglichen Spektrum gleichmäßig Farbwerte gewählt. Für ein Bild, das Farben aus einem begrenzten Spektrum benutzt, kann die Auswahl und somit die Qualität optimiert werden, indem die Auswahl aus dem verwendeten Spektrum erfolgt. Die Auswahl der verwendeten Farben wird in der CLUT in geordneter Reihenfolge gespeichert. Mit dieser Ordnung kann nun eine gegebene Farbe einer Farbe des reduzierten Spektrums zugeordnet werden. 1.8.3 Ordered Dithering mit Fehlerstreuung Es wird im Folgenden der Floyd-Steinberg-Algorithmus betrachtet. Der Algorithmus arbeitet einen Bereich pixelweise ab. Die Reihenfolge ist bei der Abarbeitung festgelegt (ordered). Jede Farbe eines Pixel wird während der Abarbeitung mit einer Farbe der reduzierten Auswahl zugeordnet. Dabei kann eine Farbe durch einen Vergleich in der CLUT, einer passenden Farbe zugeordnet werden. Die Differenz zwischen Orginal-Farbe und der reduzierten Farbe wird den noch nicht bearbeiteten Nachbarpixeln aufaddiert. Dabei wird die in Abb. 1.10 gezeigte Gewichtung vorgenommen.[TB94] Die Verteilung der Gewichtung setzt dabei voraus, dass die Abarbeitung der Pixel zeilenweise von links nach rechts geschieht. Dieses feste Abarbeitungsmuster verhindert, dass bearbeitete Pixel verändert werden oder Pixel zu stark verfälscht werden. 23 1.9. ALIASING 24 bearbeitet aktuell 7/16 3/16 5/16 1/16 Abbildung 1.10: Die aktuelle Differenz zum gerundeten Farbwert wird an die benachbarten Pixel weitergegeben. Die Weitergabe unterliegt einer Gewichtung und hängt von der Abarbeitunsrichtung ab. Es gibt verschiedene Abwandlungen des Floyd-Steinberg-Algorithmus, die die Abarbeitung betreffen. Es ist möglich, den Pixelbereich schlangenlinienartig oder auch diagonal abzuarbeiten. Je nach Anwendung kann das Resultat verbessert werden. Es ist dabei aber notwendig, eine andere Verteilung der Gewichtung auf die Nachbarn vorzunehmen. Abbildung 1.11: Floyd-Steinberg: (links) Orginalbild mit 255 Farben. (mitte) Reduzierung auf 2 Farben ohne Dithering. (rechts) Reduzierung auf 2 Farben mit Floyd-SteinbergDithering 1.9 Aliasing Ein Aliasing-Effekt entsteht in der Computergrafik, wenn durch gegebene Rahmenbedingungen eine Reduzierung der Informationen durchgeführt werden muss. Dieses Problem betrifft beispielsweise das Sampling einer Geradengleichung (siehe Abschnitt 1.4.1) oder auch die Reduktion der Farbtiefe (siehe Abschnitt 1.8). Der visuelle Effekt des Aliasing ist typischer Weise als Treppenstufe (siehe Abb. 1.1, rechts) oder in anderen ungewollten Mustern wahrzunehmen. Diese Muster beeinträchtigen die Qualität des Glyphen und wirken sich dabei auf die Lesbarkeit eines Textes aus. Deshalb ist es wichtig, den Aliasing-Effekt zu minimieren. 24 1.9. ALIASING 25 Der Bereich des Anti-Aliasing versucht diesen Erscheinungen entgegen zu wirken. Es werden im Folgenden zwei Ansätze vorgestellt. Abschnitt 1.9.1 beschreibt das objektbasierte Anti-Aliasing. Anschließend wird der Bresenham-Algorithmus durch Anti-Aliasing erweitert, um den Treppeneffekt beim Linien-Rastern zu minimieren. Abschnitt 1.9.2 beschreibt die Subpixel-Rendering-Technik, die beim ClearType-Format benutzt wird. 1.9.1 Objektbasiertes Anti-Aliasing Das objektbasierte Anti-Aliasing arbeitet auf der Ebene der Primitive. Punkte, Linien und Polygone werden durch eine Abstufung der Farbwerte an den Rändern dem Hintergrund angepasst. Es entsteht eine glatte Kante. Durch die Anwendung auf der Ebene der Primitive wird das gewünschte Gesamtbild erhalten. Das objektbasierte Anti-Aliasing kann durch eine Erweiterung der bekannten Algorithmen erreicht werden. Exemplarisch wird im nächsten Unterabschnitt der Bresenham-Algorithmus durch Anti-Aliasing erweitert. Bresenham-Erweiterung Die oben genannte Abstufung der Farbwerte kann durch die folgende Technik des Alpha Blending durchgeführt werden. Der Alphawert ist neben Rot, Grün und Blau eine zusätzliche Farbkomponente und beschreibt die Transparenz einer Farbe. Das Spektrum reicht von Durchsichtig bis Solid. Es gibt verschiedene Operationen, den Alpha-Wert zweier Farben zu verrechnen. Der over-Operator ist zur Berechnung der Überlagerung einer existierenden Farbe B mit der neuen Farbe A passend. Seien dazu A = (αA , RA , GA , BA ) und B = (αB , RB , GB , BB ) zwei Farbrepräsentationen (siehe 1.8.1). Der Farbwert C aus der Berechnung C = AoverB berechnet sich durch die folgende Formel[Wyv93]. RA RB C = αA GA + (1 − αA ) GB BA BB 25 1.9. ALIASING 26 Die eigentliche Erweiterung des Bresenham-Algorithmus besteht in der mehrfachen Anwendung des Zeichnens einer Linie. Verschiedene Linien werden mit jeweils einem kleinen Offset zum Start- und Endpunkt gezeichnet. Die Alpha-Werte der Linien können beispielweise durch 12 , 13 , 14 , ... gewählt werden. 1.9.2 Subpixel Rendering Die Microsoft ClearType Technologie benutzt eine andere Möglichkeit des Anti-Aliasing um Glyphen zu rastern. Das ClearType Format ist speziell für den Einsatz an einem LCD-Bildschirm entwickelt worden und nutzt die technischen Gegebenheiten eines LCD-Bildschirms aus. Die Funktionsweise ist frei nach Steve Gibson[Gib07] wiedergegeben. Das Raster eines LCD-Bildschirms lässt sich auf Pixelebene weiter unterteilen. Dabei besteht ein einzelner Pixel weiterhin aus drei weiteren Leuchtelementen, die sich jeweils separat in der Intensität steuern lassen. Die drei Komponenten entsprechen der Farbrepräsentation, die in Abschnitt 1.8.1 besprochen wurde. Ein Pixel unterteilt sich in drei gleich große Spalten für je eine Komponente. Dies ermöglicht nicht nur einen gesamten Pixel anzusteuern, sondern auch die Intensität der jeweiligen Subpixel. Diese Unterteilung auf Subpixelebene ermöglicht bei der Font-Rasterung eine dreifach höhere horizontale Auflösung. Das Subpixel Rendering ist vom Gerät abhängig. Es muss zum Beispiel auf die Anordnung der Rot-,Grün- und Blau-Komponenten des Gerätes geachtet werden. Die Umrisse von Glyphen müssen entsprechend der 3fach höheren horizontalen Auflösung transformiert werden. Das Rastern des Glyphen geschieht über die Entscheidung, ob ein Subpixel innerhalb dieser Umrisse liegt. Der Subpixel wird im positiven Fall ausgeschaltet, indem die Intensität auf 0 gesetzt wird. Im anderen Fall wird dieser Subpixel angeschaltet und der Wert der Intensität ist 1. Diese vereinfachte Beschreibung liefert einen schwarzen Glyphen auf weißem Hintergrund. Es entsteht aber durch die vorgegebene Farbe der Subpixel ein Problem, das zusätzlich gelöst werden muss. Es entsteht an den Rändern der Glyphen ein Farbsaum. Dieser resultiert daraus, dass die Subpixel nur in zwei verschiedenen Intensitätsstufen angesteuert wurden. Für einen schwarzen Subpixel wurde keine Intensität benutzt. Am Rand des Glyphen wird die Farbe des ersten nicht schwarzen Pixels wegen des Kontrastes vom Auge besonders wahrgenommen. Um dieses Problem zu lösen, wird die Intensität der Subpixel am Rand abgestuft. Es wird ein Filter benötigt, der dies leistet. 26 1.9. ALIASING 27 Abbildung 1.12: Subpixel-Rendering: Der linke Umriss des Glyphen soll gerastert werden. Der Glyph wird mit ganzen Pixel (Mitte) und mit Subpixeln (Rechts) gerastert. Das Filtern geschieht in zwei Stufen. Die Entscheidung über das schlichte Ein- oder Ausschalten eines Subpixels bleibt bestehen. Der Filter ändert jedoch die Verteilung der Intensität. In der ersten Stufe werden der linke und rechte Nachbar-Subpixel zusätzlich in die Filterung einbezogen. Der Raster-Algorithmus liefert die Intensität (Wert 0 oder 1) für jeden Subpixel. Der Filter gibt die Intensität zu je einem Drittel den drei Subpixeln weiter. In der zweiten Stufe wird die Intensität, die den drei Subpixeln aus der vorigen Stufe übergeben wurde, ein zweites Mal auf die gleiche Art gefiltert. Linker und rechter Nachbar sowie der zu bearbeitende Subpixel geben die übergebene Intensität den Nachbarn ihrer Seits weiter. Es entsteht daraus die in Abbildung 1.13 zu sehende Verteilung der Intensität auf die fünf involvierten Subpixel. Das Verfahren entspricht einem farblichen Anti-Aliasing. Dabei werden durch die Farben die Positionen der Subpixel angesteuert. Aus diesem Grund werden bei einer Anwendung des Verfahrens auf einem CRT-Monitor keine optimalen Ergebnisse geliefert. Ein CRT-Monitor kann die vorausgesetzte Unterteilung in Subpixeln nicht korrekt wiedergeben. Die vorgestellten Anti-Aliasing-Verfahren können helfen die Umrisse der Glyphen zu glätten. Jedoch tritt dabei durch die Abstufung der Farbwerte am Rand eine 27 1.9. ALIASING 28 1 1/3 1/3 1/3 1/9 2/9 1/3 2/9 1/9 Abbildung 1.13: Subpixel-Rendering: Die aktuelle Intensität eines Pixels wird auch auf die vier benachbarten Pixel verteilt.. Unschärfe auf. Es ist daher ein Kompromis zwischen Schärfe und Kantenglättung zu finden. Dies zeigt, wie auch an anderen Stellen zu sehen, dass die angestrebte optimale Lesbarkeit äußerst schwer zu erreichen ist. 28 Kapitel 2 Shading Kai Lawonn 2.1 Einleitung Das Schattieren von geometrischen Oberflächen ist ein wichtiges Teilgebiet der Computergraphik. Viele Modelle zur Bestimmung des Aussehens von geometrischen Figuren sowie Formen wurden entwickelt, um solche Objekte realistischer wirken zu lassen. Hierbei unterscheidet man zunächst globale und lokale Beleuchtungsmodelle. Globale Beleuchtungsmodelle simulieren die Ausbreitung von Licht Beispiele für globale Beleuchtungsmodelle sind Raytracing oder Radiosity. Lokale Beleuchtungsmodelle, um die es in dieser Arbeit auch vorrangig gehen soll, simulieren die Wechselwirkung zwischen Licht auf Oberflächen. Bei diesem Beleuchtungsmodellen wird die Farbe beziehungsweise die Helligkeit eines Objekts berechnet. Für dieses Berechnungen werden lediglich durch die Blickrichtung, den Lichteinfall sowie einiger Materialkonstanten von Objekten und den Lichtquellen bestimmt. Hierbei wird die indirekte Beleuchtung völlig ausgeschlossen weiterhin berechnen globale Beleuchtungsmodelle Schatten, die die Objekte werfen, die auch beim lokalen Beleuchtungsmodellen nicht berechnet werden. In dieser Arbeit werden zwei Beleuchtungsmodelle: Lambert- und Phong-Beleuchtungsmodell vorgestellt sowie drei Shading-Verfahren, die sich als die Hauptverfahren der Schattierungsalgorithmen herauskristallisiert haben: Flat-, Gouraud- und das Phong-Shading. Weiterhin habe ich noch zwei weitere Kapitel verfasst, die das Thema Licht aufgreifen: Das erste Kapitel behandelt die Frage, was passieren kann, wenn das Licht mit einem Objekt in Wechselwirkung steht, während das sechste Kapitel Kapitel das Licht aus 29 2.2. GRUNDLAGEN 30 einem geschichtlichen Aspekt behandelt. Hierbei wird beschrieben, wie sich im Laufe der Zeit immer mehr physikalische Theorien über das Licht entwickelten. 2.2 2.2.1 Grundlagen Lichtausbreitung Wenn das Licht in eine Szene eintrifft und mit einem Objekt in Wechselwirkung steht kann das Licht 1. absorbiert, 2. reflektiert oder 3. transmittiert werden. Die Bedeutung der einzelnen Begriffe wird im Folgenden erklärt. 1. Der Begriff Absorption (lat.: absorptio = aufsaugen) bedeutet im Allgemeinen etwas in sich aufnehmen“. Im Zusammenhang mit Licht ist darunter das ” Aufnehmen von Licht bestimmter Frequenz durch das vorhandene Material gemeint. Wird also zum Beispiel ein schwarzes Material mit weißem Licht bestrahlt, so wird das Licht fast vollständig vom Material absorbiert. Die Folge ist, dass uns das Material schwarz erscheint, wobei man bei solchen Formulierungen vorsichtig sein muss: Insbesondere heißt es nicht das Licht wird absorbiert, weil das Material schwarz ist, sondern vielmehr, gerade weil das Licht absorbiert wird, erscheint uns das Material schwarz. Abbildung 2.1: Absorption 2. Der Begriff Reflexion (lat. reflectere: zurückbeugen, drehen) bedeutet im Allgemeinen etwas zurückwerfen“. Im Zusammenhang mit Licht versteht man ” 2.2. GRUNDLAGEN 31 darunter, dass Zurückwerfen von Licht mit bestimmter Wellenlänge. Hierbei werden noch zwei weitere Unterscheidungen vorgenommen: spiegelnde (specular) und ausbreitende (diffuse) Reflexion. Beide Reflexionstypen sind abhängig von dem Material mit dem sie interagieren. Bei der spiegelnden Reflexion stelle man sich eine nahezu perfekte Oberfläche vor, die glatt ist und ohne kleine Unebenheiten. Beispiele hierfür sind ein Spiegel oder ein stiller Teich. Schauen wir in einen Spiegel, werden die Lichtquanten, die auf einen Spiegel treffen, nahezu komplett reflektiert, nach dem Gesetz: Einfallswinkel=Ausfallswinkel (siehe Abbildung 2), und wir sehen uns selber wieder. Dies gilt aber nur bei einem perfektem Spiegel. Abbildung 2.2: Spiegelnde Reflexion bei einem idealen Spiegel Abbildung 2.3: Diffuse Reflexion Im Gegensatz zu der spiegelnden Reflexion findet sich die ausbreitende Reflexion auf einer Oberfläche wieder, die nicht frei von Unebenheiten ist. Beispiel hierfür ist zum Beispiel Holz. Die Unebenheiten sind auf der Oberfläche so klein, dass die Reflexion des Strahls in eine nicht vorhersehbare Richtung reflektiert wird (siehe Abbildung 3). Das Kosinusgesetz von Lambert erklärt einen einfachen Zusammenhang zwischen der reflektierenden Lichtintensität in Abhängigkeit des Einfallswinkels: I = A · L · cos θ, 2.2. GRUNDLAGEN 32 wobei • I die Lichtstärke, • L eine Konstante, • A ein Flächenelement und • θ der Winkel zwischen der Normale und dem einfallenden Licht bedeutet. Diese Gleichung ist allerdings nur für eine ideale diffuse Fläche gültig, auf der der Strahl gleichermaßen in alle Richtungen reflektiert wird. Vereinfacht kann man auch nach dem Lambert-Strahler schreiben: I = Imax cos θ. Hierbei nimmt die reflektierende Lichtstärke mit größer werdendem Reflexionswinkel ab. Die Lichtstärke ist direkt proportional zum Eintrittswinkel, das heißt sie nimmt mit größer werdendendem Reflexionswinkel ab. Für den Lambert-Strahler gilt, es ist egal aus welcher Richtung man auf die Fläche schaut, sie erscheint gleich hell. Abbildung 2.4: Lambert-Strahler 3. Der Begriff Transmission (von lat. trans - hinüber und mittere - schicken) bedeutet im Allgemeinen etwas übertragen“. Im Bezug auf Licht ist damit ” die Abnahme der Lichtintensität gemeint, wenn sie durch einen Stoff hindurch strahlt. Ein Beispiel ist zum Beispiel eine Flüssigkeit. Das Licht mit einer bestimmten Intensität trifft auf eine Flasche, in der sich eine Flüssigkeit befindet. Vereinfacht denken wir uns die Flasche als nicht vorhanden, bzw. die Flasche übt keinen Einfluss auf das Licht aus. Dann wird das auftreffende 2.2. GRUNDLAGEN 33 Licht nicht nur reflektiert und absorbiert, sondern es wird auch transmittiert, das heißt das Licht strahlt noch durch die Flüssigkeit durch. In diesem Zusammenhang darf auch nicht die Brechung unerwähnt bleiben, die auf die Gesetze von Snell zurückführt. Die Brechungszahl ist der Quotient aus der spezifischen Brechungszahl n1 des aktuellen Materials (z.B. Luft) und der spezifischen Brechungszahl n2 des Materials, auf welches das Licht eintrifft (z.B. Wasser): n2 sin θ1 = sin θ2 n1 wobei θ den Winkel des aktuellen Materials bezüglich Einfallswinkel und Flächennormale beschreibt (siehe Abbildung 5). Abbildung 2.5: Brechung eines Lichtstrahls, der vom Material 1 mit der Brechungszahl n1 in das zweite Material, mit Brechungstzahl n2 , eindringt. 2.2.2 Lichtquellenmodelle In der Computergraphik versucht man mit einer Vielzahl von unterschiedlichen Lichttypen eine Szene realistischer wirken zu lassen. Einige dieser Lichttypen werden im Folgenden kurz vorgestellt und erklärt. • Ambientes Licht: Ambientes Licht beleuchtet alle Objekte in der Szene gleichermaßen. Hierbei werden keine Schatten gesetzt, da das Licht keine Position und Richtung aufweist. Die Objekte erhalten einfach ihre spezifische Farbe, hierbei wird kein 3D-Eindruck gewonnen. 2.3. LOKALE BELEUCHTUNGSMODELLE 34 • Direktionales Licht: Direktionales Licht simuliert Licht, welches unendlich weit entfernt ist. Alle Lichtstrahlen sind dabei parallel (kollinear). Schatten können bei diesem Lichttypen auftreten. • Punktlicht: Punktlicht hat einen Ursprung, von dem die Lichtstrahlen radial in alle Richtungen ausgehen. Punktlicht ist mit einer Glühbirne zu vergleichen. Dieser Lichtquellentyp erzeugt harte Schatten. • Spotlicht: Spotlicht geht von einem Ursprung aus und leuchtet in eine vorher definierte Richtung kegelförmig Licht aus. Dabei sind die Richtung und der Radius festzulegen. Ein Beispiel hierfür wäre zum Beispiel eine Taschenlampe. Der Unterschied zum Punktlicht ist, dass der Strahl durch einen Kegel begrenzt wird. • Flächenlicht: Flächenlicht sind Lichtquellen, die sich gleichmäßig verteilt auf einer Ebene befinden. Dabei werden weiche Schatten erzeugt. Ein Beispiel wäre ein gleichmäßig beleuchteter Saal mit Deckenleuchten. 2.3 2.3.1 Lokale Beleuchtungsmodelle Lambert-Beleuchtungsmodell Das Lambert-Beleuchtungsmodell berechnet sich nach folgender Gleichung: I = Imax cos θ. Diese Gleichung wurde ausführlich im Kapitel 2.1 behandelt. Die maximale Lichtstärke wird immer senkrecht zur Oberfläche reflektiert. Hierbei ist die maximale Lichtstärke völlig unabhängig vom Ort der Lichtquelle. Dieses Beleuchtungsmodell gilt allerdings nur für nahezu perfekte Oberflächen. 2.3.2 Phong-Beleuchtungsmodell Das Phong-Beleuchtungsmodell basiert aus drei verschiedenen Komponenten: • Ambient (umgebend) • Diffuse (ausbreitend) • Specular (spiegelnd) 2.4. SCHATTIERUNGSVERFAHREN 35 Nach dem Phong-Beleuchtungsmodell berechnet sich dann die Lichtstärke: I = Iambient + Idiffuse + Ispecular . Die Lichtstärke setzt sich aus drei verschiedenen Lichtstärken zusammen. Die drei verschiedenen Lichtstärken werden im Kapitel 4.3 ausführlich behandelt. 2.4 2.4.1 Schattierungsverfahren Flat-Shading Berechnung Flat-Shading ist das einfachste Schattierungsverfahren in der Computergraphik. Dieses Schattierungsverfahren basiert auf dem Beleuchtungsmodell von Lambert, bei dem die Lichtstärke völlig unabhängig von Ort des Beobachters ist. Bei dem FlatShading wird jeder Fläche des Objekts ein Farbwert zugeordnet. Die Zuordnung des Farbwert basiert dabei auf dem Gesetz von Lambert. Dazu benötigt man: • ~ne : Die normierte Normale des Flächenelements. Diese lässt sich einfach aus dem Kreuzprodukt der Vektoren aus dem Vertices-Differenzen berechnen. • ~l: Der normierte Vektor, der von der Lichtquelle auf den entsprechenden Vertex zeigt. Dieser muss auch normiert sein. Nach dem Lambertschen-Kosinus-Gesetz gilt: I = Imax cos θ. Zunächst betrachte zur Vereinfachung nur eine Lichtquelle, dann berechnet sich die neue Farbe des Vertex wie folgt: colornew = colorcurrent ·κM + colorcurrent · cos(^(~ne , ~l)) re = ge · κM + h~ne , ~li . be (2.1) (2.2) Das letzte Gleichheitszeichen ist deshalb richtig, weil die Vektoren ~nv und ~l normiert sind. Hierbei ist auch darauf zu achten, dass die R-,G- und B-Werte die Zahl 0 nicht unterschreiten und die Zahl 1 nicht überschritten werden darf. Sollte dies der Fall 2.4. SCHATTIERUNGSVERFAHREN 36 sein, wird in einer zusätzlichen Abfrage der einzelne Wert auf 0 beziehungsweise 1 gesetzt, dies nennt man auch Clamping. Diese Regel gilt ab sofort immer, wenn es um Farbwerte im Zusammenhang mit dem Skalarprodukt geht. κM ist eine Konstante, die das Objekt mit einer bestimmten Farbe sichtbar machen lässt. Wird beispielsweise κM = 1 gesetzt, so behält das Objekt seine Farbe bei und erscheint nur an den Stellen heller, an denen die Lichtquelle das Objekt direkt bestrahlt. Wird hingegen κM = 0 gesetzt, so werden Stellen, die von der Lampe nicht angeleuchtet werden, schwarz dargestellt. Dies passiert wenn die Vektornormale und der Lichtquellenvektor senkrecht zueinander stehen, dann wird das Skalarprodukt 0 und die neue Farbe errechnet sich aus dem Produkt von colorcurrent und κM . Betrachten wir nun den Fall, dass unsere Lichtquelle farbig ist. Dann ändert sich die Abbildung 2.6: Eine Kugel die mit Flat-Shading schattiert wurde. Elemente, die direkt von der Lichtquelle angestrahlt werden, sind heller dargestellt, während die hinteren Elemente komplett schwarz sind. [Bild wurde mit JavaView erstellt] Gleichung (1) wie folgt: colornew re rL = ge ⊗ gL κM + h~ne , ~li . be bL (2.3) Über den Operator ⊗“ findet sich mehr im Anhang. Hierbei sind dann rL , gL , bL ” die entsprechenden R,G,B-Werte der Lichtquelle. Zum Schluß betrachten wir noch den Fall, dass es in der Szene mehrere Lichtquellen mit unterschiedlicher Farbe gibt, dann erhalten wir folgende allgemeine Gleichung: 2.4. SCHATTIERUNGSVERFAHREN colornew r r X e Li = ge ⊗ gLi κM + h~ne , ~li . # lights b bLi e 37 (2.4) rLi , gLi und bLi sind hierbei die Farbwerte der unterschiedlichen Lichtquellen. Abbildung 2.7: Flat-Shading mit roter und grüner Lichtquelle. [JavaView] Zusammenfassung Die einzigen Vorteile, die das Flat-Shading bietet sind, dass es sich sehr einfach implementieren lässt und sehr schnell ist. Dieses Verfahren kann benutzt werden, um einen ersten Eindruck von einer Szene zu gewinnen. Diese Verfahren erlaubt auch Schattierungen in Echtzeit. Nachteile des Flat-Shading sind: Aufgrund der Berechnung einer einzelnen Farbe für jedes Flächenelement wirkt das Objekt sehr kantig und eckig. Es ist kein sauberer Übergang von einer Kante zur nächsten erkennbar. Dieser Nachteil wird durch das nächste Schattierungsverfahren, das Gouraud-Shading, behoben. 2.4.2 Gouraud-Shading Berechnung Das Gouraud-Shading wurde vom französischen Informatiker Henri Gouraud entwickelt und erstmals 1971 vorgestellt. Es ist eines der ersten interpolativen Schattie- 2.4. SCHATTIERUNGSVERFAHREN 38 rungstechniken. Zunächst werden die Farbwerte der Vertices berechnet, doch anstatt nun wie beim Flat-Shading den Elementen nur einen Farbwert zu zuzuweisen, wird nun jedem Vertex ein Farbwert zugeordnet, die Farbe innerhalb des Elements wird durch Interpolation der Vertexfarben berechnet. Die Idee, die dahinter steckt, ist, den Pixel baryzentrisch durch die anliegenden Vertices (siehe Anhang) zu ermitteln und dann den Farbwert des Pixels mit den baryzentrischen Koordinaten und den entsprechenden Farbwerten zu mitteln. Im folgenden gehen wir von Objekten aus, die trianguliert wurden oder bereits sind. Ein Objekt heißt trianguliert, wenn jedes Flächenelement aus Dreiecken besteht. Angenommen die Farbwerte wurden für jeden Vertex berechnet, dann besteht der nächste Schritt darin, den Farbwert eines beliebigen Pixels durch die lineare Interpolation zu bestimmen. Es sei nun m ein Flächendreieck, v1 , v2 , v3 ∈ N2 die angrenzenden Vertices und v ∈ N2 ein beliebiger Punkt in m. Es werden nun die baryzentrischen Koordinaten λ1 , λ2 , λ3 ∈ R benötigt, für die gelten muss: 1. λ1 (v), λ2 (v), λ3 (v) ≥ 0, 2. λ1 (v) + λ2 (v) + λ3 (v) = 1 und 3. λ1 (v) · (v1 ) + λ2 (v) · (v2 ) + λ3 (v) · (v3 ) = v. Man mache sich klar, dass vi , v in N2 sind, da wir nur die Pixelkoordinaten betrachten. Gleichung 2. und 3. führen auf folgendes 3 × 3 Gleichungssystem: 1 1 v1x v2x v1y v2y 1 v3x · λ2 (v) = vx vy v3y λ3 (v) 1 λ1 (v) mit folgenden Lösungen: v2x v3y − v3x v2y − vx v3y + vx v2y + vy v3x − vy v2x v2x v3y − v3x v2y − v1x v3y + v1x v2y + v1y v3x − v1y v2x −v1x v3y + v3x v1y + vx v3y − vx v1y − vy v3x + vy v1x λ2 (v) = v2x v3y − v3x v2y − v1x v3y + v1x v2y + v1y v3x − v1y v2x v1x v2y + v2x v1y + vx v1y − vx v2y − vy v2x − vy v1x λ3 (v) = v2x v3y − v3x v2y − v1x v3y + v1x v2y + v1y v3x − v1y v2x λ1 (v) = (2.5) (2.6) (2.7) Hat man nun die λ’s ausgerechnet so lassen sich die Farbwerte der Pixel aus den alten Farbwerten α1 , α2 , α3 ∈ [0, 1]3 der zugehörigen anliegenden Vertices, 2.4. SCHATTIERUNGSVERFAHREN 39 errechnen. Der Farbwert für den Pixel v errechnet sich dann durch: colornew = λ1 (v) · α1 + λ2 (v) · α2 + λ3 (v) · α3 . Etwas anschaulicher kann man sich folgendes äquivalentes System vorstellen (siehe Abbildung 8): v1y − vy v1y − v2y v1 − vy vb = v1 − (v3 − v1 ) · y v1y − v3y vb − vx vp = va − (vb − va ) · x . vbx − vax va = v1 − (v2 − v1 ) · (2.8) (2.9) (2.10) Abbildung 2.8: Scanline Hierbei werden mittels Scanlines zunächst die Vertices va , vb berechnet und dann schließlich der gesuchte Vertex vp ermittelt. Mit diesen Verfahren stößt man letztendlich auf die gleichen Formeln. Diese Gleichungen ergeben sich, wenn man zunächst eine Geradengleichung, durch zum Beispiel ~v1 und ~v2 aufstellt: g : ~x = ~v1 + t · (~v2 − ~v1 ), t ∈ R und dann jenes t sucht, so dass der y-Wert der Scanline vy die Gleichung erfüllt: vy = v1y + t · (v2y − v1y ) ⇒ t = v1y −vy v1y −v2y . Die anderen Formeln werden analog bewiesen. Der Farbwert errechnet sich dann, indem 2.4. SCHATTIERUNGSVERFAHREN 40 man zuerst die Farbwerte für va und vb ermittelt und dann für vp . Die Farbwerte für va und vb errechnen sich durch Gleichung (9) bzw. (10) indem man für v1 , v2 und v3 die entsprechenden Farbwerte einsetzt. Auf dem ersten Blick erscheint nun die zweite Möglichkeit deutlich einfacher und schneller, allerdings funktioniert diese lineare Interpolation auch nur in Zusammenhang mit triangulierten Objekten. Die Idee der baryzentrischen Koordinaten lassen sich allerdings auch auf allgemeine Objekten übertragen [siehe 10], die nicht notwendigerweise trianguliert sind. Abbildung 2.9: Eine Kugel, die mit dem Gouraud-Shading schattiert wurde. Hier sieht man deutlich sehr viel weichere Übergänge von einem Element zum anderen. [JavaView] Zusammenfassung Das Gouraud-Shading bietet einen optisch besseren Eindruck als das Flat-Shading. Durch die Interpolation erscheinen die Oberflächen nicht so kantig wie beim Flat-Shading. Aber wie das Flat-Shading hat auch das Gouraud-Verfahren gewisse Nachteile: Durch die Interpolation der Pixelfarbe von den Eckpunkten des Flächenelements, bleiben markante Reflexion innerhalb des Flächenelements unberücksichtigt. Strahlt zum Beispiel eine Lichtquelle genau inmitten eines Elements, so dass man in Wirklichkeit eine starke Reflexion beobachten würde, wird dieser Effekt beim Gouraud-Shading nicht berücksichtigt. Der Grund dafür ist, dass sich die Farbwerte der Pixel innerhalb eines Elements nur durch lineare Interpolation der Farbwerte der anliegenden Vertices berechnen. Alternativ könnte man versuchen, das zugrunde liegende Objekt durch Subdivisions-Verfahren (feinere Triangulierung) zu verbessern. Je mehr Vertices vorhanden sind, desto weicher die Darstellung. Hierbei sollte man jedoch berücksichtigen, dass die Dauer des Verfahrens von der Anzahl der Vertices abhängt. Weiterhin kann man beim Gouraud-Shading die Kan- 2.4. SCHATTIERUNGSVERFAHREN 41 ten der Elemente erkennen. Das nächste Schattierungsverfahren, das Phong-Shading, behebt nun aber auch diese Lücken. 2.4.3 Phong-Shading Vorbereitung Das Phong-Shading geht auf den vietnamesischen Informatiker Bui Tuong Phong zurück, der dieses Verfahren 1973 in seiner Doktorarbeit entwickelte und 2 Jahre später veröffentlichte. Das Phong-Shading kann auf dem PhongBeleuchtungsmodell basieren. Das Phong-Beleuchtungsmodell basiert aus drei verschiedenen Komponenten: • Ambient (umgebend) • Diffuse (ausbreitend) • Specular (spiegelnd) Nach dem Phong-Beleuchtungsmodell berechnet sich dann der Farbwert: colornew = colorambient + colordiffuse + colorspecular . Diese drei Komponenten werden nun ausführlicher erklärt. Ambiente Reflexion Die Ambiente-Komponente ist eine Konstante und somit unabhängig von den Orten der Lichtquellen und des Beobachters. Hierbei wird für das Objekt eine bestimmte Grundfarbe festgelegt, die abhängig von dem Material und des Umgebungslichtes ist. Beide können vom Benutzer festgelegt werden. Es gilt, mit κamb ∈ R+ , Iamb ∈ [0, 1]3 : colorambient = κamb · Iamb . Die neue Farbe berechnet sich aus der Grundfarbe der Lichtquelle Iamb und einer empirisch zu bestimmenden Material-Konstanten κamb . Alternativ könnte man auch die Farben aller Lichtquellen mitteln und diesen Wert dann Iamb zuweisen. colorambient ist dann die resultierende Farbe des aktuellen Punktes (siehe Abbildung 10). 2.4. SCHATTIERUNGSVERFAHREN 42 Abbildung 2.10: Ambiente Reflexion: Hier wurde die Grundfarbe des Objektes auf grün gesetzt. [Bild wurde mit POV-Ray erstellt] Diffuse Reflexion Die Diffuse-Komponente hängt von dem Ort der Lichtquelle ab und ist völlig unabhängig vom Ort des Beobachters. Hierbei wird schon die Schattierung des Objektes berechnet, die abhängig von der diffusen“ Farbe des ” Lichtes, einer Materialkonstanten und dem Skalarprodukt aus dem Normalenvektor und Lichtquellenvektor ist. Es gilt, mit κdif f ∈ R+ , Idif f ∈ [0, 1]3 : colordiffuse = κdif f · Idif f · cos ^(~n, ~l) = κdif f · Idif f · h~n, ~li. Spekulare Reflexion Die Spekulare-Komponente hängt nun vom Ort des Beob- achters und vom Lichtquellenvektor, der von der Oberfäche reflektiert wird, ab. Der reflektierte Lichtquellenvektor ~r berechnet sich dabei einfach als Spiegelung an dem Normalenvektor der Fläche. Zusätzlich wird der Vektor ~o benötigt, der den Vektor vom Beobachter zum betrachteten Punkt darstellt. Bei diesem Schritt wird der Glanz an bestimmten Stellen des Objekts berechnet. Die Berechnung ist zusätzlich von der Farbe des Glanzes Ispec , einer erneuten Materialkonstanten κspec und einer GlanzKonstanten n abhängig. Es gilt dann, mit κspec ∈ R+ , Ispec ∈ [0, 1]3 , n ∈ R+ : colorspecular = κspec · Ispec · cosn (^(~r, ~o)) = κspec · Ispec · h~r, ~oin 2.4. SCHATTIERUNGSVERFAHREN 43 Abbildung 2.11: Diffuse Reflexion: Hier wurden bereits erste Schattierungen berechnet. [POV-Ray] Die Vektoren ~o und ~r sind normiert. Wie schon gesagt, gibt n den Glanz an. Diesen Exponenten nennt man auch den Phong-Exponenten. Für n < 32 ist die Oberfläche rau, ab n > 32 wird sie glatter, für einen perfekten Spiegel gilt n = ∞“. ” 2.4.4 Berechnung Das Ergebnis (siehe Abbildung 13) des Phong-Beleuchtungsmodells berechnet sich aus der Summe der drei Komponenten. colornew = colorambient + colordiffuse + colorspecular = κamb · Iamb + κdif f · Idif f · h~n, ~li + κspec · Ispec · h~r, ~oin . (2.11) (2.12) Zusätzlich gilt: κamb + κdif f + κspec = 1. Kommen noch weitere Lichtquellen hinzu, so ändert sich die Gleichung (13) wie folgt: colornew = κamb · Iamb + X κdif f · Idif fi · h~n, ~li + κspec · Ispeci · h~r, ~oin . # lights (2.13) 2.4. SCHATTIERUNGSVERFAHREN 44 Abbildung 2.12: Spekulare Reflexion: In diesem Objekt sind nur die spekularen Highlights dargestellt. [POV-Ray] Die Farbwerte Idif fi und Ispeci sind abhängig von der Position der Lichtquelle. Der Unterschied zu dem Gouraud-Verfahren besteht nun nicht nur darin drei verschiedene Komponenten zu berechnen, sondern auch im Umfang. Beim Phong-Shading werden zunächst die Vertexnormalen berechnet. Anschließend wird für jeden Pixel des Flächenelements die Normale interpoliert und anschließend das oben beschriebene Beleuchtungsmodell angewendet. 2.4.5 Zusammenfassung Das Phong-Shading ist sicherlich mit eines der aufwändigsten Shading Verfahren, dennoch sehen die Bilder im Vergleich zu Flat-Shading und Gouraud-Shading deutlich besser aus. Im Gegensatz zu dem Gouraud-Shading bekommt man hier einen noch weicheren Übergang von Flächenelmenten hin, die Kanten sind nicht mehr erkennbar. Zusätzlich werden auch markante Glanzeffekte berücksichtigt. Die Glanzeffekte sind nun auch, im Vergleich zum Gouraud-Shading, innerhalb von Flächenelementen erkennbar. Des weiteren sind nun die Kanten nicht mehr erkennbar. 2.5. COOL-TO-WARM SHADING 45 Abbildung 2.13: Ambient+Diffuse+Specular: Hier wurden alle drei Komponenten zusammengefügt.[POV-Ray] 2.5 2.5.1 Cool-to-Warm Shading Berechnung Cool-to-Warm-Shading ist eine Shading-Methode aus dem Bereich des nicht photorealistischen Renderns (NPR). Hierbei geht es nicht darum, Modelle so realistisch wie möglich darzustellen, sondern die markanten Stellen der Modelle sichtbar werden zu lassen. Dies zeigt nicht nur Anwendung in der Film- oder Computerspielwelt, sondern vielmehr auch bei technischen oder medizinischen Anwendungen, um die Formen oder Strukturen von 3D-Modellen übersichtlicher zu gestalten. Speziell beim Cool-to-Warm-Shading kommt diese Eigenschaft zum Tragen. Hier werden anstatt Helligkeitsunterschiede benutzerdefinierte Farbübergänge eingesetzt. Der Benutzer gibt also zwei verschiedene Farbwerte an und je nachdem, welchen Winkel die Flächennormale und der Lichtquellenvektor einschließen, desto stärker wird der Pixel mit einer Farbe gefärbt. Man verwendet häufig, wie der Name schon andeutet, warme und kalte Farben, wie zum Beispiel: rot/orange und blau. Bei dem Cool-to-Warm-Shading wird dann die Fläche, die der Lichtquelle zugeneigt, ist mit der wärmeren Farbe beleuchtet und die entgegengesetzte Seite mit der kalten Farbe. Für die Formel gilt dann: 2.5. COOL-TO-WARM SHADING colornew = 1 + h~n, ~li 2 ! 46 1 + h~n, ~li · colorwarm + 1 − 2 ! · colorcool . Bei diesem Shading-Verfahren kann man entweder, wie beim Gouraud-Verfahren erklärt, nur jeden Vertex nach der obigen Gleichung einen Farbwert hinzufügen und dann die anderen Farbwerte des Flächenelements durch bi-lineare Interpolation ermittelt. Eine andere Möglichkeit wäre dies genau wie beim Phong-Shading pixelweise zu erledigen und für jeden Pixel mit den baryzentrischen Koordinaten den zugehörigen Normalenvektor ermitteln und dann mit der obigen Formel den entsprechenden Farbwert zu ermitteln. Es gibt noch eine Möglichkeit, bestimmte Highlights, also zum Beispiel kleine Reflexionen des Lichtes auf der Oberfläche zu erzeugen. Hierfür kommt noch eine Reflexions-Komponente hinzu, Gleichung (14) ändert sich dann wie folgt (siehe Abbildung 14): colornew = 1 + h~n, ~li 2 ! 1 + h~n, ~li · colorwarm + 1 − 2 ! · colorcool +h~n, ~hin . (2.14) Abbildung 2.14: Phong-Shading(links) im Vergleich zu Cool-to-Warm-Shading(mitte und rechts mit Kanten). Von Stefan Müller [6] 2.6. DISKUSSION 2.5.2 47 Zusammenfassung Das Cool-to-Warm-Shading ist sicherlich sehr einfach zu implementieren und erlaubt für verschiedene Farbwerte sehr schöne Resultate. Vom Standpunkt der Geschwindigkeit ist dieses Verfahren nicht viel aufwändiger als das Phong- oder Gouraud-Shading, je nachdem welches Verfahren man für das Pixel färben benutzt hat. 2.6 2.6.1 Diskussion Geschichte des Lichtes Beleuchtungsmodelle sind in der Computergraphik lediglich eine Approximation an die Realität. Es gibt sehr viele physikalische Eigenschaften des Lichtes, die bei der vereinfachten Darstellung von Licht, völlig unberücksichtigt bleiben. Doch klären wir zunächst einmal, was Licht im physikalischen Sinne ist. Albert Einstein sagte 1954 einmal: Fünfzig Jahre intensiven Nachdenkens haben mich der Antwort auf ” die Frage ’Was sind Lichtquanten?’ nicht näher gebracht. Natürlich bildet sich heute jeder Wicht ein, er wisse die Antwort. Doch da täuscht er sich!“. Eine der ersten Theorien, wieso Licht sich so verhält, wie es sich verhält, wurde von Sir Isaac Newton 1672 als Korpuskeltheorie aufgestellt. Bei dieser Theorie wird dem Licht ein Teilchencharakter zugeordnet. Das Licht besteht also aus kleinen Teilchen, die mit hoher Geschwindigkeit von leuchtenden Körpern geradlinig ausgeschleudert“ werden. Teilweise können damit die geradlinige Ausbreitung ” und die Reflexion erklärt werden. Brechung und Beugung bereiten jedoch einige Schwierigkeiten. Diese Theorie wurde schon bald, 6 Jahre später, von Christiaan Huygens Wellentheorie abgelöst. Mit seiner Wellentheorie konnte er die Beugung und Brechung von Licht erklären. 1905 wurde dann von Albert Einstein die Lichtquantenhypothese aufgestellt, die besagt, dass Lichtquanten eine Energie besitzen, Elektronen die Energie eines Photons absorbieren können und dass bei einem Quantensprung von Elektronen Energie in Form eines Lichtquants frei wird. Die Wellentheorie ist deutlich schwieriger nach Einsteins Photoeffekt zu erklären: Werden Photonen, mit hinreichend großer Energie auf eine Metallplatte gestrahlt, lösen sich Elektronen aus dieser heraus. Nach der Wellentheorie müssten, sich mehr Elektronen herauslösen, wenn die Intensität des Lichtes größer wird. Dies ist aber nicht der Fall. Einstein erhielt dafür den Nobelpreis. 1922 machte Arthur Holly Compton eine Entdeckung, für die er 1927 den Nobelpreis erhielt. Wenn ein Pho- 2.6. DISKUSSION 48 ton auf ein elektron trifft, prallen Elektron und Photon ab und bewegen sich mit unterschiedlichen Energien voneinander weg. Dieses Phänomen unterstützt wiederum die Teilchen-Theorie, da es sehr stark an den Impuls erinnert. Allgemein wurde aber nun von einem Welle-Teilchen-Modell im Zusammenhang mit Licht geredet. Louis-Victor Pierre Raymond de Broglie schrieb 2 Jahre nach Comptons Entdeckung in seiner Dissertation, dass sich jede Form von Materie den WelleTeilchen-Modell unterwarf. Eine komplette Beschreibung aller Phänomene, die von Lichtteilchen bzw. geladenen Teilchen aller Art handelt, wurde von Richard P. Feynman, Shinichiro-Tomonaga und Julian Schwinger aufgestellt. Dies ist heutzutage die Grundlage der Quantenelktrodynamik. Viele dieser Phänomene werden in den Feynman-Diagrammen sichtbar und sind heutzutage Standard. In seinem Buch ’QED. Die seltsame Theorie des Lichts und der Materie’ berichtet Feynman, dass er seinen Studenten immer sagte: Keiner versteht die Quantenelektrodynamik, nicht ” einmal ich. Ich zeige Ihnen nur, wie sie damit umzugehen haben.“ 2.6.2 Problematik Die Beleuchtungsmodelle nutzen bei den Berechnungen lediglich den Teilchencharakter des Lichtes aus. Effekte, die auf das Wellenmodell zurückführen, bleiben hierbei völlig unbeachtet. Interferenz zum Beispiel, also das Überlagern von zwei oder mehr Wellen bleibt völlig unberücksichtigt. Hier ist gemeint, falls Licht auf einen Doppelspalt gestrahlt wird, hinter den Spalten abwechselnd angestrahlte Stellen und dunkle Stellen zu sehen sind. Hierbei kann sich das Licht einerseits verstärken“ und anderseits gegenseitig auslöschen. Ein anderer Effekt, dem das ” Shading unterlegen ist, ist, dass angestrahlte Körper auch Licht emittieren. Weiterhin werden Objekte schattiert, Schatten von diesen Objekten werden allerdings nicht berechnet, so dass eine Kugel auf einer Ebene so wirkt, als würde sich schweben, anstatt darauf zu liegen. 2.6.3 Warum nicht physikalisch exakt? Aus Sicht der Quantenelektrodynamik lassen sich bestimmte Effekte nicht vorhersagen; es lässt sich nur mit einer bestimmten Wahrscheinlichkeit sagen, was passieren wird. Selbst bei einem einfachen Experiment wie dem Doppelspaltversuch können wir nicht sagen, welches Photon durch welchen Spalt fliegt“. Aufgrund ” von Beobachtungen und unter Zuhilfenahme der Wellentheorie können wir sagen, wie die Szene aussehen wird doch nur mit dem Teilchenmodell ausgestattet, wie 2.7. ANHANG 49 wir es in der Computergraphik benutzen, lassen sich solche Resultate nicht exakt bestimmen. Kommen nun komplexere Objekte hinzu, die von der Einfachheit des Doppelspaltes weit entfernt sind, dann wären die Rechnungen viel zu komplex, um genau zu sagen wie die Szene aussehen wird. Es spielt bei der Berechnung ja nicht nur eine zentrale Rolle, wohin das Licht strahlt und welche Objekte vom Licht beeinflusst werden, komplizierter wird es noch, wenn man bedenkt, dass das Licht ja auch auf sich selbst einen Einfluß ausübt (siehe Interferenz). Alles in allem sind die lokalen Beleuchtungsmodelle aus physikalischer Sicht noch weit davon entfernt, realistisch zu sein, allerdings spielen sich sehr viele Lichteffekte, die sich in der Computergraphik nicht darstellen lassen, auch in einer makroskopischen Welten ab, die für den Beobachter kaum wahrnehmbar sind. Deshalb lassen sich aus der Sicht des Betrachters die Ergebnisse wirklich sehen lassen und sind augenscheinlich nahezu perfekt. 2.6.4 Ausblick In dem vorherigen Kapitel wurden einige Schwachpunkte des Shadings angesprochen. Allerdings lassen sich einige diese Probleme, zumindestens augenscheinlich, beseitigen. Das Radiosity-Verfahren berechnet zum Beipsiel den Lichteinfluß von Objekten untereinander, so dass Gegenstände, die sich in der Nähe von sehr auffälligen Gegenständen befinden, auch deren Farbwerte annehmen. Ein Beispiel ist der rote Apfel auf dem weißen Blatt (siehe oben). Ein anderer Schwachpunkt ist, dass keine Schatten gesetzt werden. Diese Problem wird allgemein durch das Raytracing-Verfahren gelöst. Hierbei werden durch Schnittpunktberechnungen zunächst ermittelt welche Flächenelemente von den Strahlen einer Lichtquelle getroffen werden und welche nicht. Die Flächenelemente die nicht getroffen werden erscheinen dunkler und es kommt zur Schattenbildung. 2.7 Anhang 2.7.1 Vektoren Definition 1 (Vektorraum Rn ). Der Rn ist als die Menge aller n-Tupel von reellen Zahlen erklärt, geschrieben: ~x = (x1 , . . . , xn ). Definition 2 (Addition zweier Vektoren). Es sei ~x (y1 , . . . , yn ) ∈ Rn = (x1 , . . . , xn ), ~y = zwei Vektoren, dann ist die Addition komponentenweise erklärt 2.7. ANHANG 50 durch: ~x + ~y := (x1 + y1 , x2 + y2 , . . . , xn + yn ). Definition 3 (skalare Multiplikation). Es sei ~x = (x1 , . . . , xn ) ∈ Rn ein Vektor sowie t ∈ R ein skalar, dann ist die skalare Multiplikation erklärt durch: t · ~x := (t · x1 , t · x2 , . . . , t · xn ). Definition 4 (Skalarprodukt (euklidisch)). Es sei ~x = (x1 , . . . , xn ), ~y = (y1 , . . . , yn ) ∈ Rn zwei Vektoren, dann ist das Skalarprodukt erklärt durch: h~x, ~y i := n X x i yi . i=1 Definition 5 (Länge eines Vektors). Es sei ~x = (x1 , . . . , xn ) ∈ Rn ein Vektor, dann ist die Länge des Vektors erklärt durch: k~xk := p h~x, ~xi. Bem. ein Vektor ~x heißt normiert, wenn k~xk = 1. Definition 6 (Winkel zwischen zwei Vektoren). Es sei ~x = (x1 , . . . , xn ), ~y = (y1 , . . . , yn ) ∈ Rn zwei Vektoren, dann gilt: cos(^(~x, ~y )) = 2.7.2 h~x, ~y i . k~xk · k~y k Farbwerte Definition 7 Es sei α = [rα , gα , bα ] ∈ [0, 1]3 und r ∈ R dann gilt: r · re α · r = r · ge . r · be Die skalare Multiplikation ist kommutativ. Definition 8 Es sei α = [rα , gα , bα ] , β = [rβ , gβ , bβ ] ∈ [0, 1]3 dann gilt: rα + rβ α ⊕ β = gα + gβ . bα + bβ 2.7. ANHANG 51 Die Addition ist kommutativ. Definition 9 Es sei α = [rα , gα , bα ] , β = [rβ , gβ , bβ ] ∈ [0, 1]3 dann gilt: rα · rβ α ⊗ β = gα · gβ . bα · bβ Die Multiplikation ist kommutativ. Definition 10 Es sei αi = [rαi , gαi , bαi ] ∈ [0, 1]3 eine endliche Familie von Farbwerten. Dann gilt: P i rαi X i 2.7.3 P αi := α1 ⊕ α2 ⊕ α3 ⊕ . . . = i gαi P i bαi Baryzentrische Koordinaten Definition 11 (Polygon). Eine Menge Ω = {{Pi : Pi ∈ Rd , i 6= j ⇒ Pi 6= Pj , i ∈ {0, 1, 2, . . . , n}, n ≥ 3}, {Pi Pi+1 , i ∈ {0, 1, 2, . . . , n − 1}} ∪ {P0 Pn }} heißt Polygon. Einfacher: Ein Polygon ist eine Menge aus mindestens drei Ecken, die paarweise verschieden sein müssen sowie Kanten. Eine Kante verbindet immer nur zwei verschiedene Ecken, auf einer Kante dürfen nur zwei Ecken liegen. Satz 1 (Jordanscher Kurvensatz). Jede geschlossene Jordankurve (z.B. Polygon Ω) in der euklidischen Ebene zerlegt diese in zwei disjunkte Gebiete, deren gemeinsamer Rand die Jordan-Kurve ist. Dabei wird das von der Kurve eingeschlossenes Gebiet, ◦ Inneres genannt. Im Zeichen: Ω. Definition 12 Eine Menge Ω heißt ein konvexes Polygon, falls die Verbindungsstrecke von zwei beliebigen Punkten im Inneren von Ω liegt. ◦ Formal: Ω = {V, E} Polygon: Für alle P1 , P2 ∈ V gilt: t·P1 +(1−t)·P2 ∈ Ω für alle t ∈ [0, 1] . Definition 13 (Baryzentrische Koordinaten). Es sei Ω = {V, E} ein konvexes Polygon, mit v1 , v2 , . . . , vn ∈ V . Die Zuordnungen λi : V −→ R heißen baryzentrische ◦ Koordinaten, wenn für alle v ∈ Ω folgende Bedingungen erfüllt sind: 1. λi (v) ≥ 0, i = 1, 2, . . . , n, 2.7. ANHANG 52 2. Pn = 1 und 3. Pn = v. i=1 λi (v) i=1 λi (v)vi Kapitel 3 Raytracing Tobias Pfeiffer 3.1 Einführung Ein grundlegendes Problem in der Computergrafik ist es, aus einer dreidimensionalen Szene, deren Geometrien mit Materialien und Texturen versehen sind, eine Grafik zu berechnen, die demjenigen Bild entspricht, das ein menschlicher Betrachter von einer bestimmten Position in der Szene aus sehen würde; dieser Vorgang heißt rendern. Raytracing (deutsch: Strahlenverfolgung“) ist ein Verfahren, das ” dieses Problem löst und dabei durch die Verwendung verschiedener physikalischer Gesetze der Lichtausbreitung einen hohen Grad an Realismus erreicht. Der folgende Text gibt einen Überblick über die allgemeine Funktionsweise des Raytracings und die dort verwendeten Techniken. Zunächst sollen die Grundlagen des Renderings erläutert werden, anschließend wird erklärt, wie die einzelnen Schritte des Verfahrens ablaufen. Danach wird die Laufzeit eines allgemeinen Raytracing-Algorithmus’ analysiert und Formen der Optimierung vorgestellt. 3.2 Grundlagen des Renderings Ziel des Renderings ist es, ein zweidimensionales Abbild einer dreidimensionalen Szene zu erzeugen, so wie ein Betrachter in der Szene sie sehen würde. Folgende Problemparameter sind also gegeben: • eine Menge an geometrischen Primitiven (z. B. Polygone, Kugeln, implizit gegebene Flächen), bestimmt durch ihre Koordinaten im Raum, und deren 53 3.2. GRUNDLAGEN DES RENDERINGS 54 assoziierte Materialien bzw. Texturen • eine Menge an Lichtquellen mit deren Eigenschaften (Position, Farbe, Intensität, Form)1 • eine Betrachterposition ( Kameraposition“) und Blickrichtung ” Es soll als Ausgabe eine Raster-Grafik berechnet werden, die im Idealfall nicht mehr von einer Fotografie der gleichen Szene zu unterscheiden ist. Abbildung 3.1: Einfall von Lichtstrahlen in das Auge Dafür muss zunächst untersucht werden, wie das menschliche Auge Bilder wahrnimmt und die gewonnenen Erkenntnisse entsprechend auf das Gebiet der Computergrafik übertragen werden. Die Funktionsweise des Auges ist in Abbildung 3.1 skizziert: Licht einer gewissen Wellenlängenzusammensetzung (Spektrum) fällt durch die Pupille ein und trifft auf die Netzhaut, auf der sich Rezeptoren für bestimmte Wellenlängen des Lichtes befinden. Diese unterschiedlichen Wellenlängen werden vom Menschen als unterschiedliche Farben wahrgenommen, wobei es mehrere Spektren gibt, die die gleiche wahrgenommene Farbe erzeugen. Ein Bild“ ” zu berechnen, ist also äquivalent dazu, für jeden Bereich einer Fläche Intensität und Spektrum des dort auftreffenden Lichts zu bestimmen. [DSC93] behandelt umfassend die physikalischen Eigenschaften von Licht, die in der Computergrafik gebraucht werden, wie beispielsweise Ausbreitung, Brechung und Farbe. In der Computergrafik wird aus technischen Gründen die Position von Brennpunkt und Netzhaut vertauscht. Wie in Abbildung 3.2 gezeigt, wird dazu eine Bildebene, die senkrecht auf der Blickrichtung des Blickpunktes steht, definiert. Eine rechteckige Fläche auf dieser Bildebene wird in der Breite und in der Höhe in kleine Quadrate unterteilt, die den Pixeln auf dem zu berechnenden Bild entsprechen. 1 Es soll im Folgenden versucht werden, zwischen der Farbe, d. h. der Wellenlängenverteilung, und der Intensität, d. h. der Lichtstärke, angemessen zu unterscheiden, wo dies möglich ist. 3.3. DAS RAYTRACING-VERFAHREN 55 Abbildung 3.2: Umsetzung der Augenfunktion in der Computergrafik Die Aufgabe eines Renderverfahrens ist es nun, für jeden dieser Pixel einen Farbwert zu berechnen, der sich aus den in diesem Bereich sichtbaren Objekten ergibt. Da das, was der Mensch als Farbe“ wahrnimmt, sich jedoch ausschließlich ” aus den im Auge ankommenden Lichtwellen verschiedener Wellenlänge ergibt, bedeutet dies, dass im Wesentlichen die Lichtausbreitung in der modellierten Szene berechnet werden muss. 3.3 Das Raytracing-Verfahren Das Raytracing-Verfahren basiert darauf, die Ausbreitung der Lichtstrahlen in der Szene zu verfolgen; es ist damit ein globales Beleuchtungsmodell. Beim ForwardRaytracing wird von der Lichtquelle ausgehend das ausgesandte Licht verfolgt, auch über mehrere reflektierende Oberflächen hinweg, bis es entweder auf der Bildebene ankommt, sich aus der Szene hinaus bewegt oder zu schwach wird, um irgendeinen Einfluss auf das Bild haben zu können. Da nur ein winziger Bruchteil der anfangs ausgesandten Lichtstrahlen jemals im Bild ankommt, wird dieses Verfahren in der Praxis nicht verwendet. Wenn allgemein vom Raytracing-Verfahren die Rede ist, ist damit in der Regel das Backward-Raytracing gemeint. Dies bedeutet, dass vom Blickpunkt aus der eintreffende Lichtstrahl rückwärts verfolgt und dessen Ursprung auf einem Objekt in der 3D-Szene bestimmt wird. Anschließend kann durch verschiedene Verfahren, unter anderem durch weitere Aussendung von Strahlen und Einsatz eines lokalen Beleuchtungsmodells (siehe Kapitel 2.7.3), die Farbe und Intensität des in Richtung des Blickpunktes ausgesandten Lichtes von diesem Punkt aus berechnet werden, die dann der Farbe an dem jeweiligen Bildpixel entspricht. 3.3. DAS RAYTRACING-VERFAHREN 3.3.1 56 Schnittpunkt- und Normalenbestimmung Zunächst muss für jeden Pixel dasjenige Objekt bestimmt werden, das vom Blickpunkt aus in Richtung dieses Pixels gesehen“ wird. Sei dazu der Blickpunkt v ∈ R3 , ” die Blickrichtung d ∈ R3 und die Bildebene durch E := b + λr + µu | λ ∈ [0, wmax ] , µ ∈ [0, hmax ] gegeben (siehe Abbildung 3.3). Abbildung 3.3: Bildpunkt und Bildebene: Bezeichnungen Dabei legt b legt die untere linke Ecke des Bildausschnitts im Raum fest, u ∈ R3 ist der Vektor, der nach oben zeigt, (um verschiedene Rotationen der Kamera zu erlauben) und r ergibt sich als Kreuzprodukt von u und d. hmax und wmax sind die gewünschten Pixelanzahlen in der Höhe bzw. der Breite. Dann entspricht ein Bildpixel (x, y) gerade der Punktmenge {b + λr + µu | λ ∈ [x, x + 1] , µ ∈ [y, y + 1]} mit dem Pixelmittelpunkt m := b + (x + 12 )r + (y + 12 )u. Der vom Blickpunkt durch diesen Pixelmittelpunkt gehende Blickstrahl“ hat ” also die Gleichung v + λ(m − v), λ ≥ 0. Nun kann für jedes Primitiv der Szene der Schnittpunkt mit diesem Strahl berechnet werden, wenn es einen gibt. Im Folgenden werden für einige Primitivtypen Methoden zur Schnittpunktbestimmung vorgestellt. Da zur Berechnung der Lichtausbreitung später auch die Normalen am Schnittpunkt benötigt werden, wird auch gleich die Bestimmung eines Normalenvektors erklärt. 3.3. DAS RAYTRACING-VERFAHREN 57 Kugel Die Kugel2 ist ein sehr beliebtes Motiv in Raytracing-Szenen, da sich der Schnittpunkt eines Strahls mit einer Kugel sehr schnell feststellen lässt. Eine Kugel mit Mittelpunkt p ∈ R3 und Radius r ∈ R, r ≥ 0 ist die Punktmenge {x ∈ R3 | |x − p| = r}. Nun gilt |x − p| = r ⇔ |x − p|2 = r2 ⇔ |x − p|2 − r2 = 0 und durch Einsetzen der Strahlgleichung v + λd erhält man: 0 = |v + λd − p|2 − r2 = hv + λd − p, v + λd − pi − r2 = hv − p, v − pi + 2λ hv − p, di + λ2 hd, di − r2 = λ2 |d|2 + 2λ hv − p, di + |v − p|2 − r2 ⇐⇒ 0 = λ2 + λ 2 hv − p, di |v − p|2 − r2 + |d|2 |d|2 (Hierbei ist h., .i das euklidische Skalarprodukt.) Dann gilt unter der Voraussetzung |d| = 1 (d. h. mit normiertem Richtungsvektor): 2 q v − p, d − |v − p|2 + r2 λ1,2 = − v − p, d ± Der Einheitsnormalenvektor auf einem Punkt x auf einer Kugel ist gerade der normierte Richtungsvektor vom Kugelmittelpunkt p zu diesem Punkt auf der Oberfläche: 1 n = (x − p) r Dreieck Ein Dreieck mit den Eckpunkten a, b, c ∈ R3 ist die Menge {αa + βb + γc ∈ R3 | α, β, γ ≥ 0, α + β + γ = 1}, wobei jeder Punkt in diesem Dreieck eindeutig bestimmte Koeffizienten α, β, γ hat; dies nennt man die baryzentrische Darstellung. Der Strahl ist gegeben durch den Term v + λd mit λ ≥ 0, dabei soll |d| = 1 sein. Dann ist eine Lösung für die Gleichung v + λd = αa + βb + γc 2 Eigentlich geht es hier, mathematisch betrachtet, um eine Sphäre oder Kugelfläche, es soll jedoch im Folgenden der im allgemeinen Sprachgebrauch eher verbreitete Begriff der Kugel verwendet werden. 3.3. DAS RAYTRACING-VERFAHREN 58 gesucht. Man kann nun γ = 1 − α − β einsetzen und umformen in α(a − c) + β(b − c) − λd = v − c. Dies lässt sich als lineares Gleichungssystem schreiben: α a − c b − c −d β = v − c , λ welches mit den bekannten Verfahren für lineare Gleichungssysteme (z. B. GaußAlgorithmus) gelöst werden kann. Existiert eine Lösung mit α, β, 1 − α − β ≥ 0, λ > 0, so schneidet der Strahl das Dreieck, andernfalls geht er außen daran vorbei oder das Dreieck liegt hinter dem Startpunkt des Strahls. Den Schnittpunkt erhält man dann mit v + λd, die Normale n, unabhängig von der erhaltenen Lösung, durch das Kreuzprodukt (a − c) × (b − c). Hierbei muss man jedoch beachten, dass unter Umständen die Normale auf die Rückseite des Dreiecks zeigt, was in der Regel nicht erwünscht ist. Dazu prüfe man, ob hv − c, ni > 0; andernfalls sollte man das Vorzeichen des Normalenvektors ändern. Der Fall Strahl–Ebene ist eine Verallgemeinerung des Falls Strahl–Dreieck; man ersetze a−c und b−c durch die beiden die Ebene aufspannenden Richtungsvektoren (dann ist c Stützvektor) und lasse beliebige Werte für α und β zu. Achsenparalleler Quader Ein Quader wird im Raytracing-Verfahren häufig als Container für andere Objekte verwendet (z. B. als Bounding Box) und man will im Allgemeinen nur wissen, ob der Strahl diese Box schneidet oder nicht. Ein Quader kann als Schnittmenge von drei senkrecht aufeinander stehenden Paaren paralleler Ebenen betrachtet werden. Eine Ebene ist eindeutig bestimmt durch ihre Normale n und den Abstand a zum Ursprung. Betrachtet man nun nur achsenparallele Ebenen, so reicht die Angabe der Normalenrichtung d ∈ {x, y, z} (d. h. die Normale zeigt in Richtung der x-, y- oder z-Achse) und der Abstand zum Ursprung. Ein Ebenenpaar ist dann gegeben durch (ad1 , ad2 ) (sei o.B.d.A. ad1 ≤ ad2 ), die zwischen den beiden Ebenen enthaltene Punktmenge ist {p ∈ R3 | ad1 ≤ pd ≤ ad2 } und ein achsenparalleler Quader ist die Schnittmenge dreier Ebenenpaare in verschiedene Koordinatenrichtungen. Sei v + λr ein Strahl mit einem Intervall [a, b] der möglichen Parameterwerte, wobei dieses mit [0, ∞[ initialisiert wird. Nun kann man für jede Koordinatenrichtung das Intervall der Parameterwerte ausrechnen, in dem das von den Ebenen eingeschlossene Gebiet geschnitten wird und das mit dem Strahl gespeicherte Inter- 3.3. DAS RAYTRACING-VERFAHREN 59 vall entsprechend verkleinern: λ1 := vd − ad1 rd λmin := min(λ1 , λ2 ) λ2 := vd − ad2 rd (3.1) λmax := max(λ1 , λ2 ) (3.2) b := min(b, λmin ) (3.3) a := max(a, λmin ) Ist das Intervall [a, b] nach Behandlung aller drei Koordinatenrichtungen nicht leer, so schneidet der Strahl den durch die Ebenen berandeten Quader im Punkt v + a · r. Auswählen des sichtbaren Objekts Hat man eine Liste von λi für den Blickstrahl berechnet, wählt man daraus das kleinste aus, denn Punkte mit größeren Werten für λ sind sicherlich weiter vom Blickpunkt entfernt als Punkte mit kleineren Werten und werden folglich von diesen verdeckt (siehe Abbildung 3.4). Im Allgemeinen wird es durch numerische Rechenungenauigkeiten so sein, dass der berechnete Punkt nicht auf der Oberfläche eines Objekts liegt, sondern etwas davor oder dahinter. Damit bei der weiteren Aussendung von Strahlen nicht das Objekt selbst den ersten Schnitt erzeugt, kann es notwendig werden, das berechnete λ noch ein wenig nach unten zu korrigieren, damit der Punkt nicht hinter der Oberfläche liegt. Abbildung 3.4: Das erste geschnittene Primitiv ist das vom Betrachter aus sichtbare Objekt Damit ist dieser Abschnitt, die Bestimmung des sichtbaren Punktes, dessen Farbe nun noch ermittelt werden muss, abgeschlossen. Im Abschnitt 3.4 finden sich Methoden, diesen Teil des Verfahrens deutlich zu beschleunigen. 3.3.2 Farbbestimmung eines Punktes Aus dem vorherigen Abschnitt kennt man den Punkt p ∈ R3 auf einem Primitiv P ⊂ R3 , die Normale n ∈ R3 sowie die Richtung r ∈ R3 , in der der Betrachter 3.3. DAS RAYTRACING-VERFAHREN 60 auf p sieht, und muss nun die Farbe bestimmen, die von dort in Richtung des Blickpunktes v (also in Richtung −r) ausgesandt wird. Dazu überlegt man sich zunächst, welche Arten von Licht von p ausgehen können: • Licht, das direkt von platzierten Lichtquellen der Szene auf p fällt und in alle Richtungen reflektiert wird3 • gerichtet reflektiertes Licht, wie z. B. bei einem Spiegel • gerichtet transmittiertes Licht, wie z. B. bei einer Glaskugel • diffus reflektiertes Licht, wie auf matten Oberflächen zu beobachten • diffus transmittiertes Licht, wie z. B. bei einer Milchglasscheibe Diese Arten des Lichteinfalls sind unterschiedlich kompliziert zu bestimmen und müssen für das Berechnen eines realistisch wirkenden Bildes kombiniert werden. Hat man für p die möglichen Lichtquellen und -einfallsrichtungen berechnet, kann man mittels eines geeigneten Shading-Verfahrens in Abhängigkeit von Spektrum, Intensität, Entfernung, Einfallswinkel und gegebenenfalls weiteren Parametern das ausgesandte Licht berechnen; dies ist jedoch nicht das Thema dieser Arbeit (siehe stattdessen z. B. Kapitel 2.7.3). Im Folgenden soll daher nur gezeigt werden, was die genannten Kategorien des Lichteinfalls auszeichnet und wie man sie berechnen kann. Direkter Lichteinfall In der einfachsten Form des Raytracing muss bestimmt werden, von welcher der Lichtquellen Licht am Punkt p ankommt. Sicherlich macht es für die Erscheinung eines Objekts einen massiven Unterschied, ob es direkt von einer Lichtquelle beschienen wird oder bezüglich dieser Lichtquelle im Schatten eines anderen, lichtundurchlässigen (opaken) Objekts liegt. Zu prüfen ist folglich, ob und in welchem Maße Licht von der Menge L ⊂ R3 der gegebenen Lichtquellen auf p fällt. Dazu erstellt man für jede Lichtquelle l ∈ L einen Strahl p + λ(l − p) (einen sog. Schattenstrahl) und berechnet, ob es ein Objekt gibt, das diesen Strahl für λ ∈ [0, 1] schneidet. Wenn dies so ist, bekommt p 3 Genau genommen ist die Reflexion von Licht, das direkt von Lichtquellen kommt, nur ein Sonderfall der diffusen Reflexion. Dort ist der Fall gegeben, dass man zufällig weiß, aus welcher Richtung sehr starkes Licht kommt; dies wird aber nach den gleichen physikalischen Gesetzen behandelt wie die diffuse Reflexion im Allgemeinen. 3.3. DAS RAYTRACING-VERFAHREN 61 kein direktes Licht von l, denn der Weg der Lichtstrahlen von l zu p ist durch ein Objekt versperrt. Andernfalls erhält p direktes Licht von l, das dann teilweise zum Blickpunkt reflektiert wird. Die Intensität des in Richtung des Blickpunktes ausgesanten Lichts verhält sich dabei nach [Gla89] proportional zum Cosinus des Winkels zwischen Lichteinfall und Oberflächennormale. Hier gilt das Lambertsche Gesetz I = L · A · cos α, wobei I die Lichtstärke, L die Leuchtdichte und A die leuchtende Fläche ist. Dies bedeutet, dass die Intensität des ausgesandten Lichts am stärksten ist, wenn die Lichtquelle senkrecht über der Oberfläche steht; wenn sie sehr stark von der Seite strahlt, ist die Intensität geringer (vergl. Abbildung 3.5). Abbildung 3.5: Auswirkung des Einfallswinkels auf die ausgesandte Lichtstärke Gerichtete Reflexion und Transmission Abbildung 3.6: Zu verfolgende Lichtstrahlen bei idealer gerichteter Reflexion Aus der Erfahrung weiß man, dass auf spiegelnden Oberflächen der direkte 3.3. DAS RAYTRACING-VERFAHREN 62 Lichteinfall die Aussendung von Licht in Richtung des Blickpunktes nur bedingt beeinflusst. Steht man in einem bestimmten Winkel vor einem Spiegel, so sieht man nur noch das Licht, das in einem bestimmten anderen Winkel eingefallen ist. Dabei gilt für perfekte Spiegel das bekannte Gesetz Einfallswinkel = Ausfalls” winkel“; dies bedeutet, dass der Winkel α zwischen Betrachtungsrichtung r und Oberflächennormalen n der gleiche ist wie der Winkel β zwischen der Richtung l, aus der das gespiegelte Licht kommen muss, und der Oberflächennormalen, siehe Abbildung 3.6. Des weiteren liegen die Betrachtungsrichtung, Normalenvektor und Lichtursprungsrichtung in einer Ebene. Es kann (unter der Prämisse |r| = |n| = 1) mittels der beiden angegebenen Nebenbedingungen h−r, ni = hn, li und ∃ α, β : l = αr + βn für den ausgehenden Vektor mit Länge 1 folgende Formel bestimmt werden: l = r − 2 hn, ri · n (Die Gültigkeit der Forderungen ist leicht nachzuprüfen, die Herleitung findet sich in [Gla89].) Abbildung 3.7: Zu verfolgende Lichtstrahlen bei idealer gerichteter Transmission Ähnlich geht man bei Objekten vor, die aus einem Material bestehen, das zu einem Teil lichtdurchlässig ist. Auch hier kann das Licht, das von einem Punkt in eine gewisse Richtung ausgesandt wird, bei einem ideal transmittierenden Material aus genau einer Richtung kommen, man nennt das Material dann transparent. Dabei tritt das Phänomen der Lichtbrechung auf, d. h. der Winkel α zwischen Betrachtungsrichtung r und der Oberflächennormalen n ist abhängig vom Winkel γ zwischen der Richtung t, aus der das transmittierte Licht kommen muss, und der Oberflächennormalen, siehe Abbildung 3.7. Wieder liegen die Betrachtungsrichtung, Normalenvektor und Lichtursprungsrichtung in einer Ebene. 3.3. DAS RAYTRACING-VERFAHREN 63 Der Grad der Brechung hängt dabei immer von den beiden Materialien ab, an deren Grenze der Lichtstrahl gebrochen wird. Jedes Material hat einen Brechungsindex η, der das Verhältnis der Lichtgeschwindigkeit in diesem Material im Vergleich zur Lichtgeschwindigkeit im Vakuum angibt. Dann gilt nach Snells Gesetz sin α ηr = sin γ ηt Es kann passieren, dass beim Übergang von einem dichteren in ein weniger dichtes Material Totalreflexion auftritt, d. h. der Winkel zwischen einfallendem Licht und der Normalen ist so groß, dass keine Brechung mehr statt findet, sondern das Licht an der Innenseite der Fläche komplett reflektiert wird. Unter der Vorraussetzung |r| = |n| = 1 erhält man für den ausgehenden Vektor t in das zweite Material hinein die Formel: r ηr η r 2 ηr ·r+ cos α − 1 + · (cos α − 1) · n t= ηt ηt ηt (Die Herleitung findet sich, mit anderen Bezeichnungen, ebenfalls in [Gla89].) Ist der Term unter der Wurzel negativ, so ist dies gerade das Zeichen dafür, dass Totalreflexion auftritt; es ist dann stattdessen die Formel für die ideale Reflexion zu verwenden. In die jeweils berechnete Richtung l bzw. t kann man nun einen Strahl von p aus schicken und das Objekt finden, das diesen Strahl als erstes schneidet. Anschließend muss das von diesem Objekt am Schnittpunkt in Richtung −l (bzw. −t) ausgesandte Licht berechnet werden. Dies ist offenbar genau das gleiche Problem, wie das Ursprungsproblem, das an p in Richtung −r ausgesandte Licht zu bestimmen, daher kann man hier einen rekursiven Ansatz wählen; dies nennt man dann rekursives Raytracing, vergl. Abbildung 3.8. Der Rekursionsanker kann dann beispielsweise das Verlassen der Szene, eine bestimmte Rekursionstiefe oder ein zu gering werdender Anteil an der Gesamtintensität des von p ausgehenden Lichts sein. Ein Beispiel, bei dem intensiv von der Möglichkeit des rekursiven Raytracings Gebrauch gemacht wurde, ist in Abbildung 3.9 zu sehen. Diffuse Reflexion und Transmission Die im vorigen Abschnitt beschriebene gerichtete Reflexion findet so nur auf glatten, spiegelnden Oberflächen statt. Auf rauen, matten Oberflächen findet stattdessen diffuse Reflexion statt; dies bedeutet, dass einfallendes Licht aus einer Richtung in 3.3. DAS RAYTRACING-VERFAHREN 64 Abbildung 3.8: Beispiel für rekursives Raytracing und dazugehöriger Strahlenbaum Abbildung 3.9: Reflexion und Transmission an einem lebensnahen Beispiel (aus [PR]) alle Richtungen gleichmäßig ausgesandt wird. Daraus ergibt sich umgekehrt sofort das Problem, dass nicht eindeutig bestimmbar ist, aus welcher Richtung das Licht kommt, das in Richtung des Betrachters ausgesandt wird. Ein ähnliches Problem tritt auf, wenn ein Material zwar lichtdurchlässig ist, aber nicht die Möglichkeit einer gerichteten Transmission bietet, weil es im Innern viele Partikel gibt, die das Licht umlenken, wie z. B. bei Milchglas; man nennt das Material dann transluzent. Auch hier ist das Problem, dass Licht aus vielen 3.3. DAS RAYTRACING-VERFAHREN 65 Richtungen zum Farbwert am betrachteten Punkt beitragen könnte. Eine mögliche Herangehensweise an dieses Problem ist, den Einfluss der diffusen Reflexion bzw. Transmission zu vernachlässigen oder durch ein globales Umgebungslicht zu simulieren. Eine Alternative dazu bietet das stochastische bzw. verteilte Raytracing, das in [Coo89] umfassend beschrieben wird. Die Idee bei diesem Verfahren ist, statt nur eines Strahls in eine feste Richtung mehrere, mehr oder weniger zufällig verteilte Strahlen in ungefähr diese Richtung auszusenden und die erhaltenen Werte zu mitteln. Vergleich der Beleuchtungsarten Im Folgenden soll veranschaulicht werden, welche Konsequenzen die Berechnung der oben vorgestellten Arten des Lichteinfalls hat. Die verwendeten Bilder wurden aus [Wik] entnommen. Abbildung 3.10: Raytracing nur mit Verdeckungsberechnung (Raycasting) Abbildung 3.11: Raytracing mit jeweils einem Schattenstrahl pro Punkt In Abbildung 3.10 sieht man eine Szene, bei der nur Primärstrahlen ausgesandt wurden und die Farbe der Textur als einzige Größe für die Berechnung der Lichtaussendung in Richtung des Blickpunktes herangezogen wurde. Als Folge davon kann man sehen, dass korrekt festgestellt wurde, welches Objekt ein anderes Objekt verdeckt. Jede weitere Tiefeninformation geht jedoch verloren, da es keine Schatten und keine Auswirkungen von Lichtquellen gibt. In Abbildung 3.11 wurde zusätzlich von jedem Punkt auf einem getroffenen Objekt ein Schattenstrahl in Richtung der Lichtquelle (bzw. einem Punkt im Zentrum der Lichtquelle) ausgesandt. Man erkennt nun bereits die dreidimensionale Gestalt 3.3. DAS RAYTRACING-VERFAHREN 66 der Körper und deren Lage relativ zur Lichtquelle. Die Körper werfen Schatten mit harten Kanten, da im Schatten sein“ hier eine binäre Eigenschaft ist, es gibt keinen ” Halbschatten. An Wänden und Decke des Szene sowie an der Grenze von Licht und Schatten auf den Kugeln erkennt man den Einfluss des Einfallswinkels des Lichts (siehe Abschnitt 3.3.2). Abbildung 3.12: Raytracing mit jeweils einem Schattenstrahl pro Punkt und rekursiver Reflexions-/Transmissionsbestimmung Abbildung 3.13: Raytracing mit rekursiver Reflexions-/Transmissionsbestimmung und teilweise diffuser Reflexion In Abbildung 3.12 wurde die hintere Kugel als spiegelnd und die vordere als teils transparent, teils spiegelnd modelliert. Von dem jeweils getroffenen Punkt der Kugel wurden also rekursiv weitere Strahlen im jeweiligen Ausfalls- bzw. Brechungswinkel ausgesandt. In der vorderen Kugel erkennt man die Spiegelung der orangen Wand und der Lichtquelle und die durch Lichtbrechung im Inneren der Kugel umgedrehte blaue Wand, die sich hinter der Kugel befindet. Wände, Decke und Schatten sehen genauso aus wie im vorherigen Bild, da diese nicht perfekt spiegeln und daher keine veränderte Behandlung erfahren. In Abbildung 3.13 wurden zusätzlich zu den bisher eingesetzten Techniken zur Berechnung der diffusen Reflexion einige Strahlen in zufällige Richtungen ausgesandt. Dies kann man insbesondere an den Schatten mit weichen Rändern erkennen, die dadurch entstehen, dass von Punkten im Randbereich des Schattens einige Lichtstrahlen die Lichtquelle treffen, andere nicht, und die Mittelung der so erhaltenen Farbwerte zu einem Ergebnis zwischen vollständig im Schatten“ und ” nicht im Schatten“ führt. Auch der Bereich an der Decke um die Lichtquelle herum ” ist nun deutlich weicher berandet. 3.4. LAUFZEITBETRACHTUNGEN UND OPTIMIERUNG 3.4 3.4.1 67 Laufzeitbetrachtungen und Optimierung Analyse der Laufzeit Raytracing ist ein Verfahren, das hochqualitative Ergebnisse liefern kann, jedoch oft zum Preis einer langen Laufzeit. Zunächst einmal ist (von einer konstanten Anzahl von Strahlen pro Pixel ausgehend) die Anzahl der ausgesandten Primärstrahlen proportional zur Anzahl der Pixel des zu erzeugenden Bildes. Dies bedeutet, dass die Renderzeit direkt von der Auflösung des zu erzeugenden Bildes abhängt. Ohne weitere Optimierungen muss jeder Strahl gegen alle n in der Szene vorhandenen Objekte getestet werden. Dies gilt nicht nur für die O(xy) Primärstrahlen, sondern auch für alle Sekundärstrahlen, wie zum Beispiel die bei der Reflexionsoder Transparenzbestimmung ausgesandten Strahlen. Es soll daher zunächst die Anzahl s der Sekundärstrahlen bestimmt werden. In jeder Ebene des Strahlenbaums (vergl. Abbildung 3.8) wird zu jeder Lichtquelle ein Strahl gesandt und ein Reflexionsstrahl und ein Transmissionsstrahl erzeugt. Die letzten beiden erzeugen wieder Schnittpunkte, von denen das Gleiche aus geschieht. Die Anzahl der Sekundärstrahlen im Strahlenbaum mit Tiefe d ist also: sd = (|L| + 2) + 2(|L| + 2) + 4(|L| + 2) + . . . = (2d − 1)(|L| + 2) ∈ O(2d ), wobei |L| die Anzahl der Lichtquellen ist. Wenn für jeden Strahl n Objekte auf Schnitt getestet werden müssen und d als Obergrenze für die Tiefe des Strahlenbaums festgelegt wird, ergibt sich als Gesamtanzahl der Schnittoperationen: O xy · (1 + sd )n = O(n · xy · 2d ) 3.4.2 Verbesserungen der Laufzeit Die im vorherigen Abschnitt bestimmte Anzahl der Schnittpunktbestimmungen ist linear in der Anzahl der Pixel, der Objekte und exponentiell in der Tiefe des Strahlenbaums. Nach [AK89] werden 95% der Laufzeit eines Raytracing-Rendervorgangs auf Schnittpunkttests verwendet; es besteht also – gerade in Bildern mit großem d, d. h. vielen Spiegelungen (vergl. Abbildung 3.9) – durchaus Optimierungsbedarf. In [AK89] werden die Techniken zur Beschleunigung in folgende Kategorien eingeteilt: • schnellere Schnittpunktbestimmung (schnellere bzw. weniger Strahl-ObjektSchnittoperationen) 3.4. LAUFZEITBETRACHTUNGEN UND OPTIMIERUNG 68 • weniger Strahlen, z. B. durch adaptive Tiefenkontrolle des Strahlenbaums • verallgemeinerte Strahlen, d. h. verfolge ein Volumen (z. B. Kegel) statt eines Strahls Die Geschwindigkeit der Strahl-Objekt-Schnittoperationen kann man verbessern, indem man Algorithmen zur Schnittpunktbestimmung entwickelt, die mit möglichst wenig Elementaroperationen (Multiplikation, Addition etc.) auskommen, wie sie beispielsweise bei [Han89] und [Hai89] vorgestellt werden. Da diese Optimierungen häufig wenig anschaulich sind, sollen im Folgenden nur Methoden zur Reduktion der Anzahl der Strahl-Objekt-Schnittoperationen erläutert werden. Wie oben beschrieben, muss prinzipiell jeder Strahl gegen jedes Objekt getestet werden. Dies ist jedoch, gerade bei zunehmend komplexer werdenden Szenen, ein Problem; insbesondere, weil nur der erste Schnittpunkt für den Strahl interessant ist. Eine Idee, die die Laufzeit eines Raytracing-Algorithmus’ beschleunigen kann, ist es daher, effiziente Indexstrukturen einzuführen; zwei Möglichkeiten dafür werden im Folgenden erläutert. Objekthierarchien Eine Möglichkeit, die Anzahl der Schnittpunkttests zu reduzieren, ist das Verschachteln von mehreren Objekten in ein gemeinsames Elternobjekt, das einfacher auf Schnitt mit einem Strahl zu prüfen ist. Es können beispielsweise mehrere Primitive in einer Kugel zusammengefasst werden, diese dann wieder in einem größeren Objekt, usw., bis zum Schluss alle Objekte in einem großen Container-Objekt zusammengefasst sind. Ein Beispiel für diese Situation ist in Abbildung 3.14 gezeigt. Wird nun ein Strahl in den Raum geschossen, wird zunächst das Wurzelobjekt auf Schnitt geprüft. Gibt es einen Schnittpunkt, werden alle Kindobjekte geprüft, dann ggf. deren Kinder usw., bis es entweder kein Objekt mehr gibt, das den Strahl schneidet, oder so weit in der Objekthierarchie hinabgestiegen wurde, bis ein Strahl-Primitiv-Test durchgeführt werden muss. Bei der Auswahl der Art der Container-Objekte (z. B. Kugel, Quader, Zylinder) muss man zwischen Geschwindigkeit des Schnittpunkttests und Genauigkeit der Unterobjektapproximation abwägen. Sicherlich ist es besser, wenn das ContainerObjekt so genau wie möglich das enthaltene Objekt annähert, denn dann ist die Wahrscheinlichkeit geringer, dass man den Container trifft, obwohl das eigentliche Objekt nicht getroffen wird. Andererseits wird der Aufwand des Strahl-ContainerSchnittpunkttests höher, je komplizierter der Container ist und unter Umständen 3.4. LAUFZEITBETRACHTUNGEN UND OPTIMIERUNG 69 Abbildung 3.14: Objekthierarchie mit Kreisen als Container-Objekten (7 Kreisschnitt- und 1 Primitivschnitt- statt 11 Primitivschnitttests) gewinnt man dann keinen Geschwindigkeitsvorteil mehr. Eine Erweiterung dieses Verfahrens ist beispielsweise die Verwendung mehrerer Container-Objekte unterschiedlichen Typs, die alle geschnitten werden müssen, bevor ein Test mit dem enthaltenen Primitiv durchgeführt wird. Zur weiteren Optimierung kann man zu einem Strahl v + λr außer Startpunkt v und Richtung r auch noch ein Intervall [a, b] ⊂ R speichern, aus dem der Parameter λ sein darf. Davon kann man profitieren, wenn man eine Tiefensuche im ContainerBaum durchführt und nach jedem erfolgreichen Strahl-Primitiv-Test das obere Ende des Intervalls so setzt, dass es gerade noch den berechneten Schnittpunkt enthält, aber keine Punkte, die weiter vom Startpunkt des Strahls entfernt sind. Dann braucht ein Container-Objekt, dessen nächster Punkt erst bei einem λ > b geschnitten wird, nicht weiter untersucht zu werden, denn es kann sicher keine Objekte mehr enthalten, die näher an v sind als eines der bisher gefundenen. Raumaufteilung Eine Alternative zur Gruppierung von Objekten ist die Partition des Raumes in Bereiche, die dann nur noch eine Teilmenge der Objekte enthalten. Ein Beispiel dafür ist das Binary Space Partitioning (BSP)4 , bei dem durch Ebenen eine Aufteilung des Raums in Halbräume vorgenommen wird, bis jeder Bereich nur noch eine festgelegte Anzahl an Primitiven enthält, vergl. Abbildung 3.15. Zu jedem Blatt des BSP-Baums wird dann eine Liste der Objekte, die im entsprechenden 4 Sowohl BSP-Bäume als auch ähnliche Strukturen wie Octrees oder k-d-Bäume sind in jedem Standardwerk über Algorithmen ausführlich beschrieben. [dB93] beschäftigt sich zu großen Teilen mit speziellen Techniken zur Reduktion von Schnittpunkttests. 3.5. AUSBLICK 70 Bereich liegen, gespeichert. Abbildung 3.15: BSP-aufgeteilter Bereich und entsprechender BSP-Baum Wenn nun der erste Schnittpunkt eines Strahls mit einem Objekt aus der Szene bestimmt werden soll, wird, beginnend bei der Wurzel des BSP-Baums, immer dasjenige Kind des Knotens zuerst betrachtet, das den Bereich repräsentiert, der näher am Startpunkt des Strahls liegt. Mit dieser Methode erreicht man zuerst das Blatt des Baums, dessen assoziierter Bereich am nächsten am Startpunkt liegt. Gibt es einen Strahl-Primitiv-Schnittpunkt in diesem Bereich, kann abgebrochen werden, denn es gibt sicherlich kein Primitiv, das noch näher am Startpunkt des Strahls ist. Andernfalls muss man den zum jeweiligen Elternknoten gehörenden anderen Bereich prüfen und ggf. wieder eine Ebene nach oben gehen. Durch Anpassung der Grenzen des Intervalls, aus dem die Parameterwerte λ des Strahls kommen können, kann man bestimmte Unterbäume gleich vollständig von der Suche ausschließen. Mit Hilfe der in diesem Abschnitt vorgestellten Techniken ist es möglich, die Anzahl der Schnittpunkttests pro Strahl in eine Größenordnung von O(log n) zu bringen. 3.5 Ausblick In der vorliegenden Arbeit wurden die Grundlagen des Renderings im Allgemeinen und des Raytracings im Speziellen erläutert. Es wurde ausgeführt, welche Arten des ausgesandten Lichts es gibt und wie man für einen gewissen Punkt in der Szene die beeinflussenden Lichtquellen bestimmt. Die durch die verschiedenen Techniken erzeugten Effekte wurden demonstriert, eine Laufzeitanalyse durchgeführt und Techniken der Geschwindigkeitsoptimierung vorgestellt. 3.5. AUSBLICK 71 Ein Thema, das in dieser Arbeit nicht ausführlich behandelt wurde, sich aber für den interessierten Leser zur Vertiefung anbietet, ist das stochastische Raytracing. Damit lassen sich mit vergleichsweise einfachen Methoden Effekte wie weiche Schatten, Tiefenunschärfe, verschwommene Reflexionen, Kantenglättung und Bewegungsunschärfe simulieren. Kapitel 4 Geometric Modelling: Approximation und Interpolation von Kurven und Flächen. Von Flächen zu Objekten Jacqueline Spexard 4.1 4.1.1 Bezierkurven Renault auf dem Vormarsch Die 60er Jahre waren eine Zeit des Aufschwungs und des allgemeinen Wohlstands. Eine Zeit in der Luxusgüter, wie zum Beispiel Autos, für Normalbürger erschwinglich wurden. Da zu dieser Zeit Viele Arbeitsschritte von Maschinen übernommen wurden,wurde die Produktion einzelner Güter billiger. Es handelte sich nicht mehr um mühsame Handarbeit. Man entwickelte Maschinen und Methoden, um effizienter zu arbeiten und zu produzieren. So hatte auch der französische Ingenieur der Firma Renault, Bezier, zu dieser Zeit eine Methode entwickelt Kurven zu modellieren, ohne dabei von Schablonen, Modellen und Skizzen abängig zu sein. Durch Beziers neue Methode sind viele Arbeitschritte bei der Modellierung weggefallen. Früher wurden zunächst Skizzen und kleine Modelle aus Ton angefertigt .Diese wurden dann von Designern korrgiert. Erst dann wurde ein 72 4.1. BEZIERKURVEN 73 originalgroßes Modell aus Sperrholz und Ton hergestellt. Dieses Modell wurde dann erstmals den Managern präsentiert, die noch Ideen und Korrekturen einbringen konnten. Nachdem diese Änderungen durchgeführt wurde, konnte man mit Hilfe des Rohmodells ein serienreifes Modell produzieren. Allerdings verging vom Entwurf bis zur Produktion meistens mehr als ein Jahr. Dieser lange Arbeitsverlauf, der auf Erfahrung, Experementieren und handwerklichem Geschick basierte, konnte durch Beziers leichte mathematische Berechnungen enorm verkürzt werden. 4.1.2 Wie entstehen Bezierkurven? Definition Bezierkurven werden mit Hilfe polynomieller Basisfunktionen (genannt Bersteinpolynome) und n Kontrollpunkten erstellt.Dabei wird jede Basisfunktion durch jeweils einen Kontrollpunkt skaliert. B(t) = n X Un,i (t)Pi 0≤t≤1, 0≤i≤n i=0 Dazu das Bersteinpolynom(Basisfunktion). n Un,k (t) = (1 − t)n−k tk k Eigenschaften Die dadurch entstandene Bezierkurve liegt immer in der konvexen Hülle der KonP trollpunkte, da die Summe der Basisfunktionen immer 1 ergibt. ni=0 Un,i (t) = 1 Die Kontrollpunkte definieren demnach auch den ungefähren Verlauf der Kurve. Aufsteigend miteinander verbunden, bilden die Kontrollpunkte das so genannte Stützpolygon. Aus der Definition der Bezierkurve und insbesondere der Bernsteinpolynome gilt, dass der Grad der Kurve bestimmt wird durch die Anzahl der Kontrollpunkte minus eins. Des Weiteren gilt, dass der Anfangs- und Endpunkt des 4.1. BEZIERKURVEN 74 Abbildung 4.1: Basisfunktionen Bezier immer interpoliert wird. P0 = B(0) und Pn = B(1) Die Gerade zwischen P0 und P1 bildet die Tangente zum Anfangspunkt. Gleiches gilt für den Endpunkt mit der Geraden Pn−1 und Pn Abbildung 4.2: Beispielkurve mit 4 Kontrollpunkten Ferner gilt für Bezierkurven die variation diminishing property, die besagt, dass eine beliebig durch die Kurve gesetzte Gerade die Kurve nicht öfter als das Stützpolygon schneidet. Bezierkurven lassen sich zwar generell für jeden beliebigen Grad bauen, jedoch steigt der Rechenaufwand ab Grad drei enorm. In der Praxis 4.1. BEZIERKURVEN 75 arbeitet man normalerweise mit kubischen Bezierkurven (Grad 3), da diese keinen so hohen Berechnungsaufwand haben und trotzdem zu akzeptierenden Ergebnissen führen. Kubische Bezierkurven Eine kubische Bezierkurve ist eine von 4 Kontrollpunkten(P0 ,P1 ,P2 ,P3 ) umschlossene Kurve. Um den genauen Verlauf der Kurve zu berechnen, braucht man das Bernsteinpolynom, welches folgendermaßen definiert ist: n Un,k (t) = (1 − t)n−k tk k Für kubische Beziers entstehen demnach folgende 4 Polynome: U3,0 (t) = (1 − t)3 U3,1 (t) = 3(1 − t)2 t U3,2 (t) = 3(1 − t)t2 U3,3 (t) = t3 Abbildung 4.3: Bernstein-Basisfunktionen für Kurven vom Grad 3 Um jetzt die gewünschte Kurve zu erhalten multipliziert man diese 4 Polynome 4.1. BEZIERKURVEN 76 jeweils mit den 4 Kontrollpunkten (P0 ,P1 ,P2 ,P3 ) und addiert diese dann zusammen: B(t) = n X Un,i (t)Pi i=0 also B(t) = U3,0 (t)P0 + U3,1 (t)P1 + U3,2 (t)P2 + U3,3 (t)P3 .. . B(t) = (Qx (t), Qy (t)) Man erhält in vektorschreibweise ein Polynom Qx (t) für die x-Achse und Qy (t) für die y-Achse, wobei t zwischen 0 und 1 liegt(0≤t≤1). Wenn man jetzt t zwischen 0 und 1 laufen lässt, zeichnet ein imaginärer Stift unsere Kurve. Man sieht, dass alle Basisfunktionen über das ganze Intervall ]0, 1[ immer größer als null sind. Das hat den Effekt, dass sobald sich ein Kontrollpunkt verändert, sich der Verlauf der gesamten (global) Kurve ändert. Da die Beziers Summe der Kontrollpunkte multipliziert mit den Basisfunktionen sind, folgt daraus, dass man mit der Beziermethode keinen lokalen Einfluss auf die Kurve nehmen kann. Kleines Beispiel Um sich das Vorgehen genauer vorstellen zu können, hier ein kleines Beispiel: Wir nehmen folgende Kontrollpunkte und die Formel: P0 (0, 0), P1 (1, 2), P2 (2, 3), P3 (3, 1) B(t) = U3,0 (t)P0 + U3,1 (t)P1 + U3,2 (t)P2 + U3,3 (t)P3 Wenn man nun die 4 Kontrollpunkte einsetzt entsteht folgende Gleichung: B(t) = (1 − t)3 (0, 0) + 3t(1 − t)2 (1, 2) + 3t2 (1 − t)(2, 3) + t3 (3, 1) Daraus berechnet sich folgender Polynomvektor P (t) = (Qx (t), Qy (t)): B(t) = ((3t), (6t − 3t2 − 2t3 )) Wenn man nun t in 0,01 Schritten von 0 bis 1 laufen lässt, erhält man folgenden Graphen: 4.1. BEZIERKURVEN 77 Abbildung 4.4: Bezierkurve mit den 4 Kontrollpunkten: P0 (0, 0), P1 (1, 2), P2 (2, 3), P3 (3, 1) Komplexere Beziers Wie schon vorher erwähnt, verwendet man Beziers eigentlich nur bis Grad 3, da sonst der Rechenaufwand zu hoch wird. Man versucht dieses Problem des hohen Rechenaufwands zu umgehen, indem man Kurven niederen Grades(meist dritten Grades) zu einer komplexeren Kurve zusammensetzt. Um einen schönen glatten Übergang zu gewährleisten, müssen bestimmte Stetigkeitsbedingungen beim Zusammensetzen erfüllt sein. Es gibt zwei verschiedene Arten von Stetigkeit die C-Stetigkeit und die GStetigkeit(geometrische Stetigkeit). Sobald eine Kurve C-stetig ist,ist sie auch G-stetig. Jedoch folgt nicht aus der G-Stetigkeit die C-Stetigkeit. Die geometrische Stetigkeit ist eine abgeschwächte Form der C-Stetigkeit. Da sich die C-Stetigkeit in der Praxis oft nicht realisieren lässt, verwendet man die abgeschwächte Form. Wir betrachten nur die G-Stetigkeit. G0 -Stetigkeit(positionelle Stetigkeit) Für die positionelle Stetigkeit muss gelten, dass zwei Kurven sich in einem Punkt berühren.Kann aber zu Knicken führen. Werden zwei Bezierkurven am gleichen Kontrollpunkt zusammengestzt, ist die positionelle Stetigkeit gewährleistet. Da unsere Kurve aber einen möglichst glatten Übergang haben soll, reicht diese Bedingung nicht aus. 4.1. BEZIERKURVEN 78 Abbildung 4.5: positionelle Stetigkeit = G0 − Stetigkeit G1 -Stetigkeit(tangentielle Stetigkeit) Die Tangente, die durch den Verbindungspunkte läuft muss bei beiden Verbindungsstücken die gleiche Steigung haben. Sobald der vorletzte Punkt der ersten Kurve, der Verbindungspunkt und der zweite Punkt der zweiten Kurve kollinear sind, wird die Kurve G1 -stetig. Demnach können wir auch die tangentielle Stetigkeit bei Bezierkurven erreichen. Abbildung 4.6: tangentielle Stetigkeit = G1 − Stetigkeit 4.1.3 Nachteile der Bezierkurven Die Bezierkurven können noch nicht die optimale Lösung sein, da sie mehrere Probleme aufweisen: 1. Der Grad der Kurve ist abhängig von der Anzahl der Kontrollpunkte. 2. Der Verlauf der Kurve lässt sich nur global ändern. Die Bezierkurve ist demnach nicht die ideale Lösung in der Computergrafik, hat diese aber sicherlich enorm beeinflusst. Der Vorteil der Bezierkurven liegt in der 4.2. B-SPLINES 79 Einfachheit.Nach wie vor sind sie ein beliebter Modellierungsapperat und werden auch heute noch für beispielsweise Schriftdesign eingesetzt. Jedoch lassen die oberen Probleme bestimmte Modellierungen nicht zu. Diese verlangten einen anderen Lösungsansatz. Die B-Splines. 4.2 B-Splines 4.2.1 Mit Schiffen fing alles an Der Ursprung der B-Splines liegt im Schiffsbau.Um einen Schiffsrumpf zu bauen, wurden große Metallstreifen (Splines) in die gewünschte Form gebracht und mit Gewichten (Knots) fixiert. Durch die Gewichte konnte man die Metallstreifen auch lokal beeinflussen. Eine Eigenschaft, die man bei den B-Splines ebenfalls erreichen wollte. 4.2.2 Definition von B-Splines Ähnlich wie bei Bezierkurven, entstehen B-Splines mit Hilfe von Basisfunktionen und Kontrollpunkten.Auch hier werden die Basisfunktionen durch n Kontrollpunkte skaliert. C(u) = n X Ni,k (u)Pi a≤u≤b i=0 Dabei entstehen die Basisfunktionen folgendermaßen 1 falls t < t i i+1 und ti ≤u≤ti+1 Ni,1 (u) = 0 sonst und Ni,k (u) = (u − ti )Ni,k−1 (u) (ti+k − u)Ni+1,k−1 (u) + ti+k−1 − ti ti+k − ti+1 Achtung: Eine Division durch Null ist hier erlaubt, das heißt 0/0 wird gleich 0 gesetzt. Die Basisfunktionen entstehen mit Hilfe des Knotenvektors T = (t0 ...tj ). Ein Knotenvektor definiert Teilintervalle eines großen Intervalls [a, b]. Es gibt zwei 4.2. B-SPLINES 80 Arten von Knotenvektoren,mit deren Hilfe man zwei verschiedene B-Spline-Typen erstellen kann. 1. Zum einen die uniformen (einheitliche) B-Splines (Abstand der Knotenwerte im Knotenvektor ist immer gleich groß.Knotenwerte sind aufsteigend sortiert) 2. Zum anderen die nicht-uniformen B-Splines (non-uniform-B-Splines genannt) (Abstände der Knotenwerte im Knotenvektor variieren.Werte können sich wiederholen. Auch hier sind die Knotenwerte aufsteigend sortiert.) Des Weiteren gilt für B-Splines, dass der Grad der Kurve nicht mehr von der Anzahl der Kontrollpunkte abhängt. Man kann beliebig viele Kontrollpunkte wählen, nämlich Pi ,wobei 0≤i≤n. Also hat man n + 1 Kontrollpunkte. Auch den Grad der Kurve kann man vorher selber definieren. Dieser ist definiert durch k = Grad + 1. Grundsätzlich gilt, je höher der Grad umso glatter wird die Kurve und entfernt sich immer mehr den Kontrollpunkten. 4.2.3 Uniform-B-Splines Ähnlich wie bei den Beziers, werden die uniformen B-Splines durch kontrollpunktskalierte Basisfunktionen erstellt. Abbildung 4.7: Basisfunktionen eines uniformen B-Splines Der Unterschied hierbei ist, dass der B-Spline mit Hilfe des Knotenvektors in 4.2. B-SPLINES 81 Kurvensegmente unterteilt wird. Diese Kurvensegmente sind über aufeinanderfolgenden Intervallen gleicher Länge definiert. Jedes Kurvensegment besteht dabei aus vier Kontrollpunkten (für kubische B-Splines). und liegt in der konvexen Hülle dieser vier Punkte. Benachbarte Kurvensegmente teilen sich jeweils drei Kontrollpunkte.Demnach hat man bei den B-Splines n − 1 Kurvensegmente. Die Aufteilung in Kurvensegmente hat zur Folge, dass wir unseren B-Spline auch lokal beeinflussen können. Abbildung 4.8: Beispiel für lokale Manipultion eines B-Spline Für uniforme B-Splines gelten die im vorherigen Kapitel beschriebenen Bedingungen. Der Knotenvektor ist für uniforme B-Splines folgendermaßen definiert. Der Abstand der Knotenwerte im Knotenvektor ist immer gleich groß. Die Knotenwerte sind aufsteigend sortiert. tj+1 − tj = konstant, ∀j Hierzu sei gesagt, dass im Allgemeinen bei uniformen B-Splines der Anfangs- und Endpunkt nicht interpoliert wird. Unsere Basisfunktionen für uniforme B-Splines mit sechs Kontrollpunkten sehen folgendermaßen aus.(Siehe Abb.:1.7) Da sich jedes Kurvensegment drei Punkte teilt, fangen wir erst ab u = 3 bis u = 6 an die Kurve zu zeichnen. Also besteht demnach unser erstes Kurvensegment S3 aus den Punkten P0 , P1 , P2 und P3 . S4 aus den Punkten P1 , P2 , P3 und P4 . S5 aus den Punkten P2 , P3 , P4 und P5 . Der Knotenvektor sieht folgendermaßen aus: T = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) Wobei wieder jeweils ein Polynomvektor für die Kurvensegmente entsteht. Lässt man also u von 3 bis 6 laufen, entsteht folgende Kurve. 4.2. B-SPLINES 82 Abbildung 4.9: Entstandener B-Spline Möglichkeit der Interpolation Man kann auch bei uniformen B-Splines sich an Kontrollpunkte annähern beziehungsweise interpolieren. um das zu erreichen, definiert man Kontrollpunkte einfach mehrfach. Wenn man einen Kontrollpunkt mehrfach definiert nähert sich das Kurvensegment diesem Kontrollpunkt an. Wenn aber die Anzahl der hinzugefügten gleichen Kontrollpunkte genauso groß ist wie der Grad der Kurve, dann wird dieser Punkt interpoliert. Allerdings auf Kosten der Stetigkeit. Abbildung 4.10: Mehrfache Definition eines Kontrollpunktes; das rechte Bild zeigt nur noch einen G0 -stetigen Übergang 4.2.4 Non-uniform B-Splines Der non-uniforme B-Spline unterscheidet sich von uniformen B-Splines nur im Knotenvektor. Hierbei gilt nur, dass tj ≤tj+1 ∀j.Das heißt bei diesem Knotenvektor sind alle Eingaben erlaubt, sie müssen nur aufsteigend sortiert sein. Ansonsten unterscheidet sich die Berechnung nicht von uniformen B-Splines. Es gibt noch einen Spezialfall des Knotenvektors. Es handelt sich dabei um eine Unterart des 4.2. B-SPLINES 83 non-uniform Knotenvektortypen. Den open-uniform knot-vector: 0 falls j < k tj = j − k + 1 falls k≤j≤n n − k + 2 falls j > n Dieser definiert die Anfangs- und Endwerte des Knotenvektors mehrfach. Dadurch wird der Anfangs- und Endpunkt des B-Spline interpoliert. Abbildung 4.11: Beispiel für eine open-uniform (bzw.non-uniform) Basisfunktion Bezierkurven sind ein Spezialfall der open uniform B-Splines. Dieser Fall ensteht,wenn die Anzahl der Kontrollpunkte um eins höher ist wie der Grad der Kurve. Wenn also folgender Knotenvektor ensteht, berechnet man wieder eine Bezierkurve. Durch die Mehrfachdefinition von 0 und 1 wird der Anfangs- und Endkontrollpunkt interpoliert. T = ( 0...0 |{z} 1...1 |{z} ) k−mal k−mal Man hat bei den non-uniformen B-Splines auch die möglichkeit die Kurve näher an einen bestimmten Punkt heranzuführen oder gar zu interpolieren. Allerdings nicht über die Kontrollpunkte, sondern mit Hilfe des Knotenvektors. Wie man auch schon bei dem open-uniform B-Spline gesehen hat, muss man einfach Knotenwerte mehrfach im Knotenvektor definieren (genannt: multiplizieren). Dadurch verschieben verschmelzen die einzelnen Teilintervalle. Sobald die Basisfunktionen in einem Punkt eine Spitze bilden, wurde ein Kontrollpunkt interpoliert. Wir haben hier also eine weitaus elegantere Möglichkeit komplexe Kurven zu modellieren, die nicht mehr die gleichen Probleme haben wie die Bezierkurven. Selbst die G2 −Stetigkeit ist auf der gesamten Kurve definiert. 4.2. B-SPLINES 84 Beispiel für eine Interpolation bei non-uniformen B-Splines Genauer gesagt bei open-uniformen B-Splines. Zunächst betrachten wir uns unsere Kurve.Die Basisfunktionen haben vier Teilintervalle (Kästchen oben rechts). Das heißt außer dem Anfangs- und Endpunkt, übt jeder Punkt einen gleichmäßigen Einfluss auf die Kurve aus. Die blauen Punkte kennzeichnen die einzelnen Teilintervalle. Abbildung 4.12: B-Spline ohne Manipulation Hier sieht man nun, wie sich die Basisfunktionen verschieben und die vier Teilintervalle zu drei Teilintervallen verschmelzen. Die Basisfunktionen addieren sich in dem verkleinerten Intervall auf und dadurch erhöht sich der Einfluss des einen Kontrollpunktes auf die Kurve. Der Punkt P3 zieht hier also stärker die Kurve an sich heran. Abbildung 4.13: Annäherung an Punkt P3 Hier werden die drei Teilintervalle der Basisfunktionen zu zwei Teilintervallen verschmolzen. Da die Basisfunktionen sich zu eins aufaddieren, wird der Kontrollpunkt P3 interpoliert. Damit entfällt auch die G1 − Stetigkeit. 4.2. B-SPLINES 85 Abbildung 4.14: P3 wurde interpoliert 4.2.5 Zusammengefasst Mit den B-Splines haben wir nun eine Methode gefunden komplexe Kurven zu beschreiben, ohne dass sie von der Anzahl der Kontrollpunkte abhängen. Des Weiteren können wir nun auch lokal Einfluss auf die Kurve nehmen. Das war bei den Beziers nicht möglich. Also haben wir mit den B-Splines die Probleme der Bezierkurven umgangen. Ein weiterer Vorteil zu den Bezierkurven ist, dass die B-Splines auch G2 -Stetig sind. G2 -Stetigkeit(Krümmungstetigkeit) Bei der Krümmungsstetigkeit muss gelten, dass an jedem beliebigen Punkt einer beliebigen Kurve, ein Kreis sich an die Kurve anschmiegen kann. Wird Krümmungskreis genannnt. In jedem Krümmungskreis gibt es einen Krümmungsvektor. Die Krümmungsvektoren unterscheiden sich nur im Betrag. Da aber die B-Splines mit Polynomen arbeiten, können wir Kreise und Ellipsen (Kegelschnitte) nur annähern, aber nicht exakt beschreiben. Also muss auch hier eine bessere Lösung gefunden werden. Die NURBS. 4.3. NURBS (NON-UNIFORM RATIONAL B-SPLINES) 4.3 86 NURBS (non-uniform rational B-Splines) Die NURBS-Kurven gehören zu der Klasse der rationalen Splines.(B-Splines waren non-rational) Diese haben den Vorteil, dass sie Kreise und Ellipsen genau beschreiben. Ähnlich wie bei B-Splines berechnen sich die NURBS mit Hilfe von Kontrollpunkten und Basisfunktionen. Die NURBS sind rational, da wir nochmal durch die Summe teilen allerdings ohne die Kontrollpunkte. Pn Ni,k (u)wi Pi Cn,k (u) = Pi=0 n i=0 Ni,k (u)wi Die Basisfunktionen werden wieder durch die Kontrollpunkte skaliert. Allerdings taucht hier noch ein weiterer Parameter wi auf, der als Gewicht bezeichnet wird. Der Gewichtsparameter beeinflusst die Kurve nur in seinem Kurvensegment, also wieder lokal. Das Gewicht zieht die Kurve näher an den Kontrollpunkt heran. Es gilt für NURBS, dass der Anfangs- und Endpunkt interpliert wird. C(0) = P0 und C(1) = Pn Rationale NURBS können auch wieder nicht-rational werden, wenn der Gewichtsparameter folgendermaßen aussieht: wi = 1 ∀i, dann Rn,k (u) = Nn,k (u) Abbildung 4.15: Durch Gewichte beeinflusster NURB Non-rationale B-Splines und Bezierkurven sind Spezialfälle der NURBS. (Außerdem auch rationale Bezierkurven, wurden in dieser Arbeit aber nicht aufgeführt.) 4.4. VON KURVEN ZU FLÄCHEN 87 Ansonsten haben wir die gleichen Parameter wie bei den B-Splines.Die NURBS werden durch die folgenden Eigenschaften definiert: 1. Kontrollpunkte 2. Knotenvektor/Knoten 3. Grad 4. Gewicht Der NURB liegt (auch schon wie bei den B-Splines) in der konvexen Hülle eines kontrollpunkt-definierten Kurvensegments. Des Weiteren erfüllen NURBS die variation diminishing property. Außerdem sind NURBs Gn -stetig, was uns die optimale Glattheit der Kurve sichert. Bei den NURBS kann man also nicht nur die Kontrollpunkte verschieben, die Knotenwerte ändern, sondern zusätzlich auch Gewichte definieren. Das ermöglicht uns eine weitaus genauere und differenziertere Manipulation der Kurve. Entscheidenden Vorteile der NURBS: 1. interaktives Platzieren und Bewegen von Kontrollpunkten 2. interaktives Platzieren von Knotenpunkten 3. interaktives Steuern der Kontrollpunkt-Gewichte 4. lokale Kontrolle Durch die Genauigkeit und die Manipulationsmöglichkeiten sind die NURBS ein sehr beliebter Modellierungapperat. Berühmte Entwicklungsumgebungen wie Maya, 3dsMax und Rhinoceros verwenden NURBS. 4.4 4.4.1 Von Kurven zu Flächen Biliniar Patches Patches sind auch Flächen. Ein biliniar Patch ensteht, wenn zwei Linien L0 (u) und L1 (u) über das selbe Intervall definiert sind. Wenn jetzt zum Beispiel die Endpunkte von L0 (u) P00 und P01 sind, dann wäre L0 (u) = (1 − u)P00 + uP01 und für L1 (u) würde gelten L1 (u) = (1 − u)P10 + uP11 , wäre der biliniare Patch durch folgende Formel definiert: B(u.v) = (1 − u)(1 − v)P00 + u(1 − v)P01 + v(1 − u)P10 + uvP11 4.4. VON KURVEN ZU FLÄCHEN 88 Biliniare Patches sind planar, wenn ihre Linien L0 (u) und L1 (u) in der selben Ebene liegen. Bezier-Patches Bezier-Patches entstehen, wenn man das kartesische Produkt zweier Bezierkurven nimmt. F (u, v) = n n X X Bi (u)Bj (v)Pij i=0 i=0 Die Kontrollpunkte bilden ein Polyeder an den sich dann die Bezierfläche annähert. Die gesamte Fläche liegt unterhalb ihrer Kontrollpunkte. Die Eckpunkte werden interpoliert und somit liegt die Fläche innerhalb ihres konvexen Polyeders. Hierbei beeinflusst die Manipulation eines Kontrollpunktes wieder die gesamte Abbildung 4.16: Bezierfläche im konvexen Polyeder Bezierfläche. Wir haben bei Bezier-Patches wieder die gleichen Vor- und Nachteile, wie bei Bezierkurven. Vorteile: - Leichte und effiziente Berechnung. Nachteile: - Nur globaler Einfluss - Grad hängt wieder von Kontrollpunkten ab. Komplexere Flächen Man kann Bezier-Patches zusammensetzen, um eine größere und konplexere Kurve zu erhalten. Dabei ist wieder darauf zu achten, dass die Kurve mindestens G1 -stetig ist. Man erhält G0 -Stetigkeit, indem man die Kontrollpunkte eines Randes gleichsetzt mit den Konttrollpunkten des Randes der zweiten Fläche. 4.4. VON KURVEN ZU FLÄCHEN 89 Abbildung 4.17: G0 -stetige Fläche Um jetz G1 -Stetigkeit zu erhalten, müssen die beiden Flächen kollinear verbunden werden. Abbildung 4.18: G1 -stetige Fläche B-Spline Patches Um einen B-Spline Patch zu erhalten bilden wir wieder das kartesische Produkt der Kontrollpunkte und der B-Splinekurven. Q(u, v) = n X m X Bi (u)Bj (v)Pij i=0 i=0 Analog zu B-Splinekurven entstehen bei B-Spline Patches auch Flächensegmente, die eine Gesamtfläche bilden. Die Flächensegmente liegen in der konvexen Hülle der Teilpolyeder. Hierbei haben wir wieder die lokale Kontrolle der einzelnen Flächensegmente. Der Verlauf der Fläche hängt wieder von den beiden Knotenvektoren ab. 4.4. VON KURVEN ZU FLÄCHEN 90 NURBS Patches Ahnliches Prinzip, wie bei den B-Spline Patches. Zusätzlich hat man wieder den Gewichtsparameter wi . Pn Pm S(u, v) = i=0 j=0 P n Pm i=0 Ni,p (u)Nj,q (v)wi,j Pij j=0 Ni,p (u)Nj,q (v)wi,j Man kann bei den NURBS-Flächen mit Hilfe des Gewichtsparameters die Fläche viel genauer manipulieren. 4.4.2 Bilinearly Blended Surfaces Coons Patches Leider gibt es zu diesem Thema auch sehr wenig Informationen. Es wird meistens nur ein allgemeiner Überblick gegeben. So auch hier. Eine andere Möglichkeit Flächen zu bauen, ist der Coons Patch. Die Idee ist eine Fläche mit Hilfe von vier Randkurven zu definieren. Die Fläche wird also durch die vier Randkurven P (0, v),P (1, v) P (u, 0) und P (u, 1) begrenzt, u = [0, 1] und v = [0, 1]. Diese Kurven schneiden sich in den Eckpunkten P (0, 0),P (0, 1), P (1, 0) und P (1, 1). Außerdem brauchen die Coons Patches noch so genannte Bindefunktionen, mit denen man die Stetigkeit benachbarter Kurvensegmente gewährleisten kann. Da die Berechnung für Coons Patches sehr langwierig ist, hier eine erläuternde Skizze: Abbildung 4.19: Berechnung eines Coons Patch Man subtrahiert zum Schluss nochmal die Eckpunkte, da diese sonst doppelt definiert wären. Coons Patches werden selten in der Computergrafik verwendet. 4.5. VON FLÄCHEN ZU OBJEKTEN 4.5 91 Von Flächen zu Objekten Um Objekte zu erstellen, werden Flächen mit Hilfe der Manipulationswerkzeuge so verändert, dass man eine Objekt erhält. Angenommen wir wollen einen Kopf modellieren: Wir erstellen zunächst eine Kugel und bilden dann an den Stellen, wo die Augen sich befinden Dellen. Also wir verschieben die Kontrollpunkte nach innen oder definieren Gewichte dementsprechend. Bei der Nase analog. Die Teilfläche wird nach außen gezogen. Kapitel 5 Grafikkarten und GPU-Programmierung Christoph Sackl 5.1 Einleitung Eine Grafikkarte, brauche ich die wirklich? Im Lexikon ist die Grafikkarte definiert als das Steuergerät für die Bildschirmanzeige in einem Personal Computer [Wik07b]. Das ist heute aber nur mehr die halbe Wahrheit und verrät nur einen Teil von dem, was eine Grafikkarte tatsächlich kann. Grafikkarten werden immer schneller und können so immer realistischere 3D-Spiele am Computer oder Render-Sequenzen fürs Kino erzeugen. Sie können mittlerweile aber auch komplexe Algorithmen auf ganz anderen Gebieten, wie etwa dem Entschlüsseln von Passwörtern, sehr viel schneller bearbeiten als der Hauptprozessor (CPU, engl.: Central Processing Unit). In dieser Arbeit findet man eine kurze geschichtliche Einführung, wie rasant sich die Grafikkarte bis heute entwickelt hat und sieht einen Überblick der alten GrafikPipeline und der nun aktuellen Unified-Shader Architektur, die nVidia mit dem G80 Chip eingeführt hat. Darüber hinaus sollen auf einfache Weise die Grundlagen der Shader- und GPU-Programmierung und womit hier eigentlich programmiert wird, gezeigt werden. 92 5.2. DIE GRAFIKKARTE 5.2 5.2.1 93 Die Grafikkarte Entwicklung der Grafikkarte Die erste Grafikkarte, aus dem Jahre 1977, wurde im Apple II Computer verbaut. Dieser Monochrome-Display-Adapter ist im heutigen Sinne eigentlich keine Grafikkarte, da sie keine einzelnen Pixel ansteuern konnte. Die Darstellung auf dem Bildschirm erfolgte in nur zwei Farben (monochrom) und es wurde eine Textauflösung von 80 Spalten (Zeichen) und 25 Zeilen geboten. Deshalb bezeichnete man diese Karte auch als 80-Zeichen-Karte“ [Kom07]. Die erste Grafikkarte im heute immer ” noch so bezeichneten IBM-PC, wurde von IBM im Jahre 1983 als CGA-Karte (Color-Graphic-Adapter mit 320x200 und vier Farben) verbaut. Die ersten Modelle liefen auf einem sehr einfachen 8-Bit Bus (XT-Bus) und waren im Vergleich zu heutigen Grafikkarten sehr klein (siehe Abb. 5.1). Abbildung 5.1: Eine der ersten Grafikkarten für den XT Bus. (Quelle: Wikipedia) Bis 1989 waren die von IBM eingeführten Grafiktypen (1983 die CGA-Karte, 1984 die EGA-Karte und 1989 die VGA-Karte) bei dem am meisten verbreiteten IBM-PC Standard. Heute wird bei IBM kompatiblen PCs immer noch der VGAModus (640x480 Bildpunkte in 16 Farben) als Notfall-Modus“ unterstützt. Die zur ” Zeit gängigsten Standards sind PAL (768x576), SVGA (800x600), XGA (1024x768) und SXGA (1280x1024). Der Trend zu Widescreen-Bildschirmen spiegelt sich in neueren Standards wie dem WUXGA-Standard mit einer Auflösung von 1920x1200 Bildpunkten oder HD1080 mit 1920x1080 Bildpunkten, bei 16,7 Millionen Farben auf einem 16:10 bzw. 16:9 Monitor, wieder. Auch die verwendeten Steckplätze haben sich bis heute in starkem Umfang weiterentwickelt. Hier ein kurzer Überblick über deren technische Daten: 5.2. DIE GRAFIKKARTE 94 • ISA (Industry Standard Architecture)-Bus: Heute technisch überholt (Taktfrequenz 8,33 MHz; erreichbare Übertragungsrate: 4 MB/s; Datenbreite 16 Bit). • PCI (Peripheral Component Interconnect)-Bus: Nur noch in Servern im Einsatz (Taktfrequenz 33-66 MHz; 2x-Pipelining-Modus Übertragungsrate: 150 MB/s; Datenbreite 32 Bit). • AGP (Accelerated Graphics Port)-Bus: Zunehmend durch PCI-Express vom Markt verdrängt (Taktfrequenz 66-533 (Effektiv) MHz; bis zu 8x-PipeliningModus Übertragungsrate: 2133 MB/s; Datenbreite 32 Bit). Bei aktuellen Grafikkarten wird der moderne PCI-Express-Bus benutzt. Durch die erhöhten Taktfrequenzen und Speicherbandbreiten können immer mehr Daten in gleicher Zeit verarbeitet werden, was mit ein Hauptgrund für die höhere Grafikqualität bei Computerspielen und gerenderten Bildern ist oder auch computeranimierten Szenen in Filmen. Die hohe Speicherbandbreite kann dabei zum Beispiel für größere Texturen (höhere Auflösung) genutzt werden. Vergleicht man zum Beispiel eine Grafik mit VGA-Auflösung und vergrößert sie dann auf XGA-Auflösung wächst der Speicherbedarf der Grafik an. Das bedeutet mit mehr Speicherbandbreite kann man größere Mengen an Grafikdaten in gleicher Zeit verarbeiten, so dass wir heute zum Beispiel nicht mehr im älteren PAL-Format Filme sehen sondern in einer hohen HD-Auflösung. Anhand der Taktfrequenz lässt sich ablesen, wie lange eine Taktperiode dauert. Eine Taktfrequenz von 1 GHz entspricht zum Beispiel einer Taktperiode von 1 ns. Erhöht sich der Takt finden mehr Taktperioden in der gleichen Zeit statt. Da pro Taktperiode eine gewisse Zahl an Grafik-Operationen stattfinden kann, steigert die Takterhöhung die Zahl der ausführbaren Operationen. Im Folgenden soll anhand eines kurzen Überblicks der Aufbau einer modernen Grafikkarte erläutert werden. 5.2.2 Eine moderne Highend-Grafikkarte Die nVidia GeForce 8800 GTX ist eine moderne Highend-Grafikkarte und verwendet den nunmehr aktuellen PCI-Express-Bus zur Datenübertragung zwischen CPU und Grafikkarte. Er läuft mit einer effektiven Taktfrequenz von 1-12 GHz und unterstützt bis zu 16-Pipelines mit einer theoretischen Übertragungsrate von 4 GB/s je Richtung (Näheres in der Spezifikation [Ins07]). Die Datenbreite beträgt 32 5.2. DIE GRAFIKKARTE 95 Bit. Im folgenden die wichtigsten Bestandteile einer Grafikkarte am Beispiel der GeForce 8800 GTX (siehe Abb. 5.2). Abbildung 5.2: Eine nVidia 8800 GTX mit abmontiertem Kühler. (Quelle: Techreport) Den Kern der Grafikkarte bildet der Grafikprozessor (GPU, engl.: Graphics Processing Unit). Die GPU beherbergt auch die Grafik-Pipeline und führt Shader Operationen aus, worauf später im Detail eingegangen wird. Auf dieser Grafikkarte ist ein G80-Chip, welcher mit 575 MHz getaktet ist, verbaut. Er erlaubt eine Füllrate von 13,8 Milliarden Pixel/s und 36,8 Milliarden Texel/s. Ein Pixel ist ein Bildpunkt auf dem Bildschirm. Ein Texel (Texturelement) ist in der Computergrafik die fundamentale Grundeinheit eines Texturraumes. Texturen werden durch Arrays von Texeln repräsentiert, so wie Bilder aus Arrays von Pixeln bestehen. Die theoretisch erreichbare, maximale Füllrate an Texeln pro Sekunde gilt heute als Hauptleistungsindikator einer GPU. Sie gibt an, wieviele texturierte Pixel die Grafikkarte pro Sekunde auf den Bildschirm rendern kann. Den Kern umgibt der Grafikspeicher. In Abbildung 5.2 sehen wir um die GPU 768 MB GDDR3-Speicher mit einer Taktrate von 1800 MHz und einer Datenbreite von 384-Bit. Die maximale Bandbreite dieses Speichers beträgt 86,4 GB/s und liegt damit weit über der Geschwindigkeit früherer Modelle. Ebenfalls beachtlich ist die große Anzahl an Transistoren in GPUs. Eine GeForce 8800 GT (G92 Chip) besitzt 754 Millionen Transistoren. Im Vergleich dazu hat eine aktuelle Core 2 Duo CPU nur 291 Millionen Transistoren. Ein Transistor ist ein Halbleiterbauelemt, welches aus einem Halbleiter (meist Silizium) als Grundmaterial besteht und zum Schalten und Verstärken von elektrischen Strömen und Spannungen dient. Ein Nachteil der hohen Geschwindigkeit bei modernen Grafikkarten ist allerdings der hohe Stromverbrauch, der unter anderem auf die stark gestiegene Transistoranzahl zurückzuführen ist. Das Spitzenmodell von AMD/ATI die Radeon HD 2900XT benötigt maximal 245 Watt und damit doppelt so viel Strom wie ein durchschnittlicher PC. AMD führt zur Zeit das neue Modell HD 3870 ein, das durch ein spezielles Power Management mit einem Verbrauch knapp über 100 Watt auskommen soll und trotzdem die gleiche Leistung wie eine GeForce 5.3. GRAFIK-PROGRAMMIERUNG 96 8800 GTX bietet. Vergleicht man diese moderne Karte mit einer GeForce-Karte der ersten Generation sieht man schnell, wie stark sich die Performance in diesem Bereich entwickelt hat. So waren im Jahr 2000 bei der GeForce 256 noch ein NV10 Chip mit 120 MHz, der über eine Füllrate von nur 480 Millionen Texel/s verfügt hat, verbaut. Eine Pixel Füllrate wird für diesen Chip überhaupt nicht angegeben, da zu dieser Zeit viele Operationen, die heute von der GPU übernommen wurden, noch die CPU ausgeführt hat. Als Speicher wurden 16-64 MB SDRam mit 166-300 MHz eingesetzt, die über eine Bandbreite von 2,7-4,8 GB/s verfügten. Die Anbindung erfolgte damals noch über eine Busbreite von nur 128-Bit. Eine Übersicht über alle nVidia Chips findet man bei Wikipedia [Wik07a]. 5.3 Grafik-Programmierung Bevor man die klassische Grafik-Pipeline und die neue Shader-Architektur genauer betrachtet, sollte man wissen, womit diese eigentlich programmiert werden. Da die Ausführungen der bekannten Architekturen bei den verschiedenen HardwareHerstellern oft unterschiedlich sind, ist es wichtig auf standardisierte Schnittstellen für Programmierer zurückzugreifen. Diese Schnittstellen nennt man APIs (engl.: Application Programming Interface). Mit ihnen kann man einfach Computergrafiken programmieren ohne genauere Kenntnisse über die Hardware zu besitzen. Sie dienen als Schnittstelle zwischen Anwendung und Hardware, um so möglichst plattformund hardwareunabhängig mit standardisierten Befehlen die Grafik-Pipeline bzw. Shader programmieren zu können. Die beiden wichtigsten Beispiele für solche APIs sind OpenGL (vor allem im professionellen Bereich genutzt, engl.: Open Graphics Library) sowie Direct3D (Dieser Teil des DirectX-Entwicklungspakets wird von vielen Windows Spielen und Anwendungen genutzt). Weniger bekannte Grafik-APIs sind GDI (engl.: Beginning Game Programming) und SDL (engl.: Simple Direct Media Layer). Da GDI relativ langsam und umständlich ist [Pyg07], wird es für größere Objekte nicht verwendet. SDL ist wie OpenGL eine freie Grafik-Bibliothek und betriebssystemunabhängig, im Gegensatz zu Direct3D welches mit DirectX nur unter Windows zur Verfügung steht. Die Motivation solche speziellen Grafik-APIs anzubieten liegt darin, dass die klassischen Programmiersprachen wie beispielsweise C/C++ oder Python in ihrem Standardumfang keine Grafikfunktionen anbieten. Damit Programmierer für die Grafik-APIs keine neue Programmiersprache lernen müssen, haben die oben ge- 5.4. KOORDINATENSYSTEME 97 nannten APIs die Gemeinsamkeit, dass sie auf C basieren und auch mit C++ genutzt werden können. 3D-Anwendungen können daher mit C/C++ programmiert werden, deren Befehlsumfang dann durch die gewählte Grafik-API lediglich erweitert wird um so mit standardisierten API-Befehlen die Grafik-Pipeline oder Shader zu parametisieren. Da OpenGL und Direct3D auf C-Befehlen basieren, können diese nicht mit der sonst oft genutzten Programmiersprache Java zur Spieleprogrammierung oder für andere 3D-Anwendungen verwendet werden. Es gibt einen sogenannten Java-Wrapper mit der Bezeichnung Jogl um OpenGL nutzen zu können. Da nun gezeigt wurde, womit man etwas für die Grafikkarte programmiert, soll als nächstes veranschaulicht werden, was man eigentlich für die Grafikkarte programmiert. 5.4 Koordinatensysteme Bevor es am Bildschirm zur Bildausgabe kommt, müssen am Computer 3D-Objekte in einem typischerweise 3-dimensionalen Raum erzeugt werden. Aus diesen Geometriedaten wird die Grafik-Pipeline später das 2-dimensionale Bild auf dem Monitor erzeugen. Die Vertex-Einheiten der GPU transformieren die Vertizes der Objekte jeweils in ein oder mehrere verschiedene Koordinatensysteme [FK03]. Diese Koordinatensystem werden durch unterschiedliche Räume beschrieben, welche im Folgenden erläutert werden sollen. 5.4.1 Object Space Hier liegen alle Objekte in ihrem eigenen x-y-z-Koordinatensystem mit einem festgelegten Ursprung. Zur Bearbeitung eines solchen Raums lässt sich beispielsweise 3D Studio Max nutzen, in dem das Zentrum des Objekts für gewöhnlich den Koordinaten (0,0,0) entspricht. Bei einem Auto könnte dieser Punkt etwa dem linken Vorderreifen entsprechen. Über diesen Kontrollpunkt kann der 3D-Renderer das Modell bewegen und rotieren, weil alle Koordinaten im Object Space relativ zu diesem Ursprung liegen. 5.4.2 World Space und Eye Space Im World Sapce werden die Objekte über ein homogenes x-y-z-wKoordinatensystem in eine virtuelle 3D-Welt transformiert. Das w entspricht hier dem Wert, durch den man x, y, und z teilen würde, um die 3D-Position 5.4. KOORDINATENSYSTEME 98 im nichthomogenen Koordinatensystem zu erhalten. Auf diese Weise kann man 3D-Transformationen später effektiv als 4x4 Matrizen ausdrücken. Diese haben in den gängigsten APIs Direct3D (World- und View-Matrix) und OpenGL (Modelview-Matrix) unterschiedliche Bezeichnungen. Da die 3D-Welt nie vollständig sichtbar ist, muss ein Objekt vom World Space in den Eye Space transformiert werden oder wird eben direkt vom Object Space in den Eye Space (siehe Abb. 5.3) transformiert. Dies resultiert aus der Tatsache, dass wir immer nur von einer bestimmten Position aus den 3D-Raum betrachten. Um vom World Space in den Eye Space zu transformieren, nutzt man in Direct3D wieder eine Matrix mit der Bezeichnung View Matrix. In diesem Raum wird die tatsächliche Position der Kamera (bzw. des Betrachterauges) über die Grafik-API gesteuert und man schaut nun quasi die negative z-Achse entlang in den Raum auf die Objekte. Man muss sich das ganze wie eine Blickpyramide vorstellen, deren oberes Ende abgeschnitten ist (der Anfang des sichtbaren Bereichs) und deren Boden das Ende des sichtbaren Bereichs darstellt (siehe Abb. 5.3). Dieser Vorgang wird auch als Clipping bezeichnet. Abbildung 5.3: Die Blickpyramide in den Eye Space. (Quelle: Extreme Tech) 5.4.3 Clip Space Als weiteres wichtiges Koordinatensystem gibt es den Clip Space, in dem festgestellt wird, welche Stellen eines Objektes eigentlich sichtbar sind. Ein wichtiger Unterschied zwischen OpenGL und Direct3D im Clip Space ist die unterschiedliche Behandlung der Koordinaten. Die x-y-Koordinaten werden zwar gleich behandelt, die z-Koordinate aber nicht. In OpenGL muss alles an einer Achse ausgerichtet sein, so dass die x-y-z-Koordinaten immer kleiner oder gleich des w Wertes sind. In Direct3D dagegen gilt dies nur für die x-y-Koordinaten, während die z-Koordinate kleiner als der w Wert bis hin zur Null entspricht. Beide Vorgehensweisen setzen voraus, dass die Clip Space Positionen in homogenen Koordinaten vorliegen, da sie von w abhängig sind. In diesem Koordinatensystem wird wieder eine 4x4 Matrix 5.5. DIE KLASSISCHE GRAFIK-PIPELINE 99 mit der Bezeichnung Projektions-Matrix genutzt. 5.4.4 Window Space Während die Clip Space Koordinaten in homogenen Koordinaten vorliegen, müssen diese im Window Space in normalisierte x-y-Koordinaten transformiert werden, da unser Bildschirm nur eine 2D-Oberfläche besitzt. Erreichen kann man das durch das Dividieren von x, y, und z durch w, was man als Perspektivische Zerlegung“ ” (engl.: Perspective Division) bezeichnet [FK03], mit der wir dann die normalisierten Gerätekoordinaten erhalten. Die Posititionen in OpenGL liegen hier zwischen (-1,1,-1) und (1,1,1), während sie in Direct3D zwischen (-1,-1,0) und (1,1,1) liegen. Nach der Erläuterung in welchen Koordinatensystemen 3D-Objekte dargestellt werden, folgt nun eine Betrachtung wie diese in der klassischen Grafik-Pipeline verarbeitet werden. 5.5 Die klassische Grafik-Pipeline Ähnlich wie die CPU eine Pipeline mit mehreren Stages besitzt (Vergleich DLXPipeline, bekannt aus der Technischen Informatik), von der jede eine einfache Aufgabe schnell erfüllt, besitzt auch die GPU auf der Grafikkarte eine Pipeline. Diese sogenannte Pipelined“-Architekur dient der Aufteilung größerer Aufgaben ” in kleinere Schritte, um somit eine quasi-parallele Ausführung mehrerer Aufgaben gleichzeitig zu ermöglichen. Bei der GPU bestehen die Aufgaben aus dem Übernehmen der Daten eines Programms in Form von geometrischen Primitiven (Punkten, Linien und Polygonen), welche die 3D-Geometrie beschreiben. Diese Formen werden dann auf einer per-Vertex Basis bearbeitet und vom virtuellen 3DRaum auf den 2D-Bildschirm transformiert. Der Weg geht dabei vom ersten Polygon (in der Computergrafik werden in der Regel Dreiecke verwendet) einer Szene bis zum letzten Pixel, den man letztendlich auf dem Bildschirm sieht. Die Grafik-Pipeline besteht dabei aus mehreren Stufen ( Stages“), die 3D-Objekte in 2D-Bildschirm Objekte transformieren um so am ” Ende ein gerastertes Bild auf dem Bildschirm auszugeben [Shi05] (siehe Abb. 5.4. Die Geometrie-Daten der 3D-Objekte, die in die Grafik-Pipeline hinein gehen lassen sich grob in folgende geometrische Primitive unterteilen [Shi05]: • Punkte: Einzelne Vertizes um Punkte oder Partikelsysteme zu beschreiben. 5.5. DIE KLASSISCHE GRAFIK-PIPELINE 100 Abbildung 5.4: Grobes Modell der Grafik-Pipeline. (Quelle: Fundamentals of Computer Graphics Second Edition, Page 380) • Linien: Paare von Vertizes um Linien oder Silhouetten zu erzeugen oder Kanten hervorzuheben. • Polygone: Üblicherweise Dreiecke um über ein Netz aus vielen Dreiecken geometrische Strukturen zu beschreiben. Zu beachten ist hier, dass dies die einzigen Geometrie-Daten sind, die in der Pipeline verarbeitet werden. Auch wenn man beispielsweise Splines oder Nurbs 4.5 verwendet, werden die Oberflächen von der Hardware als Polygone behandelt. Die Kontrollpunkte der Splines oder Nurbs sind in der Pipeline betrachtet primitive Punkte, die Verbindung zwischen zwei Kontrollpunkten eine Linie und die resultierende Fläche aus drei oder mehr Kontrollpunkten stellen dann ein Polygon dar. Daraus folgt auch, dass man nur einen endlichen Grad an Rundung erreichen kann. Die Anwendung selbst (zum Beispiel ein 3D-Spiel oder 3D-Renderer) kann man als den Anfang der Grafik-Pipeline ansehen. Sie ist zwar rein technisch gesehen kein elektronischer Bestandteil der Pipeline, von hier gehen jedoch alle Befehle an die Pipeline aus. An dieser Stelle beginnt das Vertex Processing (Ein Vertex ist der Eckpunkt eines Polygons) wobei die Geometrie-Daten einigen Transformationen unterzogen werden, bevor man ein 2D-Bild auf dem Bildschirm rastern kann. 5.5.1 Geometrieoperationen Der wahrscheinlich wichtigste Teil der Pipeline sind die Geometrieoperationen. Hier finden verschiedene Transformationen der 3D-Objekte, sowie Operationen, die den Lichteinfall auf den einzelnen Vertizes bestimmen statt 2.7.3. Die Eingangsdaten (3D-Objekte) werden zuerst aus dem Object Space in eine einheitliche Form überführt, also in den World Space transformiert. Einige APIs wie zum Beispiel OpenGL, überspringen diesen Schritt und transformieren über die Modelview-Matrix direkt in den Eye Space. Mit Direct3D dagegen wird zunächst über die World-Matrix vom Object Space in den World Space transformiert und erst dann legt die View-Matrix den Standort und Blickrichtung für den Eye Space fest. Nachdem man nun den Blickwinkel in die virtuelle Welt berechnet hat, besteht die 5.5. DIE KLASSISCHE GRAFIK-PIPELINE 101 nächste Aufgabe darin, überflüssige Arbeit zu minimieren. Eine Mögichkeit stellt das Occlusion Culling“ dar, bei dem es darum geht die nicht sichtbaren Objekte ” zu entfernen. Ein Objekt hinter einer Wand muss man zum Beispiel nicht rendern. Weitere Methoden sind die Verwendung von Bounding Boxes und dem Objekt-LoD (engl.: Level of Detail). Dieser Transformation findet über die Projektions-Matrix im Clip Space statt. Um die homogenisierten Gerätekoordinaten zu erhalten, sind einige Schritte notwendig. Aus dem homogenen Koordinatensystem müssen die Koordinaten jedes Vertex normalisiert werden, damit ins endgültige x-y-Koordinatensystem im Windows Space transformiert werden kann. Es gibt dabei im wesentlichen vier Operationen, die alle mit Hilfe von Transformations-Matrizen arbeiten. • Translation: 3D-Objekte können auf einer der drei Achsen verschoben werden. Mathematisch würde es sich hierbei eigentlich um Addition beziehungsweise Subtraktion handeln, aus Effizienzgründen nutzt man diese Transformationen jedoch so, dass sie über Matrizenmultiplikation funktionieren. • Rotation: 3D-Objekte können um eine der drei Achsen gedreht werden. Einfachste mathematische Operation, wenn das Objekt bereits im Ursprung des Koordinatensystems liegt, ist hier die Multiplikation jeder Koordinate mit dem Sinus oder Cosinus von Theta. Theta ist die Gradzahl, um die das Objekt gedreht werden soll. Sollte eine Drehung um mehrere Achsen erforderlich sein, ist auch die Reihenfolge der Rotationen zu beachten, da es dabei zu unterschiedlichen visuellen Ergebnissen kommen kann. • Skalierung: 3D-Objekte müssen auch skaliert werden um deren Größe in der Nähe und Entfernung zu unterscheiden. Mathematisch gesehen wird die Veränderunggröße in den Diagonalelementen der Skalierungs-Matrix angegeben. Verwendet man zum Beispiel den Wert 0,5 in der Diagonalen einer 2x2 Matrix wird das Objekt in seiner Größe halbiert. Nutzt man unterschiedliche Werte spricht man von der nicht-uniformen Skalierung. • Skewing: Skewing (Shearing) ist wichtig, da es ja auch elastische Objekte in einer 3D-Welt geben kann, wie etwa einen Ball der beim aufprallen auf eine Wand zusammengequetscht wird. Mathematisch realisiert man dies zum Beispiel durch das addieren des x-Achsenwerts zum y-Achsenwert während man den x-Achsenwert unverändert belässt. 5.5. DIE KLASSISCHE GRAFIK-PIPELINE 102 Abbildung 5.5 zeigt ein Grundmodell wie diese Transformations-Matrizen aussehen. Abbildung 5.5: Typische Transformations-Matrizen für ein 3D-Objekt. (Quelle: Extreme Tech) 5.5.2 Pixeloperationen Der weitere Verlauf der Grafik-Pipeline ist nicht eindeutig, da manche Quellen das sogenannte Polygon-Setup zur Rasterisierung zählen und andere es als eigenständige Stufe in der Pipeline ansehen [Inc07]. Hier wird das Polygon-Setup als Vorstufe zur Rasterisierung betrachtet. Es wird zunächst die Neigung der einzelnen Polygone anhand der Vertex-Information am Ende der Kanten berechnet. Dies ist nötig, um die x-y-Werte für jedes Polygon zu berechnen. Durch diese Berechnung kann man das linke und rechte Ende jedes Polygons erfassen. Diesen Bereich der Scan-Line“ (es ” wird Zeilenweise gearbeitet) nennt man auch Span [Wat93]. Das daraus resultierende Scan-Line Diagramm, welches die Spans enthält, wird für die Pixeloperationen benötigt. In diesem Bereich der Grafik-Pipeline liegt der Übergang vom Vertex-Processing (Verarbeitung) zum Pixel-Processing. Auch hier wird wieder unnötige Arbeit eingespart, indem durch den sogenannten Depth-Test festgestellt wird, ob ein Pixel überhaupt sichtbar ist. Hier findet beispielsweise auch das Texture Mapping statt, bei dem jeder Pixel mit einem Texel in Verbindung gebracht wird. Nachdem die Rasterisierung abgeschlossen ist, werden die endgültigen Pixel in den Framebuffer geschrieben. Einen völlig neuen Ansatz des Grafikkartenaufbaus, der auf das klassische GrafikPipeline Modell verzichtet, finden wir erstmals in der G80-Grafik-Architektur von nVidia. 5.6. DIE UNIFIED-SHADER ARCHITEKTUR 5.6 103 Die Unified-Shader Architektur Die große Neuerung, die erstmals mit der G80-Architektur eingeführt wurde, ist das sogenannte Unified“ Design. Der Entwickler nVidia spricht vom Unified, ” ” Massively Parallel Shader Design“ [nVi06a]. Die 8800 GTX war die erste Grafikkarte, die auf dieser Architektur aufgebaut hat. Einen Überblick gibt das Diagramm in Abbildung 5.6. Die neueren Modelle der für den Desktop-Einsatz gedachten Grafikkarten von nVidia und auch AMD (ATI) bauen nur noch auf diese Architektur auf. Abbildung 5.6: GeForce 8800 GTX Block Diagramm. (Quelle: nVidia [nVi06b]) Das besondere an diesem Unified-Design ist der Ersatz der bekannten und relativ restriktiven Pipeline-Architektur durch eine Vielzahl von Stream-Prozessoren (SPs). Aus technischer Sicht ist ein SP ein Koprozessor, der Datenströme verarbeiten kann. Die Spezialisierung auf hohe Parallelisierung dieser Koprozessoren spiegelt sich auf einer Grafikkarte in der großen Anzahl wider (8800 GTX 128 SPs bis HD 3870 mit 320 SPs). Ein einzelner SP kann als skalare Recheneinheit angesehen werden, die einzelne skalare Rechenoperationen an einem Datenstrom (welcher vorher die Pipeline passieren musste) durchführt. Schaltet man mehrere dieser skalaren Recheneinheiten zusammen, so sind auch die für Grafikkarten interessanten Vektorverarbeitungen möglich. Der Begriff der Unified-Shader“ kommt nun da” her, dass die Grafikkarte nicht mehr einzelne Vertex- und Pixel-Pipelines besitzt, sondern jeder SP Aufgaben für Vertex-, Fragment- und auch die neu eingeführten Geometry-Operationen durchführen kann, wodurch sich die GPU dynamisch an die aktuellen Anforderungen der Anwendung anpassen kann. Was diese Begriffe im einzelnen bedeuten, folgt nach einem weiteren Überblick über die neue Architektur. Durch die Veränderung der Architektur ändert sich auch der sequentielle Datenfluss auf der GPU. So werden nicht mehr wie beispielsweise bei der GeForce 7 über 200 sequentielle Pipeline-Stages allein für den Pixel-Shader benötigt, sondern stattdessen die Anzahl der einzelnen Schritte stark reduziert um die effiziente Nutzung von 5.6. DIE UNIFIED-SHADER ARCHITEKTUR 104 Loops“ zu ermöglichen. In der Programmierung spricht man von Loops wenn eine ” Befehlssequenz die einmal spezifiziert wurde, mehrmals hintereinander ausgeführt wird. Durch die Nutzung der Loops kann so ein durch eine Befehlssequenz verarbeitetes Datum viel schneller wieder verwendet werden, als wenn es erst die gesamte Grafik-Pipeline durchlaufen müsste. Wie man sich das bildlich vorstellen kann, ist in Abbildung 5.7 zu sehen. Abbildung 5.7: Vergleich einer gewöhnlichen Pipeline mit Loops in einer UnifiedArchitektur. (Quelle: nVidia [nVi06b]) Die Vereinheitlichung“ der Shader, also dass jede Shader-Einheit für alle ” Shader Operationen genutzt werden kann, bringt noch weitere Vorteile mit sich. Die aktuell anfallenden Anfragen einer Anwendung können in ihrer Anforderung an Vertex- und Fragment-Shader variieren. In der Regel ist die Zahl der Pixel zwar größer als die der Vertizes - was der Grund ist, warum auf den alten Grafikkarten mehr Pixel-Shader als Vertex-Shader verbaut waren - es gibt aber genauso Szenen, bei denen dies nicht der Fall ist. So kann auch im untypischen Fall das die Zahl der Vertizes überwiegt, die Rechenleistung maximal dafür genutzt werden und so die Gesamt-Effizienz erhöht werden. Will man zum Beispiel ein großes MeshModell, das mehr Vertizes besitzt, als Pixel auf dem Monitor angezeigt werden (hohe Vertex-Shader Last) und ein hochauflösendes Bild (hohe Fragment-Shader Last), dann wird der Unterschied in den Anforderungen deutlich wenn man bedenkt, dass nun nicht mehr im einen Fall beispielsweise nur 4 Vertex- und im anderen Fall 8 Pixel-Shader zur Verfügung stehen, sondern 12 Unified-Shader für beide Operationen. Die Shader-Einheiten können nun auch mit verkürzten Leerlauf-Zeiten arbeiten, da die GPU theoretisch für jede Aufgabe voll genutzt werden kann und nicht immer nur für jeweils eine Teilaufgabe wie in Abbildung 5.8 gezeigt wird. Auch das Branching wurde bei der neuen Architektur verbessert. Ein Branch ist 5.6. DIE UNIFIED-SHADER ARCHITEKTUR 105 Abbildung 5.8: 3D-Transformationen (Mathematische Operationen) und TexturOperationen können gleichzeitig ausgeführt werden. (Quelle: nVidia [nVi06b]) ein Punkt in einem Computer Programm, wo der Programmfluß abhängig von einer Bedingung geändert wird (zum Beispiel if-then-else). Wurde bei alten Grafikkarten mit DirectX 9 Shadern eine Grafik mit 10000 Pixeln geladen und dann aufgrund eines if-then-else Statement festgelegt, an welchen Stellen eine bestimmte Operation stattfinden sollte und an welchen nicht, so wurden die gesamten 10000 Pixel auf einmal abgearbeitet. Dabei wird anhand der gesamten Pixel zweimal geprüft ob die Bedingung zutrifft. Einmal für die Frage nach dem Zutreffen und einmal für die Frage nach dem nicht Zutreffen. Es handelt sich also eigentlich um doppelte Arbeit. Die neue Architektur nutzt dagegen eine Granularität von 16-32 Pixeln (bei AMD X1950 XTX 48 Pixeln was nVidia als zu ungenau bezeichnet). So kann die Abarbeitung einer Grafik mit 10000 Pixeln auf die SPs verteilt werden, was zu einem deutlichen Performance-Schub führt. Mit der Einführung dieser Architektur wurde von nVidia vor allem auch darauf Rücksicht genommen, dass moderne 3D-Anwendungen performante Shader unter verschiedensten Voraussetzungen benötigen, daher nun eine etwas genauere Betrachtung wie sich das Shader Model bis heute entwickelt hat. 5.6.1 Das Shader Model Ein Shader ist ein Programm, das von den Grafikquellen hauptsächlich für das Rendering benutzt wird, um die endgültige Oberfläche eines Objektes oder Bildes zu erzeugen. Programmierer können mit den Shadern also die Grafikausgabe programmieren, die man später auf seinem Bildschirm sieht. Die veraltete Form der Grafik-Pipeline hat man hier als fixed-function-pipeline“ bezeichnet, da alle ” Bauteile auf eine bestimmte Funktion ausgelegt und somit nicht individuell programmierbar waren. Eine moderne Grafik-Pipeline bezeichnet man dagegen als programmable-pipeline“, die durch die Programmierbarkeit mehr Flexibilität mit ” sich bringt. Da nichts ohne Spezifikationen plattformübergreifend funktionieren kann, gibt es das Shader Model (Aktuell in der Version 4.0). Das Shader Model ist 5.6. DIE UNIFIED-SHADER ARCHITEKTUR 106 eine Zusammenfassung von Instruktionen unter Verwendung einer ISA (Instruction Set Architecture). Es werden dabei Befehle für alle Shader-Typen, also Vertex- und Fragment-Shader und seit der Version 4.0 auch Geometry-Shader zusammengefasst. Aufgrund der neuen Architektur seit den G80-GPUs redet man hier auch von der Unified ISA. Dieser Befehlssatz erleichtert Programmierern ihre Arbeit ganz erheblich. Das Shader Model existiert bereits seit einigen Jahren (Vertex- und FragmentShader wurden 2001 eingeführt) und hat seit seiner Einführung an Komplexität zugenommen. Zu Beginn erlaubte das Shader Model nur einfache arithmetische und boolesche Operationen. Die Verwendung von Loops war zwar auch in älteren Versionen möglich, aber sehr aufwändig und nicht effizient. Es waren meistens nur eine begrenzte Anzahl an Iterationen möglich und für je eine bestimmte Anzahl Iterationen musste ein separater Shader programmiert werden. Auch die Verwendung von Branches unterlag zu dieser Zeit noch größeren Problemen wie zum Beispiel Hazards (Hazards werden in diesem Foliensatz erklärt [uotad99]). Der Hauptunterschied der aktuellen Version 4.0 gegenüber dem Vorgänger 3.0 ist die Vereinheitlichung ( Unification“ - deswegen Unified-Architektur) der Shader, so ” dass es keine Unterschiede mehr zwischen Pixel- und Vertex-Shadern gibt. Neu eingeführt wurden die Geometry-Shader, die es erlauben Vertizes auf der GPU zu erzeugen. Diese Berechnungen musste bisher die CPU übernehmen, was zu einer höheren Belastung des Gesamtsystems geführt hat und zudem ist die CPU nicht für Grafik-Operationen optimiert. Darüber hinaus ist es nun möglich Ressourcen zu virtualisieren, was man sich in etwa wie den virtuellen Speicher auf der GPU vorstellen kann. Insgesamt soll das Shader Model 4.0 also mehr Freiheiten beim Programmieren schaffen und noch flexiblere Möglichkeiten für Programmierer bieten, als die programmable-pipeline“ dies bisher tut. ” 5.6.2 Shader Programmierung Zu Beginn wurden Shader nur über die Assembler-Sprache (Maschinencode) der GPU programmiert. Das ermöglichte zwar die volle Kontrolle über die GPU, war aber sehr schwerfällig und kompliziert in der Verwendung. Deswegen wurde von nVidia Cg (C for Graphics) entwickelt. Eine Hochsprache, die es einfacher macht ein Programm zu programmieren und später zu lesen. Cg Code ist auch portabel auf unterschiedliche Plattformen, während Assembler für gewöhnlich von der Hardware, für die es geschrieben wurde, abhängig ist. Darüber hinaus übernimmt der Cg Compiler einige Optimierungen selbst und führt einige Operationen auf unterster Ebene 5.6. DIE UNIFIED-SHADER ARCHITEKTUR 107 von selbst durch, die mit Assembler noch kompliziert von Hand gemacht werden mussten. Cg wurde in enger Zusammenarbeit mit Microsoft entwickelt und wurde unter anderem bei den aktuellen Spielen Far Cry und Quake Wars genutzt. Die zwei bedeutendsten APIs bieten zudem eigene Hochsprachen, um auf Instruktionen die im Shader Model 4.0 spezifiziert sind, zuzugreifen. Von Microsoft stammt die High Level Shader Language“ (HLSL) zur Verwendung mit der Direct3D API die ” im ersten echten DirectX 10 Spiel Crysis Anwendung findet. OpenGL spezifiziert eine eigene OpenGL Shading Language“ [Fou06a]. DirectX (Bestandteil unter ” anderem Direct3D) führt das Shader Model 4.0 in der aktuellen Version 10 ein, die nur unter Windows Vista zur Verfügung steht. OpenGL dagegen ist beispielsweise auch auf UNIX- und Apple-Plattformen nutzbar. Ein Shader besteht aus einem Array an Strings mit dem Quellcode für die jeweiligen Operationen, die angewendet werden sollen (zum Beispiel Operationen auf Vertex Basis mit dem Vertex-Shader). Um diesen Code zu nutzen, wird etwa nach der OpenGL Shading Language Spezifikation der Quellcode zunächst in ein Shader-Objekt“ geladen und dann kompiliert. Es können dann ein oder mehrere ” Vertex-Shader-Objekte“ mit einem Programm-Objekt verknüpft werden, welches ” dann einen ausführbaren Code aus allen mit dem Programm verknüpften ShaderObjekten generiert. Die Vertex- und Fragment-Shader sind dabei aus der alten Grafik-Pipeline Architektur vom Grundprinzip her übernommen worden. Neu eingeführt wurden die Geometry-Shader. Was diese Shader machen wird im folgenden erklärt. 5.6.3 Vertex- und Fragment-Shader Was als Datenstrom (Eingabe) in den Vertex-Shader kommt, sind die 3DObjektdaten mit der Position jedes Vertex mit Farben und Texturkoordinate. Der Vertex-Shader ist dabei zuständig für Transformationen mit den bereits beschriebenen 4x4 Matrizen. In OpenGL sind Vertizes immer mit zwei, drei oder vier Dimensionen deklariert. Die x- und y-Achse bilden die erste und zweite und die z-Achse die dritte Dimension. Eine vierte Koordinaten-Dimension wird dazu genutzt, um die Entfernung eines Objekts zur Kamera zu steuern. Zusätzlich werden Farbe (Color) und eventuell auch eine Sekundäre Farbe (SecondaryColor) definiert. Die homogenisierten Werte der Texturkoordinaten werden über TexCoord oder bei mehreren Texturen über MultiTexCoord spezifiziert. Für die Tiefenwerte (etwa für Gegenstände im Nebel) kann man dann noch die FogCoord definieren. Es gibt in OpenGL noch eine Reihe weiterer Attribute für Vertizes, die hier genutzt werden 5.6. DIE UNIFIED-SHADER ARCHITEKTUR 108 können. Die Daten für jeden einzelnen Vertex können dann in einem Vertex-Array abgelegt werden, der im Adressraum des Computers liegt. Verschiedene Blöcke aus diesem Array können dann über einen einzigen OpenGL Befehl als primitive, geometrische Figur ausgegeben werden womit man wieder über die Position, Farbe und Texturkoordinaten eines Vertex (Ausgabe) zur weiteren Verarbeitung verfügt. Ein Vertex-Shader steuert Informationen über Lichtquellen, Materialien und Matrizen. Die Operationen, die im Vertex-Shader stattfinden, sind zum Beispiel die Beleuchtung der Eckpunkte oder die Animation von verschiedenen Oberflächen. Im Ablauf des Bildaufbaus befinden wir uns nun beim Rastern, wo die Koordinaten aus der 3D-Welt auf den 2D-Bildschirm interpoliert werden. Wichtig ist auch, das ein einzelnes Objekt sowohl Vertex- und Fragment-Shader enthalten kann. Der Fragment-Shader (auch als Pixel-Shader bezeichnet) erhält als Eingabe pro Pixel die interpolierte Farbe und Texturkoordinaten. Fragment-Shader werden vor allem dazu genutzt, einzelne Fragmente zu manipulieren und mit bestimmten Effekten zu versehen. Das wäre etwa das Bump Mapping (wie zum Beispiel in Abbildung 5.9), Schatten (Shadow Maps) oder Nebeleffekte (Alpha Compositing). Abbildung 5.9: Eine durch Bump Mapping erzeugte Oberfläche, um eine Kugel als Orange darzustellen. (Quelle: Wikipedia) Das Texturieren ist der wichtigste Teil dieses Shaders. Für die Textur wird ein Bild an die Stelle der Texturkoordinaten gerendert, wobei jedes Fragment mehrere solcher Texturkoordinaten enthalten kann. Diese werden genutzt um ein oder mehrere Texturbilder einzusetzten um die endgültige Farbe zu modifizieren um so als Ausgabe dann einen Pixel mit dieser Farbe zu erhalten. Der Fragment-Shader arbeitet im Gegensatz zum Vertex-Shader auf einer per Pixel 5.6. DIE UNIFIED-SHADER ARCHITEKTUR 109 Basis und kann deshalb sehr viel aufwändiger sein. Bei einer Full HD Auflösung (1920x1080 Pixel) kommt man bereits auf 2 Millionen Pixel. OpenGL greift beim Rastern auf Fragment-Shader für verschiedenste Effekte zurück (Antialiasing, Points, Line Segments, Polygons, Pixel Rectangles, Bitmaps, Texturing, Color Sum, Fog [Fou06b]). Zusammenfassend kann man also sagen, dass die statischen Funktionen der GrafikPipeline mit Hilfe von Shader-Programmen an die eigenen Bedürfnisse angepasst werden können. Eine Übersicht über den Zusammenhang zwischen dem klassischen Vertex- und Fragment-Shader gibt Abbildung 5.10. Abbildung 5.10: Zusammenhang von Vertex- und Fragment-Shader. (Quelle: Stevens Institute of Technology) 5.6.4 Geometry-Shader Neu eingeführt im Shader Model 4.0 wurden die Geometry-Shader. GeometryShader sind auch ein neues Feature von DirectX 10 und steht daher unter Windows erst seit Vista zur Verfügung. Somit ist dies auch eine der besonderen Neuerungen der G80-Architektur. Die Geometry-Shader werden nach dem Transformieren der Vertizes durch den Vertex-Shader ausgeführt (siehe Abb. 5.11), aber vor dem Pixel-Processing. Abbildung 5.11: Die Reihenfolge in der die Shader ausgeführt werden. (Quelle: nVidia) 5.7. GENERAL PURPOSE COMPUTATION ON GPUS 110 Ein Geometry-Shader hat einen festen, primitiven Ausgabetyp (Punkt-, Linienoder Dreiecksfolge) und verzichtet auf Vertizes, um neue Objekte zu definieren. Ein Geometry-Shader kann dabei mehrere nicht verbundene Objekte ausgeben, die dann wie gewöhnliche von der Anwendung definierte Objekte weiter behandelt werden. Zum Beispiel wird mit diesem neuen Objekt auch ein Clipping-Test gemacht. Was durch die neuen Geometry-Shader ermöglicht wird, sind etwa sehr realistische menschliche Charaktere mit ausgeprägten Gesichtszügen, natürlichen Schatten und physikalisch korrekten Bewegungen. So kann man über diese Shader ganze Objekte einfacher kontrollieren oder auch zerstören (etwa bei einer Explosion). Ein hoher Performance-Gewinn ist vor allem deshalb gegeben, weil aufwändige physikalische Berechnungen, wie beispielsweise die Bewegung einer Wasseroberfläche nicht mehr von der CPU berechnet werden müssen, sondern von der GPU berechnet werden können. Mit Hilfe dieses Shader-Typs lassen sich auch nicht feste Objekte wie Rauch oder der Feuerball einer Explosion sehr viel einfacher und detaillreicher darstellen. 5.7 General Purpose Computation on GPUs Wie bereits in der Einleitung angekündigt, kann eine moderne GPU nicht mehr nur zu Grafikdarstellung auf dem Bildschirm genutzt werden. Im Allgemeinen spricht man hier von General Purpose Computation on Graphics Processing Units“ (GPG” PU). Durch die gestiegene Flexibilität bei der Programmierbarkeit von GPUs und der höheren Präzision in der Arithmetik, sind nun auch nicht grafische komplexe Algorithmen auf der GPU denkbar [Fou07]. Heute hat man mehr Möglichkeiten aufgrund der erweiterterten Funktionalität der GPUs. Die auf modernen Grafikkarten verbauten SPs sind sehr effizient bei Berechnungen eines konstanten Eingabeda” tenstroms“ (input stream), während sie gleichzeitg die Rückgabewerte in einem Ausgabedatenstrom“ (output stream) liefern, welcher wieder von anderen SPs ” genutzt werden kann. Besonders bei komplexen Aufgaben, die aufwändige Berechnungen erfordern, ist diese Art der Abarbeitung des Datenstroms von Vorteil. Die neuesten Modelle bieten sogar 320 SPs (AMD HD 3870 Grafikkarte), die eine spezialisierte und sehr schnelle instruction decode“ und execution logic“ eingebaut ” ” haben. Mathematisch gesehen handelt es sich bei disen SPs um sogenannte skalare Prozessoren, die ein Datum auf einmal enthalten und mit Floating Point Einheiten arbeiten. Ein Speicher direkt auf den Chips wird gewöhnlich genutzt, um die Ausgabe zu speichern und kann so extrem schnell von anderen SPs genutzt werden. 5.7. GENERAL PURPOSE COMPUTATION ON GPUS 111 Die hohe Anzahl an vorhanden SPs und die daraus resultierende hohe Parallelität bringt große Vorteile bei der Verarbeitung von Vektoren wie sie bei Grafik-Streams vorkommen, aber eben auch bei anderen Anwendungen. 5.7.1 Nutzung des skalaren Prozessor Designs Frühere GPUs haben keine skalaren Prozessoren benutzt, sondern vektorbasierte Prozessoren, da bei grafischen Operationen sehr viele Matrizen genutzt werden. Jedoch treten auch sehr viele skalare Operationen auf, zum Beispiel wenn man zum Aufhellen eines Bildes einen Wert zum Alpha-Wert hinzu addiert. Warum es bei einem Umstieg auf skalare Prozessoren bei grafischen Anwendungen nicht zu einem Verlust an Leistung kommt liegt daran, dass man viel mehr davon auf einen Chip bekommt, da sie viel kleiner sind. Vektorbasierte Prozessoren sind sogenannte 4-Komponenten Prozessoren und benötigen mehr Platz. Dieses Umdenken im Architektur-Design hat nun maßgeblich dazu geführt, dass eine GPU auch insbesondere für andere mathematische Operationen effizient genutzt werden kann, da nun auf Basis von Floating Point Werten gearbeitet wird. Einen Vergleich des möglichen Leistungsunterschieds bei solchen Berechnungen zeigt Abbildung 5.12 Abbildung 5.12: Vergleich der theoretischen Rechenperformance von GPU und CPU. (Quelle: CUDA Documentation) Ein Problem besteht jedoch darin, dass wissenschaftliche Anwendungen oft 64-Bit Floating Point Werte benötigen (Double Precision Float) die auf CPUs in der Regel auch verfügbar sind. Bisherige GPUs können aber nur 32-Bit Float Werte darstellen. Es gibt allerdings Anstrengungen Double Precision Float auf GPUs zu emulieren [DG05] und AMD ist auch gerade dabei einen SP der über diese Fähigkeit verfügt, unter dem Namen FireStream zu entwickeln. Die dabei verwendeten Instruktionen nennt man auch SIMD (single instruction/multiple data). Der Vorteil dieser Programmierweise zeigt sich dann, wenn 5.7. GENERAL PURPOSE COMPUTATION ON GPUS 112 man beispielsweise einen festen Wert mit einer mathematischen Operation auf eine lange Reihe beliebiger Werte anwenden möchte. Der Vorteil von SIMD ist hier das die Daten als Block betrachtet werden und so mehrere Werte gleichzeitig bearbeitet werden können, anstatt einen Pixel nach dem anderen abzuarbeiten. Da das Anwendungsgebiet in der Computergrafik bereits bekannt ist, nun eine Betrachtung der Anwendung im wissenschaftlichen Bereich. So kann man sich beispielsweise in der Medizin einen Genstrang als Array vorstellen, der wieder in mehrere kleine MicroArrays unterteilt werden kann und so schnell von der GPU Genomanalysen ausgeführt werden können. Ein praktisches Anwendungsbeispiel und womit man solche Anwendungen eigentlich programmiert wird im folgenden gezeigt. 5.7.2 GPGPU in der Praxis Anwendung findet GPGPU zum Beispiel in der Kryptographie für RSA-Algorithmen [MPS07]. RSA ist ein sogenanntes Public-Key Verschlüsselungsverfahren. Es war der erste Algorithmus, der sowohl zum Signieren, als auch Verschlüsseln geeignet war. Die Verschlüsselung ist sicherer wenn man längere Schlüssel verwendet. Steigert man die Ausführungsgeschwindigkeit des Algorithmus, kann man in gleicher Zeit höhere Sicherheit gewähren, weshalb hier das Portieren auf die GPU auch besonders interessant ist. Ohne näher auf die angewandten Formeln einzugehen, kann mann sagen, das RSA unter anderem mit vielen modulo Operationen und großen Primzahlen arbeitet. Für solche modulo Operationen mit Primzahlen gibt es verschiedene mathematische Verfahren. Hier kommt nun besonders das SIMD Instruction Set zu tragen, da eine Operation auf viele Datenelemente angewendet wird, wofür die GPU wie bereits mehrfach erwähnt, sehr gut geeignet ist. Ein weiteres Anwendungsbeispiel ist das Projekt Folding@home der Stanford University [Uni07]. In diesem Projekt geht es darum sehr aufwändige Berechnungen zur Faltung und Entfaltung von Proteinen durchzuführen, um so deren Zusammenhang mit der Entstehung von Krankheiten zu erforschen. Dabei wird ein Client Programm auf möglichst vielen PCs installiert, um so einen virtuellen Computer Cluster zu erhalten. Im Gegensatz zum ebenfalls bekannten SETI@home Projekt wird hier für die Berechnungen die GPU genutzt. Datenelemente, die dabei benutzt werden sind zum Beispiel Ketten von Aminosäuren die als Array dargestellt werden können. Da bei diesen Berechnungen auch wieder konstante Operationen auf eine Vielzahl von Datenelementen angewendet wird, kommt hier wieder der 5.7. GENERAL PURPOSE COMPUTATION ON GPUS 113 Vorteil der GPU gegenüber der CPU zu Tage. 5.7.3 Compute Unified Device Architecture Der Grafikchiphersteller nVidia, der auch die Unified-Architektur für GPUs als erster eingeführt hat, hat im November 2006 eine eigene API entworfen die Programmierern im GPGPU Bereich eine einfache Schnittstelle bieten soll. Das Problem war bisher, das die gängigen Grafik-APIs wie Direct3D und OpenGL auf die klassischen in der Computergrafik angewandten Operationen ausgelegt sind und nicht zur GPU-Programmierung geeignet sind. Diese neue API von nVidia die für die Programmierung unter C/C++ entwickelt wurde, bietet Programmierern nun eine Schnittstelle um auch andere Algorithmen besser auf die GPU zu portieren. Die API nenn sicht kurz CUDA (Compute Unified Device Architecture) und funktioniert derzeit nur mit der 8000er Serie von nVidia Grafikkarten. AMD bietet für seine GPUs die API CTM (Close to Metal) an. Als Beispiele für die Hauptanwendungsgebiete der API führt nVidia hier Forschung und Sprachentwicklung an. Die vier Hauptmerkmale der CUDA API sind: • Die hohe Performance bei rechenintensiven Anwendungen. • Der Hersteller garantiert die Kompatibiltät mit zukünftigen GPUs von Anwendungen, die mit dem CUDA C-Compiler erzeugt wurden. • Die Anwendbarkeit der etablierten C-Programmiersprache soll für hohe Produktivität sorgen. • CUDA Anwendungen sind frei skalierbar und funktionieren sowohl mit einfach Budget-Versionen von CUDA GPUs, wie auch in speziellen Clustern mit vielen verbundenen GPUs. CUDA beinhaltet auch eine Assembler-Sprache (Maschinencode Sprache) und ein Treiber Interface [nVi07] (CTM beinhaltet diese Erweiterungen ebenfalls). Der Hersteller bietet zu diesem Zweck auf seiner Webseite auch ein SDK-Paket (Software Development Kit) an, das Entwicklern hilft, auf CUDA-fähigen GPUs Anwendungen zu entwickeln. Aufgrund der Art und Weise wie eine Grafikkarte funktioniert, ist sie besonders Effektiv beim lösen von Problemen, die über einen einheitlichen Datenstrom realisiert werden können. So können GPUs nur Vertizes und Fragmente verarbeiten, davon jedoch sehr viele gleichzeitig. Eine optimale GPGPU Anwendung verwendet daher 5.7. GENERAL PURPOSE COMPUTATION ON GPUS 114 große Datensätze (zum Beispiel einen Genstrang als Array), nutzt die Parallelität von vielen SPs und sorgt dafür, dass eine möglichst geringe Abhängigkeit zwischen Elementen herrscht, da sonst zuviele Speicherzugriffe benötigt werden bei denen die GPU gegenüber der CPU zur Zeit keine Vorteile mit sich bringt. 5.7.4 Diskussion Was bei allem Enthusiasmus über diese neue Technologie jedoch auch bedacht werden muss, sind ökologische und ökonomische Bedenken. Auch wenn durch den mit CUDA mitgelieferten C-Compiler theoretisch sehr viele existierende Programme auf die GPU portiert werden könnten, muss ganz klar gesagt werden, dass dies nicht sinnvoll ist. Zum Beispiel ist Programmcode der mit vielen Strings und viele voneinander abhängige Datenelemente einsetzt auf der CPU sehr viel schneller auszuführen. Ist eine große Datenabhängigkeit gegeben ist mit vielen Speicherzugriffen zu rechnen, wobei eine moderne CPU durch einen größeren L2-Cache (Ein Cache-Speicher direkt auf dem Prozessor) der GPU gegenüber im Vorteil ist. Zudem sind die SPs nicht für die Verarbeitung von Strings ausgelegt sondern zum Rechnen mit Floating Point Werten und Matrizen. Wichtig ist auch, dass eine moderne Highend-GPU sehr viel mehr Strom benötigt als eine CPU. Ein Core 2 Duo beispielsweise kommt mit weniger als 60 Watt aus, während eine 8800 GTX knapp 150 Watt benötigt und auch die neuen HD 3870 Modelle mit speziellem Power Management benötigen unter Last immer noch knapp über 100 Watt. Es sollte also gut überlegt werden, ob ein Algorithmus auf der GPU genutzt werden sollte wenn dieser nur minimal schneller ist. Einen Kostenvorteil, den GPUs gegenüber CPUs haben, ist wiederum die leichtere Einsetzbarkeit von mehreren Grafikkarten. Jedes moderne Mainstream-Mainboard (die Hauptplatine im PC) unterstützt mindestens zwei Grafikkarten, die einfach zusammengeschaltet werden können. nVidia bezeichnet diese Technologie als SLI (Scalable Link Interface) und bei AMD heißt das ganze Crossfire. nVidia bietet auch spezielle für CUDA optimierte Rechen-PCs“ (Tesla GPU Computing Processor) die mehrere Grafikkarten in einem ” kompakten System vereinigen und im wesentlichen nicht für Grafik sondern für wissenschaftliche Berechnungen gedacht sind. Im Filmbereich finden diese Maschinen dennoch Einsatz, da hier teils sehr hoher Renderaufwand, der nicht mit Spielen oder einfachen 3D-Grafiken auf Desktop PCs vergleichbar ist, anfällt. 5.8. FAZIT 5.8 115 Fazit Nun kennt man den Ursprung der ersten Grafikkarten in PCs und hat grob den Aufbau einer modernen Grafikkarte gesehen. Die bisher existierende Grafik-Pipeline Architektur wurde gezeigt und wie man dort in den verschiedenen Pipeline Stages 3D-Objekte und Welten transformieren kann. Zudem haben wir auch Einblicke in die mit der G80-Architektur eingeführte Unified-Shader Architektur gewonnen und das Thema der General Purpose Computation on GPUs kennengelernt, welches in Zukunft sicher ein stark wachsendes Segment im Entwicklungsbereich darstellt. Kapitel 6 Computer Animation Jonas Fehr 6.1 6.1.1 Einleitung Was ist Animation? Das Wort Animation stammt vom lateinschen animare (zum Leben erwecken) ab. Hier geht es darum, “lebendige” Bilder zu schaffen. Unterschiedlichsten AnimationsMethoden ist eins gemeinsam: nämlich, dass sie Folgen von Momentaufnahmen aneinanderreihen, um den Eindruck einer flüssigen Bewegung zu erzeugen. Bekanntlich können wir zwischen flüssigen Bewegungen und Sequenzen von Momentaufnahmen eines Ablaufs ab einer bestimmten Bildrate nicht mehr unterscheiden. Ab welcher Bildrate diese Illusion eintritt hängt auch davon ab, wie groß die Änderungen zwischen den Bildern sind und wie (un-)scharf die einzelnen Bilder sind, aber rund dreißig Bilder pro Sekunde ist eine gute Größenordnung. Reduzieren wir im folgenden Animation darauf, Sequenzen von Einzelbildern zu erzeugen, die jeweils eine Momentaufnahme eines zeitlichen Ablaufs darstellen. Dann besteht das Problem darin, zu bestimmen, was in einem Einzelbild zu gegebenem Zeitpunkt dargestellt wird, und dieses Bild zu erzeugen. 6.1.2 Klassische Animationstechniken Während es beim Filmen reicht, in Intervallen eine arrangierte Szene zu belichten, muss beim Animieren i.d.R. die Szene für jedes Bild gestellt werden. Im Schwerpunkt soll es in dieser Ausarbeitung um computergestützte Animation 116 6.1. EINLEITUNG 117 Abbildung 6.1: Frames eines Bewegungsablaufs gehen, aber es lohnt sich ein Blick auf ältere Animationstechniken, da einige Parallelen existieren und sich mit ihnen manche Problemstellung für die RechnerGestützte 3D-Animation veranschaulichen lässt. Beim Puppentrickfilm oder Knetfigurenfilm entsteht Bewegung dadurch, dass Akteure und Gegenstände von Hand in Pose gesetzt werden und eine Aufnahme gemacht wird. Das ganze wiederholt sich ständig, wobei der Folgezustand die Szene zeitlich versetzt um einen Bruchteil einer Sekunde darstellt. Das ist intuitiv aber es ist offensichtlich sehr zeitaufwändig, längere Szenen zu erzeugen. Immerhin müssen die Modelle nicht für jedes Bild neu erzeugt werden. Beim Zeichentrickfilm werden einzelne Bilder gezeichnet. Mit einigen Tricks lässt sich die Effizienz der Animatoren steigern. Etwa indem man mit mehreren Lagen transparenter Folien arbeitet und Bild-Sequenzen von einzelnen Teilen wiederverwendet: so kann man gezeichnete Figuren vor diversen Hintergründen bewegen, usw.. Zeichentrick-Animation wurde immer ausgefeilter und fließbandmäßig organisiert: um die Ressource ’talentierte Zeichner’ effektiver zu nutzen, ließ man sie nur die Schlüßel-Posen zeichnen (Key-Framing), eine größere Anzahl Zeichner zeichneten die In-Between-Frames (Tweening) und wiederum andere kümmerten sich ausschließlich um das farbige Ausfüllen der Zeichnungen (Inking). Dieses Streben nach höherer Effizienz setzt sich bei der Computer-Grafik fort: man versucht, den Animateuren die nicht-kreativen Aufgaben abzunehmen und sie an den Computer zu deligieren. Dazu werden Werkzeuge geschaffen, die es ermöglichen, Abläufe relativ abstrakt zu beschreiben und aus den Beschreibungen viele monotone Computer-Aufgaben zu erzeugen. Für diesen Gewinn an Effizienz nahm man auch in Kauf, dass der Animateur weniger Kontrolle im Detail über die erzeugten Szenen hat. Das sah man frühen CG-Filmen auch an - sie wirkten im Vergleich zu Zeichentrick-Filmen etwas unnatürlich und hölzern. Aber mit besseren Werkzeugen wurden bessere Animationen möglich. Bevor es mit Computergrafik weitergeht will ich noch kurz auf ein paar Parallelen hinweisen, man hat vielleicht ein plastischeres Bild einer Methode, wenn man ihre klassische Entsprechung kennt. 6.2. COMPUTER ANIMATION - EINLEITUNG ZUR 3D-ANIMATION 118 • Das erwähnte Tweening taucht in der Computer-Grafik als Key-FrameInterpolation wieder auf, bei der zwischen zwei Posen interpoliert wird, um Zwischen-Bilder zu finden. • Das noch unerwähnte Rotoscoping des Zeichentrickfilms, bei dem Bewegungen eines Films in Einzelbildern als Silhouette auf eine Mattscheibe projeziert werden, damit der Animator davon leicht variiert abpausen kann, hat in der Computer-Grafik als Entsprechung das Motion-Capturing. Der Zweck der Sache ist, dass natürliche Bewegungen von Tieren oder Menschen einfach schwer zu animieren ist. Speziell für CG Sequenzen lassen sich natürliche Bewegungen auf 3D-Modelle effektiv übertragen, was eine Menge Animations-Arbeit spart. Hierzu bekommen Schauspieler an relevanten Stellen Markierungen oder Sensoren, deren Positionen protokolliert werden, während sie schauspielern. • Wenn später Kinematik und Inverse Kinematik erwähnt werden, kann man sich Gliederpuppen vorstellen, wie sie in sog. Stop Motion Animationen genutzt werden. Was gelenkige Puppen von sich aus können, wird auf dem Rechner nachempfunden. • Deformation: Die Free-Form-Deformation, die später vorgestellt wird, hat eine gewisse Ähnlichkeit zur Verformung von Knete-Figuren. 6.2 Computer Animation - Einleitung zur 3D-Animation Ich will nicht gesondert auf 2D-Animation eingehen. Die 3D Animations-Methoden lassen sich aber weitgehend auf 2D übertragen. Dieser Abschnitt soll elementare Operationen vorstellen, die zum Animieren verwendet werden und auf die spätere Abschnitte aufbauen. Mit diesen Operationen lässt sich eine Anordnung von Objekten im 3D-Raum manipulieren. Die Momentaufnahmen, die für eine Bilder-Serie benötigt werden, werden durch ständige Neu-Anordnung der Szene erreicht. Translationen, Rotationen, globale und lokale Koordinatensysteme und die “Kamera” sollten bekannt sein (siehe auch Themen der Vorträge 1 und 3). Grundlegende Manipulationen einer 3D-Szene: Sei die Ausgangslage, dass wir 3D Modelle im Koordinatensystem positioniert haben und damit eine Szene abdrehen wollen. Wir haben eine Idee, wie sich welche Objekte bewegen sollen und stehen vor dem Problem, dass wir für gegebene 6.2. COMPUTER ANIMATION - EINLEITUNG ZUR 3D-ANIMATION 119 Zeitpunkte die Szene so arrangieren müssen, wie es das Drehbuch vorsieht. Vom Rendering der Szene brauchen wir nichts zu wissen. • Bewegung der Kamera Schon mit der Bewegung der Kamera relativ zu einer statischen Anordnung von Objekten lassen sich interessante Aufnahmen machen: Man kann einzelne Gegenstände aus sich wandelnder Perspektive betrachten oder sich durch komplexe virtuelle Welten bewegen. In einem ganz einfachem Szenario könnte man von einem 3,6 SekundenFilm ausgehen, der unsere Objekte leblos auf einem Präsentationsteller zeigt, wärend die Kamera einmal einen Kreis um die Szene fährt. Zuerst positionieren wir die Kamera weit genug vom Koordinatenursprung, dass sie die komplette Szene zeigt und lassen sie auf den Nullpunkt blicken. Pro Sekunde Film-Laufzeit sollten also 100◦ zurückgelegt werden und wir wollen 25 Bilder/s produzieren: also rotieren wir die Kamera um 4◦ um die Y-Achse, lassen das Bild rendern und wiederholen den Vorgang noch 89 mal und “that’s a wrap!”. • Bewegung von Gegenständen Das nächste simple Beispiel soll nur mit Translationen arbeiten. Ausgangslage sind unsere Objekte, die im Raum verstreut sind und wir wollen, dass ein Raumschiff über die Sachen fliegt. Wie lange die Sequenz dauert, ist uns egal, aber sie endet, wenn das Raumschiff 1000 einheiten weit an uns vorbeigeflogen ist. Das Schiff fliegt konstante 25 Einheiten pro Sekunde. Das Raumschiff wird etwas hinter und oberhalb der Kamera positioniert und los geht’s: rendern, Z-Koordinate des Raumschiff um 1 dekrementieren, und widerholen bis die Z-Koordinate ≤ −1000 ist. 6.2.1 Rigid Body Animation Die vorangegangenen einfachen Beispiele 6.2 kann man als “Rigid Body Animation” kategorisieren, weil die Objekte ihre Form nicht ändern. Damit lässt sich schon sehr viel machen, aber die Objekte bleiben starr: nur Translationen und Rotationen werden zur Transformation genutzt. Der Begriff “Rigid Body” hat eine Konnotation von Leblosigkeit, aber mit starren Körpern und den “Rigid-Body-Transformations” (Translation, Rotation) lassen sich auch Objekte realisieren, die ihre Form ändern. Man kann aus Gruppen von 6.2. COMPUTER ANIMATION - EINLEITUNG ZUR 3D-ANIMATION 120 “Rigid Bodies” interessantere Objekte erstellen, und durch koordinierte Bewegung der Einzelteile den Eindruck eines sich verformenden Objekts schaffen. Eine Windmühle, bei der sich (nur) der Flügel dreht, könnten wir mit elementaren Transformationen schon hinbekommen. Oder wir basteln eine Figur, bei der Kopf, Oberköper, Arme, Hände, Beine und Füße jeweils statische Modelle sind. Durch koordinierte Bewegungen der Einzelteile entsteht der Eindruck eines zusammenhängenden Roboters, statt einer Menge Einzelteile. In der Koordination der Teile liegt die Komplexität: speziall wenn Einzelteile über rotierende Achsen miteinander verbunden sind (der Normalfall). Eine Rotation eines Teils sollte sich korrekt auf verbundene Teile, ihre relative Position und Orientierung auswirken. Eine Bewegung hat ggf. Auswirkungen auf ganze Ketten von verbundenen Gliedern. Es muss einiges berücksichtigt werden, damit der Zusammenhang der Einzelteile erhalten bleibt. Wer darüber nachdenkt und sich fragt: “wie rotiere ich eigentlich um eine beliebige Achse?” Oder “muss ich mir nicht alle möglichen relativen Beziehungen und Zustände merken? Wie halte ich die Informationen fest und werte sie aus?”, der wird erleichtert sein, zu wissen, dass es hierfür ein methodisches Vorgehen gibt. Das wird im Abschnitt 6.6 vorgestellt. Als nächstes werden Techniken Vorgestellt, mit denen sich die Positionierung und Orientierung von Gegenständen effektiv und flexibel animieren lassen - erstmal von einfachen Objekten (Rigid Bodies) ausgehend. Bei den bisher vorgestellten Methoden wurden die Modelle entweder “von Hand” Bild für Bild animiert, oder, wie bei den 3D-Beispielen von oben 6.2 mit einfachen Funktionen, die einen Parameterwert (Koordinate, Rotation) abhängig von der Zeit ausdrücken. Man könnte auch beliebig komplexe, speziell zugeschnittene Skripte schreiben, die Objekte einer Szene zeitabhängig arrangieren. Aber das ist weder besonders effektiv (geringe Wiederverwendbarkeit) noch besonders elegant. Anstatt das Rad neu zu erfinden und komplexe Animations-Skripte für Probleme zu schreiben, die längst gelöst wurden, lässt sich für viele Aufgaben auf bewährte Verfahren zurückgreifen, mit denen sich Bewegungsabläufe definieren und durchführen lassen. In Animationssoftware-Paketen sind entsprechende Werkzeuge integriert; Animateure basteln im GUI mit Schaltflächen, Zeitleisten, Pfad-Definitionen und manipulieren Figuren mit der Maus. 6.3. KEY-FRAMING 6.3 121 Key-Framing Die Werkzeuge, die Animateure unterstützen, sollten ihnen möglichst viel Arbeit abnehmen, und gleichzeitig Möglichkeiten bieten, soviel Kontrolle über die Animation zu haben, wie nötig. Bei den Beispielen, die in (6.2) skizziert wurden, gab es nur primitive Bewegung, die sich mit einer trivialen Funktion bzw. Iteration umsetzen ließ. Nur selten wird es reichen, Objekte entsprechend einer mathematischen Funktion über die Zeit zu verschieben und rotieren: die Animateure müssen flexibel gestalten können, um variablere, interessantere Sequenzen animieren zu können. Eingangs wurde das Tweening beim Zeichentrickfilm erwähnt und darauf hingewiesen, dass es eine Entsprechung in der 3D-Animation hat. Was beim Zeichentrickfilm die “Tweener” erledigt haben, wird bei der Computer-Animation vom Computer errechnet. Key-Framing in der Computer-Animation ist vielseitiger, als das Keying beim Zeichentrick-Verfahren. Beim Zeichentrick wurde - wenn wir das Schichten von transparenten Folien beiseite lassen - die ganze Szene gezeichnet. Beim CG Key-Framing brauchen nur die nötigen Parameter festgehalten zu werden: etwa ein einziger Punkt für die Position eines Modells, ein Rotations-Winkel, Orientierungs-Vektor oder eine sonstige Eigenschaft, die sich in der Animation widerspiegelt. Für die Parameter, deren Werte für Schlüssel-Momente festgehalten wurden muss natürlich klar sein, wie sie sich auf welche Objekte der Szene auswirken. Häufig werden die Beziehungen zwischen Objekten und die Parameter in einem Hierarchischen Modell (6.6) festgehalten, für das festgelegt ist, wie sich ein Parameter auf welche Teile auswirkt. Wenn die Voraussetzungen erfüllt sind, lassen sich die Key-Frames für die Szene definieren und der Computer ist in der Lage, alle Einzelbilder für die Szene in einem Rutsch ohne Eingriffe von Animatoren zu generieren. Hierzu werden die Parameter der Key-Frames interpoliert und die Szene für die Einzelbilder arrangiert. 6.4 Interpolation Es gibt ein paar Sachen zu beachten im Kontext von Keyframing. Wenn zwischen Keyframes interpoliert wird, erwartet man i.d.R. dass klar ist, wie die ZwischenWerte ausfallen. Wenn man sich wenig Gedanken über die Frames macht, die man anlegt, können unerwartete Ergebnise resultieren. 6.4. INTERPOLATION 122 Angenommen es wird ein hüpfender Ball animiert und wir geben naiv einen KeyFrame pro Sekunde an. Dann ist abzusehen, dass der Ball in aufeinanderfolgenden Key-Frames i.d.R. nicht in der gleichen Auf- oder Abwärtsbewegung ist und was resultiert, ist eine Animation eines Balls, der nur selten den Boden berührt und sich erratisch in der Luft hin und her bewegt. Es ist also wichtig, Key-Frames an den Stellen zu definieren, an denen sich eine Bewegung stark ändert. Es müssen also geeignete Keyframes definiert werden, die signifikante Momente einer Bewegung festhalten. Außerdem ist die Wahl der Parameter, über die interpoliert wird und die Interpolationsmethode wichtig. Es lohnt sich nochmal auf Unterschiede zwischen Tweening beim Zeichentrick und Keyframing bei der Computeranimation hinzuweisen, um zu verstehen, warum die Wahl der Parameter und die Interpolationsmethode eine Rolle spielen. Beim Zeichentrick besteht ein Keyframe aus einer kompletten Zeichnung: für Menschen ist das geeignet und eindeutig, für Maschinen nicht: da der Computer keine Ahnung hat, was durch Bilder oder Anordnungen von Eckpunkten im 3D-Raum dargestellt wird, kann er schlecht folgern, wie ein Zwischenbild aussieht, wenn man ihm nicht “unter die Arme greift”. Bei der cg-Animation hält man deswegen Parameter fest, die die Anordnung von 3D-Modellen beeinflussen: und zwar so eindeutig, dass ein Rechner durch bloßes Regelfolgen die Zwischenbilder erzeugen kann. Und da stellt sich die Frage, welche Parameter beschreiben eine Bewegung am besten (Eine Position? Ein Drehungswinkel? Was ist der Bezugspunkt?) und welches Verhalten erwarten wir von der Bewegung noch? Wie ändern sich die Parameter (gleichmäßig, sprunghaft, graduell, variabel schnell)? Hierzu ein weiteres Ball-Beispiel: Angenommen, wir animieren einen Ball, der schräg nach oben gewurfen wird und fällt, und wir wollen nicht so viele Frames definieren. Wir legen 3 Positionen fest: den Start-Punkt, den Scheitel und den Punkt, wo der Ball den Boden berührt. Wenn linear zwischen den Keyframes interpoliert wird, sieht die Flugbahn unnatürlich aus, wegen des spitzen Winkels. Authentischer wäre eine Parabel, statt eines umgedrehten “V”. Außerdem würde man erwarten, dass der Ball beim Scheitelpunkt abbremst und sich im Fallen wieder beschleunigt. Die Probleme könnten umgangen werden, indem man eine große Anzahl von Keyframes definiert - aber das ist keine echte Option, vor allem wegen des hohen Aufwands, aber es bliebe auch der Defekt, dass sich die Geschwindigkeit des Balls sprunghaft ändert - auch wenn das bei vielen Keyframes nicht mehr auffällt. Im folgenden Abschnitt werden Methoden angesprochen, die es ermöglichen, einen besseren Ball zu animieren. 6.4. INTERPOLATION 123 Abbildung 6.2: Flugbahn des Balls durch 3 Punkte definiert. Unterschiedliche Interpolationsmethoden 6.4.1 Interpolation von parametrischen Kurven Abbildung 6.3: Splines in 2D. Graue Kontrollpunkte sind durch graue Linien verbunden (lineare Interpolation). Rote Punkte: Auswertung d. Splines in gleichmäßigen Schritten. Links: mit Arclength Re-Parametrisierung; Rechts: ohne Abbildung 6.4: Eine Spline in 3D definiert einen Bewegungs-Pfad Parametrische Kurven wurden in den Vorträgen zur geometrischen Modellierung behandelt und ich gehe davon aus, dass B-Splines bekannt sind. Ich will die hier nochmal im Kontext der Interpolation aufgreifen, weil sie nicht nur beim modellieren, sondern auch beim Animieren eine große Rolle spielen. Zur Erinnerung: Parametrische Kurven sind durch Kontrollpunkte und eine interpolierende Funktion definiert. Für einen Parameter aus dem Definitionsbereich der Kurve interpoliert die Funktion den Wert der Kurve. Weiter Oben 6.4 wurde an einem Interpolationsbeispiel mit einem Ball gezeigt, dass lineare Interpolation für bestimmte Aufgaben unbefriedigende Ergebnisse 6.4. INTERPOLATION 124 liefert. Wir hatten 3 Positionsangaben für den Ball, und die Interpolation lieferte einen spitzen Winkel am Scheitelpunkt. Wenn die Positionswerte als Kontroll-Punkte einer Spline genutzt werden und wir über die interpolieren, sieht das Ergebnis deutlich natürlicher aus, weil eine Kurve abgetastet wird. Für die meisten natürlichen Bewegungen sind Kurven natürlicher als GeradenSegmente mit spitzen Winkeln. Interpolation über Parametrische Kurven wirkt meist natürlicher, weil man von Gegenständen mit Masse meist erwartet, dass sie ihre Orientierung graduell ändern. Der fliegende Ball lässt sich mit Spline-Interpolation schon viel schöner animieren, aber da war noch die Sache mit der Geschwindigkeit, die unnatürlich wirkte. Wie man damit umgehen kann ist im folgendem Abschnitt 6.4.2 beschrieben. Bevor es damit weitergeht, noch ein Hinweis zur Interpolation von Splines. Gleichmäßige Abstände der Parameterisierungs-Variable haben nicht gleichmäßige Abstände beim Wert zur Folge (Siehe Zusammenhang zw. Knotenvektor, Kontrollpunkten und dem Parameter). Man bevorzugt aber häufig ein lineares Verhältnis zwischen Argument und Wert, damit sich beim Abtasten der Kurve in gleichmäßigen Parameter-Abständen der ermittelte Wert ebenfalls gleichmäßig ändert und nicht abhängig von der Kurvenform unterschiedlich schnell. Eine Möglichkeit, die lineare Beziehung herzustellen, ist, die Spline einmal in kleinen Schritten auszuwerten und jeweils die Distanz zwischen 2 Werten zu errechnen (Pfad-Abschnitt). Die Summer der Pfad-Abschnitte ist die Gesamtlänge der Kurve. Beim ermitteln der Gesamtlänge entgehen uns die Teillängen nicht (wir summieren ja die Teillängen auf, um die Gesamtlänge zu ermitteln). Für einen Abschnitt von U0 bis U1, dessen Länge wir ermitteln notieren wir für U1 in einer Tabelle die bisher aufsummierte Länge in einer Tabelle - aus der Tabelle und der Gesamtlänge der Kurve lässt sich nachher ablesen, dass an Stelle U1 eine bestimmte Strecke der Kurve zurückgelegt wurde. Durch die Gesamtlänge geteilt ergibst das eine Prozentangabe. Wie gesagt: eine Spline, die auf [0,100] definiert ist liefert mit Argument U=50 i.A. nicht den Mittel-Punkt einer von der Kurve beschriebenen Linie. Mit der Tabelle können wir aber zwei Argumente finden, von denen eins ¡50 und eins ¿= 50 Prozent der zurückgelegten Strecke entspricht. Ein gewichtetes Mittel dieser beiden Argument-Werte wird als Ersatz-Argument eingesetzt und wir haben eine praktisch lineare Beziehung zwischen Argument und Pfad-Länge. Vergleiche Abb. 6.3. Im nächsten Unterabschnitt (6.4.2) wird die “Re-Parametrisierung” noch thema- 6.4. INTERPOLATION 125 tisiert werden, wenn wir die Dynamik, mit der eine Kurve abgetastet wird selbst bestimmen wollen. 6.4.2 Dynamik von Bewegungen Wenn eine Spline für einen Parameter ausgewertet wird, der sich über die Zeit ändert, können wir von einer Geschwindigkeit sprechen, mit der der interpolierte Punkt auf der Kurve bewegt. Bei der oben angerprochenen Re-Parametrisierung, ging es darum, eine gleichmäßige “Geschwindigkeit” zu ermöglichen. Hier geht es darum, eine eigene Dynamik zu definieren, mit der die Kurve abgetastet wird. Um noch ein letztes Mal auf das Beispiel mit dem Ball 6.4 zu sprechen zu kommen: der letzte Punkt an dem noch etwas auszusetzen war, war, dass die Geschwindigkeit nicht passte. Um das Problem zu lösen, wollen wir die Dynamik der Bewegung entlang des Pfads kontrollieren. Bei einem gewurfenem Ball könnte man dies auch mit einer physikalischen Formel tun, aber hier soll die Dynamik mit einer Spline-Kurve geregelt werden. Gegeben sei eine Pfad-Angabe in Form einer Spline, die - man kann es ja willkürlich wählen - zwischen 0-100 definiert ist (0=Start, 100=Ziel). Durch ReParametrisierung verhält sich das Argument linear zum Wert. D.h. 50 ergibt die Mitte des Pfades, 33,3 entspricht einem Drittel, usw. (die oben erwähnte ParameterErsetzung erfolgt transparent in der Auswertungs-Funktion). Jetzt definieren wir eine Spline für die Dynamik: das Argument ist die Zeit und der Wert ist eine Zahl zwischen 0 und 100, der die Stelle des Pfades angibt. Für das gewünschte Ball-Verhalten sieht unsere Dynamik-Kurve etwa so aus: sie steigt, geht in ein Plateau über (das ist der Zeitpunkt zu dem der Ball auf dem Scheitelpunkt der Kurve ist) und steigt dann weiter bis 100. Wir setzen nun s(t) in die Funktion ein, die druch Parameter-Ersetzung das u einsetzt, für das p(u) dem Pfad-Anteil s(t) entspricht. Abbildung 6.5: Links: Pfad-Position s(t) für Zeit t. Rechts: Die Kurve für Parameter u. Position für Gegebenes t ist durch p(reparam(s(t))) gegeben 6.5. ANIMATIONS-ZYKLEN 126 Die Geschwindigkeit ist, wie der Pfad, durch eine stetige Kurve definiet, was dazu führt, dass Be- und Ent-Schleunigung auf Anhieb recht natürlich wirken. Dass der Pfad und die Geschwindigkeit seperat definiert sind, hat auch den Vorteil, dass man etwa nachträglich die Dynamik fein-tunen kann. Die Dynamik-Kurve muss nicht monoton steigen: man kann damit genausogut bewirken, dass ein eine Kurve vor- und rückwärts abgetastet wird: u.U. möchte man modellierte Bewegungen ja vor- und rückwärts ausführen. Ein Beispiel: Angenommen, wir modellieren mit einer Kurve nochmal die Position eines Balls dessen Aufund Abwärtsbewegung symmetrisch ist (der Ball wird gedribbelt). Den Pfad definieren wir nur für eine Richtung und eine Dynamik-Kurve beschreibt die Pfad-Position in eine Richtung und zurück (für t=0..100 geht s(t) von 0 auf 100 und zurück auf 0). Wir haben also ein Dribbling definiert, bei dem der Ball an der Stelle endet, wo er anfangs war. Wir könnten übrigens, weil der Ball exakt da endet, wo er gestartet ist, die Bewegung, die bei t=100 endet, problemlos bei t=0 fortsetzen. Mit t =< Zeit > %100 hätten wir ein passendes t, um die Bewegung sich zyklisch wiederholen zu lassen. 6.5 Animations-Zyklen Einige Bewegungen wiederholen sich regelmäßig. Weiter oben war die Rede davon, dass man Objekten einen Positions-Pfad vorgeben kann, die Bewegungs-Dynamik seperat definieren kann und sich auch andere Parameter, z.B. die Orientierung nach gleichem Muster definieren und interpolieren kann. So elegant die Methode ist, für wiederkehrende, gleiche Abläufe ist das definieren von immer neuen Frames zu aufwändig. Wenn wir ein Auto animieren, sollen sich die Räder während der Fahrt drehen. Es wäre eine Sisyphos-Arbeit, nur der Räder wegen Key-Frames für einzelne RadUmdrehungen zu definieren, wenn eigentlich eine Pfad- und Dynamik-Definition schon alle Informationen zum Autofahren liefert: Mit der Dynamik wird gesteuert, wie schnell das Auto wann fährt, aus dem Pfad lässt sich die Orientierung des Autos errechnen (vgl. Frenet Frame). Das Verhalten der Räder lässt sich als Funktion ausdrücken: pro zurückgelegter Einheit auf der Strasse, dreht sich das Rad X mal, dann ist die nötige Reifen-Rotation: (Entf ernung ∗ X ∗ 360)%360 Grad. Bei Armen und Beinen, die während des Gehens einer Figur eigentlich immer das gleiche tun, sieht es ähnlich aus. Eine Funktion für die Körper-Animation zu 6.6. HIERARCHISCHE MODELLE UND KINEMATIK 127 finden ist etwas komplizierter als einen Reifen zu drehen. Eine Möglichkeit ist, eine kurze Posen-Sequenz für die Figur anzufertigen, bei der die letze Pose nahtlos in die erste übergeht. Vergleiche hierzu Abbildung 6.1. Das kann man nach Bedarf verfeinern durch Funktionen, die mehr Parameter betrachten und mehr Posen kennen (z.B. Rechts-, Links-, Rückwärts-Laufbewegungen, die je nach Pfad-Krümmung und positiver/negativer Geschwindigkeit genutzt werden). Angenommen eine Zyklusche Bewegung ist durch Schlüsselposen definiert. Für einfache Spiele und Simulationen reicht es u.U. aus, eine diskrete Anzahl von Posen direkt anzusteuern. Für anspruchsvollere Animation ist das nicht gut genug: da möchte man flüssige Übergänge zwischen den Schlüssel-Posen haben. Dafür würde man zwischen den Posen interpolieren: das passt zum Key-Framing Schema. Um die Zwischen-Posen einer Figur ermitteln zu können, muss die Figur in einer Form modelliert sein, die für die Interpolation geeignet ist. Einzelne Posen als Rigid-Body-Modell zu haben, deren Vertizes interpolieren werden, führt zu absurden Zwischenposen; und eine lose Anordnung von Rigid-Bodies, die zusammen die Figur ausmachen, einzeln bzgl. Orientierung und Position zu interpolieren, ist kaum besser. Wenn man sich für beide Fälle die Zwischenposen vorstellt für Pose-1: Arm nach unten ausgestreckt und Pose-2: Arm nach oben ausgestreckt, sieht man, dass es so nicht geht: in dem einen Fall verschwindet der Arm zwischenzeitlich, in dem anderen trennen und sich Schulter, Ober- und Unterarm. (Das Problem mit den positionell interpolierten Vertizes ist offensichtlich; Beim zweiten Fall - Glieder unkoordiniert interpolieren - würde der Unterarm nicht der Rotation des Oberarms folgen, sondern sich um seine eigene Achse drehen und aufwärts translieren.) Im Abschnitt Key-Framing 6.3 wurde erwähnt, das klar sein müsse, wie sich interpolierte Parameter auf welche Objekte auswirken sollen - das gilt speziell für zusammengesetzte, sogannate “artikulierte” Objekte. Im folgenden Abschnitt 6.6 wird ein Modell vorgestellt, das sich zur Interpolation von sogenannten Posen eignet. Posen sind - wie der Name vermuten lässt - Haltungen von Figuren - Bei hierarchischen Modellen werden sie durch eine Menge Parameter ausgedrückt, die bewirken, dass eine Figur ebenjene Haltung einnimmt. 6.6 Hierarchische Modelle und Kinematik Die Idee der im Abschnitt 6.2.1 angesprochenen Gruppierung von Körpern, um sie gemeinsam zu manipulieren, lässt sich zu hierarchichen Modellen ausbauen. In dem 6.6. HIERARCHISCHE MODELLE UND KINEMATIK 128 Abbildung 6.6: Matrix-Transformation: Translation, Rotation Modell werden Beziehungen zwischen einzelnen Körpern definiert. Eine typisches Hierarchisches Modell, ist als Baum modelliert, bei dem in Knoten und Kanten Informationen festgehalten werden, die miteinander verbundene Objekte auszeichnen und in Beziehung zueinander setzen. Wenn ein Mensch modelliert wird, definieren Knoten ein Körperteil, während Kanten das Bindeglied zu weiteren Körperteilen sind. Man kann sich die Kanten als Gelenke vorstellen: sie speichern z.B. die Information, in welchem Winkel und mit welcher Verschiebung die Kind-Knoten verbunden sind. Gelenke mit mehreren Freiheitsgraden lassen sich durch hintereinanderschalten von einfachen Gelenken konstruieren. So kann man für ein Gelenk den Offset des Modells (Körperteil, der am Gelenk sitzt) und einen Orientierungs-Vektor (Rotations-Achse) konstant speichern und hat als Variable nur eine Winkel-Angabe (Rotations-Winkel). Das Vortragsthema “Mathematical foundations - transformations and coordinates” hätte Translationen, Rotationen, und das Rechnen mit Matrizen vorgestellt. Interessant zu wissen ist, dass sich Transformationen mit Matrizen ausdrücken lassen, und dass sich Kompositionen von Transformationen durch Multiplikation der Matrizen darstellen lässt (siehe Abb. 6.6). Wie gesagt, wird für jeden Knoten (Körperteil) festgehalten wie es relativ zum Elternknoten versetzt ist und in welchem Winkel er gedreht ist. Der Wurzelknoten bezieht sich entweder auf den Ursprung des globalen Koordinatensystems oder des Kontexts in dem das Modell platziert wird. Wenn wir die Rotationen kurz ignorieren, können wir für jeden Knoten im Baum die Koordinaten des Kontext-Koordinaten-Systems (ggf. Welt-Koordinaten) bestimmen, indem wir einem Pfad zur Wurzel folgen und die Offsets zu den jeweils übergeordneten Knoten aufsummieren. Wenn ein solches Modell erstellt wurde, steht die Figur in ihrer Ausgangs-Pose. Zum Zeichnen des Modells wird ein Tiefendurchlauf durch den Baum gemacht: 6.6. HIERARCHISCHE MODELLE UND KINEMATIK 129 Abwärtsgehend werden die Transformationen akkumuliert (Komposition der Abbildungen durch Matrix-Multiplikation) und die resultierende Transformations-Matrix mit jedem Schritt tiefer im Baum auf einen Stack ge-pushed - sie wird für die anderen Teilbäume ab diesem Knoten noch gebraucht. Aufwärtsgehend wird die Matrize vom Stack ge-popped (Arbeit an diesem Teilbaum ist abgeschlossen), und die Matrize des Eltern-Knotens wird zur aktuellen Transformations-Matrix. Wenn z.B. der Daumen ein Blatt des Baums ist, das gerade abgearbeitet wurde, wird seine Transformations-Matrix vom Stack ge-popped, oben auf dem Stack findet sich die Hand-Transformations-Matrix wieder. Sie wird zur aktuellen TransformationsMatrix, mit der der Transformationsvorgang der restlichen Finger beginnt. Bei jedem Knoten, der betrachtet wird, wird die Transformations-Matrix mit der Translations- und Rotations-Matrix multipliziert. Die Vertices, die das Objekt am Knoten definieren werden mit der Matrix multipliziert und an die Render-Pipeline übergeben. Danach geht es mit der Traversierung des Baums weiter. Die Menge der Winkel-Angaben an den Gelenken ergibt die Pose (Offsets und Rotationsachsen sind konstante - interessant sind die Variablen). Man spricht auch von einem “Pose-Vector”. Zur Animation eines Hierarchichen Modells können vordefinierte Posen-Vektoren oder dynamisch errechnete Posen-Vektoren genutzt werden. Betrachten wir Abb. 6.1 und denken nochmal an Animations-Zyklen (s. Abschnitt 6.5): wir könnten uns Bewegungs-Posen für das Gehen anlegen und zwischen den Pose-Vektoren interpolieren (nach Pose n geht’s mit Pose 1 weiter, usw.), um eine fließende Bewegung zu animieren. Das Steuern eines hierarchischen Objekts über die Gelenk-Angabe nennt man “Forward-Kinematics”: der Pose-Vektor bestimmt eindeutig die Position und Orientierung der Einzelglieder. Beispiel für Animation mit FW-Kinematik Siehe hierzu Abbildung 6.7. Es soll ein Gang modelliert werden. Der Einfachheit halber wird nur ein Bein von der Hüfte bis zum Unterschenkel betrachtet und der Fuß wird auch ignoriert. Die Hüfte stellt den Wurzelknoten der Hierarchie dar. Sie wird in das globale Koordinatensystem transliert. Der Oberschenkel ist über ein Gelenk mit der Hüfte verbunden und der Unterschenkel ist am Knie mit ihm verbunden. Die Hüfte animieren wir, indem wir ihr eine Gerade als Pfad vorgeben und die sie entsprechend positionieren. Jetzt müssen noch die Beine bewegt werden. Details wie Hüft-Wippen oder das anpassen der Beinbewegung, so dass es zur Geschwindigkeit der Hüft-Translation passt, klammern wir aus - die Beine 6.6. HIERARCHISCHE MODELLE UND KINEMATIK 130 sollen sich erstmal einfach bewegen. Wir haben ein hierarchisches Modell, und die Pose hängt von den Winkeln der Gelenke ab. Jetzt interpolieren wir die Gelenkwinkel, indem wir Kurven definieren, die die Winkel für gegebene Zeit ausdrücken. Der Winkel zwischen Hüfte und Oberschenkel ist anfangs 0◦ , wächst auf 45◦ an (Bein ist vorne), verringert sich auf -35◦ und nimmt zu, bis er wieder 0◦ ist. Der Winkel zwischen Knie und Unterschenkel variiert zwischen 0◦ und -35◦ . Während der Oberschenkel sich nach vorne orientiert, ist das Knie geknickt. Beim Auftreten vorne ist es wieder durchgedruckt und nach dem Abrollen des Fußes (der hier nicht modelliert wird) ist das Knie wieder geknickt und der Unterschenkel um -35◦ gedreht. Wie weiter oben im Abschnitt erwähnt, müssen die Transformationen vom Wurzel-Knoten ausgehend akkumuliert werden. Die Vertizes des Unterschenkel-Modells werden folgendermaßen Transformiert: (Tranlation: Hüfte zu Welt) * (Translation: Oberschenkel zu Hüfte) * (Rotation d. Oberschenkels) * (Translation: Knie zu Oberschenkel) * (Rotation d. Unterschenkels) * (Vertizes) Abbildung 6.7: FW-Kinematik, Animation eines Beins - Quelle: [Wat93] Die Forward Kinematik setzt voraus, das die Animatoren die Posen vorgeben: Also Key-Frames oder Skripte anlegen, die die Gelenk-Winkel definieren. Eine Pose zu modellieren, ist mit einigem Aufwand verbunden. Komfortabler wäre es für die Animatoren, wenn sie die Pose einer Figur definieren könnten ohne alle Winkel anzugeben. Wenn es in einer Sequenz darauf ankommt, dass zwei Figuren sich die Hände schütteln, wäre es schön, wenn man allein die Position und Orientierung der Hände angeben müsste und der Rechner errechnet, wie sich Unter- und Oberarm bewegen und die Rotationen an Ellenbogen und Schulter ausfallen. 6.7. CHARAKTER ANIMATION MIT SKELETT-MODELL 131 Mit solchen Problemen beschäftigt sich die Inverse Kinematik (IK): Wir kennen die gewünschte Pose (die Winkelangaben) nicht, bekannt ist nur die aktuelle Pose. Wir fordern, dass ein Teil eine bestimmte Orientierung und Position haben soll. Zum Beispiel könnten wir fordern, dass die Hand einer Figur am Griff einer Teekanne sein soll, die in der Nähe steht. Ein sogenannter “IK-Solver” soll uns zur Problemstellung die geeignete Pose ermitteln. Formeller: gegeben sind eine oder mehrere sog. “End-Effektoren” mit geforderter Orientierung und Position. Gesucht sind die Winkel-Angaben, die zu einer Pose führen, die die Forderungen erfüllt. Häufig gibt es noch zusätzliche Einschränkungen für die Gelenke, die nur Winkel in einem bestimmten Intervall haben dürfen. Oder es werden einzelne Körperteile “verankert”, sodass sich nur deren Kind-Knoten frei bewegen dürfen. End-Effektoren sind die Körperteile, deren Position und Orientierung vom Animator gegeben wird. Ensprechend ihrer Vorgabe ist der Rest zu errechnen. Eine Ansicht des Problems ist ein Gleichungssystem, bei dem jede Gleichung einen Winkel und seinen Einfluss auf den Fehler (bzgl. gewünschter Konstellation des Endeffektors) beschreibt. Ein analytisches Vorgehen ist häufig so kompliziert, dass man stattdessen versucht, sich iterativ heranzutasten. U.U. gibt es keine oder beliebig viele Posen, die die Forderungen erfüllen. Gute Lösungen zu finden, die gleichzeitig natürlich aussehen ist eine Herausforderung. Das Thema ist zu komplex, um es hier zu behandeln, aber ich wollte die Problemstellung zumindest erwähnt haben. 6.7 Charakter Animation mit Skelett-Modell Bei der Animation von Wirbeltieren werden häufig einfache Skelett-Modelle zugrundegelegt, die die für die Animation wesentlichen Knochen enthalten. Ein Skelett könnte folgendes enthalten: Unterschenkel, Oberschenkel, Oberkörper, Schädel, Oberarme, Unterarme, Hände. Die Knochen haben eine Platzhalter-Funktion. Das Skelett enthält die Teile, deren Anordnung das Gesamtbild eines Menschen oder Tieres wesentlich ausmachen. Dieses Gerüst wird animiert und zu jeder Pose wird auf ihm die “Haut” angebracht - das heisst, Oberflächenmodelle, die i.d.R. als Patches statt fertiger Polygon-Meshes vorliegen (dazu gleich mehr). Es ist bekannt, wo Arme, Beine, etc. relativ zu den Knochen zu plazieren sind: wenn einzelne Oberflächen nicht dynamisch generiert werden, oder sich über mehrere Knochen strecken, muss die Oberfläche nur den Offset zum Knochen und dessen Orientierung 6.8. KOLLISIONS-ERKENNUNG 132 nachvollziehen (siehe Hierarchischen Modelle 6.6). Andernfalls kann man entlang den Knochen wandern und die Oberfläche durch Platzierung von Vertices formen (“Sweeping”). Man kann Posen und Animations-Zyklen für das Skelett entwerfen und es für unterschiedliche Charaktere nutzen, indem man eine andere “Skin” anbringt. Für unterschiedlich gebaute Charaktere nutzt man eine skalierte Variante des Skeletts. Damit beim Charakter die Körperteile schlüssig miteinander verbunden sind, werden Vertizes an den Kontaktstellen miteinander “verschmolzen” (VertexSkinning). Das wird bewirkt, indem die Rand-Kontrollpunkte von benachbarten Patch-Oberflächen verbunden werden. Die aufgesetzten Oberflächen können sich so bei Gelenkbewegungen strecken oder kontraktieren und es entstehen keine Lücken oder Kanten zwischen Körperteilen. Abbildung 6.8: Skelett-Modell, mit und ohne Skin. - Quelle: vrlab.epfl.ch/ alegarcia 6.8 Kollisions-Erkennung Abbildung 6.9: Kollisionserkennung. Interpretation: Mitte: Kollisionen von BoundingSpheres; Rechts: Präzisierung der festgestellten Überlappung - Quelle: isg.cs.tcd.ie Auf das Thema will ich nur kurz eingehen, auf Ansätze und Einsatzgebiete hinweisen und Stichworte zur möglichen Vertiefung nennen. Kollisionserkennung beschäftigt sich damit, eingetretene, aber u.U. auch künftig eintretende Kollisionen bzw. Überlappungen von Objekten zu erkennen. 6.8. KOLLISIONS-ERKENNUNG 133 Häufig prüft man auf Kollisionen mit der Absicht, irgendwie darauf zu reagieren. Im einem einfachen Fall möchte man vielleicht das weitere Ineinander-Bewegen der Objekte verhindern, oder die Kollision in einem Shooter-Spiel als Treffer registrieren. In anderen Fällen könnte die Kollision genauer untersucht werden, um die Objekte voneinander apprallen zu lassen oder entsprechend der Krafteinwirkung zu deformieren. Das sind Beispiele aus der Simulation und Spiele-Welt - man könnte meinen, bei einer Animation, in der die Bewegungen selbst festgelegt werden, braucht man keine Kollisionserkennung. Aber auch hier gibt es Szenarien dafür. In vorigen Abschnitten wurden zunehmend abstraktere Methoden zur Beschreibung von Bewegungen angesprochen, bei denen der Rechner sich um die lästige Detail-Arbeit kümmert und die Animateure einen Teil der Kontrolle abgeben. Beispiele bei denen in einer Animation Kollisionen auftreten können sind • Kinematik: Ein IK-Solver sollte berücksichtigen, dass sich Teile eines Körpers nicht schneiden durfen. Für die Interpolation der Posen gilt das ebenso. • Partikel-Effekte: Sprühende Funken sollten nicht durch Gegenstände fliegen. • Physikalische Effekte an Personen: Anstatt einer steifen “Helm-Frisur” könnte eine Figur wehendes Haar haben, dessen Bewegung mit physikalischen Formeln erzeugt wird. Bei soviel Aufwand sollte man auch noch sicherstellen, dass die Haare nicht durch Gesicht und Schultern wehen. Es gibt einige Methoden, auf Kollisionen zu prüfen. Eine ganz exakter Test kann sehr rechenintensiv sein, deshalb gibt man sich häufig damit zufrieden, dass ein Test grob stimmt. Eine Methode, die Kollisionen immer korrekt erkennt, aber auch mal falsche Positive meldet ist meist akzeptabel. Ein sehr einfacher Ansatz ist der Bounding-Box Test: Zu jedem Objekt ermittelt man eine Kiste, die das Objekt umfasst, indem man vom Objekt die Minima und Maxima der X, Y und Z Koordinaten ermittelt. Mit dieser Box testet man dann auf Kollision: überlappen sich keine Boxen, können sich deren Inhalte auch nicht überlappen. Überlappen sich die Boxen, dann könnten sich die Objekte schneiden und man kann die Stelle, die in Frage kommt genauer testen. U.U. muss man es nicht so genau wissen. Wenn man mit Hierarchischen Modellen arbeitet, kann man Boxen für Einzelteile errechnen, die man von 2 Objekten prüft, wenn sich deren Boxen überlappen - so bekommt man weniger falsche Positive. Statt Bounding-Boxes können natürlich auch Bounding-Spheres genutzt werden: die sind leicht zu testen, umfassen aber Objekte i.d.R. weniger eng, als eine Box, 6.9. DEFORMATION 134 deren Dimensionen unterschiedlich sein können. Ein weiterer Ansatz ist, den Raum mittels Binary Space Partition Trees aufzuteilen in belegte Sektoren, die untersucht werden. Zu BSP, siehe die Ausarbeitung zu Ray-Tracing Für einfache geometrische Figuren (Linien, Ebenen, Kugeln, Würfel) sind Intersektionsformeln bekannt und für komplexe Modelle lassen sich ihre Einzelteile betrachten, sodass ein exakter Kollisionstest für ein Modell eine große Menge von einfachen Tests erfordert. Präzise Verfahren finden für Objekte eine (oder mehrere) konvexe Hüllen, deren Oberflächen-Ebenen gegen alle in Frage kommenden VertexVerbindungen auf einen Schnitt getestet werden. Um unnötiges Testen zu vermeiden bietet sich an, zuerst mit Bounding-Boxes /-Spheres zu schauen, ob eine Kollision überhaupt möglich ist. 6.9 6.9.1 Deformation Globale Deformation Abbildung 6.10: Populäre globale Deformationen - Quelle: [Wat93] Deformationen, die dadurch erreicht werden, dass alle Vertizes eines Modells durch eine Mathematische Funktion manipuliert werden, nennt man auch globale Deformationen. Man kann sich natürlich unendlich viele Funktionen ausdenken, aber es gibt ein paar Funktionen die so gängig sind, dass sie einen Namen haben. Die Funktionen werden einzeln auf jeden Vertex eines Modells angewandt und nutzen als Parameter nur die Vertex-Koordinaten und ggf. Parameter, die einmalig für die Funktionsanwendung festgelegt oder berechnet wurden. Mit sonstigen Parametern meine ich Werte, die die Deformation charakterisieren: z.B. Winkel und Position einer Biegung u.ä.. Gängige Deformationen: • Taper: Verschlankung der Form durch Skalierung 6.9. DEFORMATION 135 • Displace: Versetzen von Vertizes • Twist: Vertizes um eine Achse drehen • Bend: Vertizes werden (mithilfe einer Rotations-Funktion) verbogen. 6.9.2 Free Form Deformation Abbildung 6.11: Free-Form Deformation, simuliert - Quelle: www.medhfz.unibas.ch Die Globale Deformation baut auf einfache Mathematische Funktionen auf. Durch Parametrisierung der Funktionen und Kombinationen aus mehreren Deformationen lassen sich aufwändige Verformungen erreichen. Wenn wir eine ganz bestimmte Verformung erreichen wollen, mag es sein, dass sich die mit einer bestimmten Kombination elementaren Verformungen hinbekommen lässt, aber solche Lösungen kann man sich schwer spontan ausdenken. Angenehmer wäre eine Methode, bei der sich ein Objekt wie Knete formen lässt. Free-Form-Deformation ist eine Technik, die genau das realisiert: man kann frei an Objekten “herumkneten”, und mit geeignetem Feedback ein Modell interaktiv bearbeiten. Bei der FFD wird um ein Modell oder eines Teils davon, ein 3-dimensionales Gitter gedacht, das als eine Art Erzatz-Koordinatensystem dient. Die Punkte des Gitters sind Kontrollpunkte von parametrischen Kurven (z.B. Splines), die im Moment noch als gerade Linien durch das Gitter gehen. Die Vertizes des Modells, das verformt werden soll, werden relativ zu den Kontrollpunkten des Gitters berechnet. Dann wird verformt, indem die Kontrollpunkte des Gitters manipuliert werden. Nach der Manipulation des Gitters (d.h. sämlicher Splines, die zusammen das Gitter ausmachen), wird die neue Position der Modell-Vertizes entsprechend des verformten Gitters errechnet (Siehe 6.11). 6.10. GESICHTS-ANIMATION 6.9.3 136 Animierte Deformation Free-Form Deformationen sind nicht auf einmalige Verformungen beschränkt. Wir können ein sogenanntes “Deformation Tool” - so bezeichnet man das Tupel: (Gitter, Verformtes Gitter) - über Modelle streichen oder Modelle in und aus dem Einflussbereichs eines Verformers bewegen. Damit lassen sich einige Effekte erzielen: Z.B. könnten wir eine gedehnte Stelle entlang eines Schlauchs bewegen (vergleiche in etwa Abb. 6.12), eine Raupe animieren, einen Geist in eine Flasche quetschen oder einen Zerrspiegel simulieren. Abbildung 6.12: Deformation in Bewegung- Quelle [Wat93] Wenn wir die Kontrollpunkte eines Gitters selbst animieren, etwa indem wir sie durch eine zeitabhängige Funktion bewegen, werden neue Arten von Effekten denkbar. Lassen wir die Kontrollpunkte sich dezent konzentrisch kontraktieren und ausdehnen und platzieren das “Verformungs-Werkzeug” über den Oberkörper einer Figur, dann sieht das so aus, als würde die Figur ein- und ausatmen. Lassen wir die Kontrollpunkte hin und her, auf und ab schaukeln, können wir Wellen simulieren. Es ist schon auffällig, wie viel sich mit Kurven und Interpolation anstellen lässt. 6.10 Gesichts-Animation Bei der Animation von Charakteren ist das Skelett (siehe Skeletal Animation 6.7) wohl am bedeutendsten - seine Anordnung bestimmt das Aussehen einer Figur extrem. Was Muskeln und Sehnen machen, sticht nicht so ins Auge und meistens macht sich ihre Aktivität nur indirekt durch Bewegung des Skeletts bemerkbar. Gesichter sind anders: hier bewegen die Muskeln keine Knochen, sondern beeinflussen die Mimik. Die Mimik spielt eine grosse Rolle dabei, Charaktere authentisch wirken zu lassen. Deswegen wurden zur Animation von Gesichtern aufwändige Techniken entwickelt. Ein Gesicht wird, damit es sich gut animieren lässt, aus Patches modelliert (siehe Abb. 6.13) und hat eine Menge Kontroll-Punkte. Bei einer relativ einfachen Animations-Methode, wird eine überschaubare Anzahl signifikanter Gesichtsausdrücke modelliert. Sie unterscheiden sich, durch die Anordnung der Kontroll- 6.10. GESICHTS-ANIMATION 137 Punkte. Das Gesicht wird dann animiert, indem eine gewichtete Mischung aus den gewünschten Posen erzeugt wird: z.B. Könnten die Posen “Fröhlich” und “Skeptisch” zu gleichen Anteilen gemischt werden, indem man zwischen den Kontrol-Punkten der beiden Posen interpoliert. Die Qualität der Bewegungen hängt davon ab, Posen zu haben, deren Übergänge glaubwürdig aussehen. Bei diesem einfachen Ansatz würden wir einfach die Kontrollpunkte linear zwischen Posen interpolieren. Das ist beim Gesicht viel unproblematischer als bei Knochen- und Gelenk-Konstrukten, da Punkte des Gesichts praktisch keine Rotationen um andere Punkte durchmachen. aufwändigere Verfahren modellieren Muskeln (in Form von Splines oder Patches) nach, die sich auf Kontroll-Punkte des Gesichts in ihrer Umgebung auswirken. Das hat eine gewisse Ähnlichkeit zu den Free-Form-Deformations 6.9.2, aber die Kopplung der Kontroll-Punkte des Gesichts zu den Kontroll-Punkten der Muskeln ist i.d.R. aufwändiger realisiert als bei der FFD, weil das anatomische Vorbild nachempfunden wird. Das beginnt damit, dass Punkte die weniger direkt auf der Linie der Zugrichtung eines Muskels liegen, schwächer beeinflusst werden, und geht soweit, dass gezogene Kontroll-Punkte eine Gegenkraft ausüben, die sich wiederum auf ihre Nachbarpunkte auswirkt (Elastizität und Gewebeverdrängung). Mit letzterem Verfahren, bei dem die jeweiligen Mimik-Parameter einzeln geregelt werden können, lassen sich Gesichter sehr flexibel animieren. Siehe Abbildung 6.13 Abbildung 6.13: Links: Gesichts-Modellierung ausgehend von einer Zeichnung - Quelle: Web/unbekannt; Rechts: Parametrisierte Mimik bei Nvidias Dawn Demo Kapitel 7 Image-Based Rendering Selimkhan Achmerzaev 7.1 Einleitung Die meisten 3D Techniken, die wir bis jetzt kennen gelernt haben, versuchen 3D-Szenen und Objekte so realistisch wie möglich zu gestalten. Dabei kommen verschiedene Techniken zum Einsatz: Unter anderem realistische Modelle (z.B. Vortrag über Splines und Nurbs von Jacqueline Spexard), Texturen (GPU, Christoph Sackl), Reflexionen und Beleuchtung (Raytraycing, Tobias Pfeiffer). Bei Image-Based Rendering (IBR), auf der anderen Seite, werden reale Bilder und reale Szenen benutzt, um diese in die 3D-Welt zu übertragen. Dies kann in vielen Fällen sehr hilfreich sein. Wenn man aus einem oder mehreren 2D Bildern ein Objekt (bzw. eine gesamte Szene) der realen Welt schnell und realistisch als ein 3D-Modell (3D-Szene) realisieren kann, kann es einiges an Modellierungsarbeit, Beleuchtung und Texturierung ersparen. Die Komplexität der Szene spielt hierbei auch keine Rolle. Mit Hilfe von Image-Based Modeling (IBM) und Image-Based Rendering (IBR) ist es möglich, dreidimensionale Szenen auf Basis von zweidimensionalen Bildern zu erstellen. Bei den zugrunde liegenden Bildern kann es sich entweder um Fotografien der realen Welt handeln, oder um bereits vorberechnete Bilder. Dies geschieht, indem man versucht, in den Quellbildern die Struktur, Beschaffenheit, Raumwirkung und Beleuchtung zu erkennen. Die so gewonnene Information wird 138 7.1. EINLEITUNG 139 dann in die 3D Welt übertragen und es können neue Bilder erzeugt werden. Ein weiteres Verfahren, welches reale Bilder in die 3D-Welt einbindet, ist Image-Based Lighting (IBL). Image-Based Lighting erlaubt es, reale Bilder als Lichtquellen zu benutzen und somit eine sehr realistische globale Beleuchtung einer Szene zu realisieren. Diese Ausarbeitung wird zwei Image-Based Modelling and Rendering Verfahren (IBMR) kurz vorstellen: • - Light Field und View Interpolation als Teil von Image Based Modelling und Rendering und ein Image-Based Lighting Verfahren (IBL): • - Globale Beleuchtung mit Hochkontrastbildern Der Leser soll am Ende eine übersichtliche Vorstellung dieser Techniken haben. Es werden viele Bilder zum Einsatz kommen und Bezüge zur praktischen Anwendung dieser Techniken vorgestellt. Es gibt unterschiedliche Methoden von Image Based Modelling: solche, die ohne Geometrie (z.B. Light Field Rendering), mit impliziter Geometrie (View Interpolation) oder expliziter Geometrie rendern[HS00]. Das Grundprinzip hinter diesen Verfahren ist es den Lichtfluss, also die Bewegung der Lichtstrahlen in der Szene, parametrisieren und festhalten zu können (plenoptische Funktion). Wie das genau geschieht, wird beim Light Field Rendering Verfahren vorgestellt. Vorausetzung für die IBMR-Verfahren ist jedoch, dass die benutzten Quellbilder zusammenhängend sind, dieselbe Szene repräsentieren und möglichst aus derselben Richtung und unter gleichen Lichtbedingungen aufgenommen wurden. Ansonsten kann es zu Fehlern und Missinterpretationen kommen. 7.2. LIGHT FIELD 7.2 140 Light Field Light Field Rendering [LH96] ist eines der Image Based Rendering Verfahren. Mit Hilfe von Light Fields ist man in der Lage, durch Aufnahmen eines realen, digitalisierten oder synthetischen Objekts, neue Ansichten von diesem Objekt zu generieren. Dabei werden viele Bilder des Objekts benötigt, aber keine Information über die Geometrie der Szene. Um zu verstehen, wie das realisiert wird, sollte das Konzept der Plenoptischen Funktion erklärt werden, da diese Funktion alle visuellen Eigenschaften einer Szene definiert. In der Computergrafik wird Licht häufig als Strahl (eng: Ray) betrachtet. Die Menge des Lichtes, welches durch diesen Strahl wandert, nennt man Strahldichte (engl.: radiance). Die Plenoptische Funktion (vorgestellt durch Adelson und Bergen [AB91]) beschreibt die Intensität von Lichtstrahlen an jedem Punkt (Vx , Vy , Vz ), unter jedem möglichen Winkel(θ, φ). P = (Vx , Vy , Vz , θ, φ) (7.1) Da wir davon ausgehen können, dass zwischen der Kamera und dem Objekt ein freier Raum ist (nur Luft), wodurch sich die Wellenlänge des Lichtes nicht verändert, da der Lichtstrahl keinen weiteren Objekte trifft, kann man die plenoptische Funktion auf vier Faktoren reduzieren, wodurch wir eine 4D Funktion erhalten. Die Farbe eines Lichtstrahls, im freien Raum, bleibt auf ihrem Weg konstant. Um diesen Lichtstrahl parametrisieren zu können, reichen zwei parallele Ebenen, die sich zwischen dem Objekt und der Kamera befinden und eine konvexe Hülle bilden (Abbildung 7.1). L(u, v, s, t) (7.2) Dabei stehen u und v für die Koordinatenachsen einer Ebene und s,t für die Koordinatenachsen der anderen Ebene. Die beiden Ebenen werden als: (u,v)-Ebene (Objektebene) und (s,t)-Ebene (Kameraebene) bezeichnet. Sie haben eine feste Entfernung zu einander und der Lichtstrahl bewegt sich durch die beiden Ebenen. In der Praxis wird die Breite und die Höehe der beiden Ebenen festgelegt. Dadurch kann man die Lage des Lichtstrahls parametrisieren, da die Koordinaten, an denen der Lichtstrahl die beiden Ebenen schneidet, bekannt sind. Diese Darstellung wird auch als ’light slab’ - 7.2. LIGHT FIELD 141 Abbildung 7.1: Darstellung von einem Light Slab. Aus [LH96] Darstellung bezeichnet. Abbildung 7.2: links: ein Light Slab; rechts: vier Light Slabs aus vier verschiedenen Richtungen 7.2.1 Sampling Als weiterer Schritt erfolgt das Sampling (Abtastung). Dabei sollte man sich vorstellen, als platziere man eine Kamera in einem Punkt in der (s,t)-Ebene und würde jeden Punkt in der (u,v)-Ebene damit aufnehmen, wodurch wir das Light Field von diesem Punkt aus hätten. Die dadurch gewonnenen 2D-Bilder könnte man wiederum in die 4D-Funktion L(s,t,u,v) einsetzen. Dies könnten wir von jedem Punkt aus auf der (s,t)-Ebene machen. Somit wäre das Einfügen dieser Bilder in L unser Light Field. Das Extrahieren von 2D Bildern aus dieser 4D-Funktion ermöglicht es neue Bilder aus neuen Perspektiven zu bekommen, indem die Nachbarsamples interpoliert werden. 7.2. LIGHT FIELD 142 Außerdem kann man sowohl von jedem Punkt auf der (s,t)-Ebene alle Punkte der (u,v)-Ebene aufnehmen, aber auch von allen Punkten in der (s,t)-Ebene einen bestimmten Punkt in der (u,v)-Ebene. (siehe Abbildung 7.3) Desweiteren können auch spezielle 4D-Filter (z.B. 4D-Tiefpassfilter [LH96]) Abbildung 7.3: Oben: Erfassung eines Punktes in der (s,t)-Ebene, durch jeden Punkt in der (u,v)-Ebene Unten: Erfassung jedes Punktes in der (s,t)-Ebene, aus einem Punkt in der (u,v)-Ebene zum Einsatz kommen, um Aliasing zu vermeiden und einen besseren Übergang zwischen benachbarten Light Fields zu erzielen. 7.2.2 Technische Probleme Prinzipiell ist es nicht möglich, unendlich viele Bilder (bzw. unendlich viele Samples) aus verschiedenen Perspektiven aufzunehmen. Dies wäre mit einem sehr hohen Aufwand verbunden. Zudem würde sich eine sehr große Datenmenge ansammeln. Aus diesem Grund ist man gezwungen, möglichst wenige Samples zu verwenden. Gewöhnlich wird die (s,t)-Ebene in MxM Quadrate (meist 32x32 Punkte) und die (u,v)-Ebene in NxN Quadrate(256x256) aufgeteilt. Man sollte bedenken, dass man selbst bei dieser Menge an Samples, auf etwa 1GB Daten kommt, wenn man mit 24-Bit pro Pixel das Objekt von allen sechs Seiten aufnimmt. Um die Datenmenge gering zu halten, kommen spezielle Kompressionsmethoden zum Einsatz. Dabei werde die anfallenden großen Datemengen komprimiert gespeichert. Eins dieser Kompressionsverfahren ist eine zweistufige Pipeline bestehend aus Vektorquantisierung mit fester Bitrate und anschließender Entropiekodierung mit dem Lempel-Ziv-Algorithmus, die eine Verarbeitung in Echtzeit ermöglicht (Aus 7.2. LIGHT FIELD 143 ”Light Field Rendering”von M.Levoy, P.Hanraham. [LH96]). Ein weiteres Problem stellt die Bewegung und die Positionierung der Kamera dar. Die Kamera muss für jeden Sample korrekt positioniert werden, denn sonst wären die Bilder ungenau, unscharf, verschwommen und unregelmässig voneinander entfernt. 7.2.3 Resampling / Erzeugen von neuen Bildern Anhand der gewonnenen Samples ist man nun in der Lage, neue Bilder aus anderen Blickrichtungen zu generieren. Zunächst wird die Position der Kamera festgelegt. Danach werden die (s,t)- und (u,v)-Ebenen für unsere Bildstrahlen ermittelt und die Samples extrahiert, die am nähsten zu dieser neuen Blickrichtung liegen. Anschließend werden diese ”resampled”, wobei eine Interpolation der benachbarten Samples bzw. Farbwerte stattfindet, um ein bestmögliches Ergebnis zu erzielen. Abbildung 7.4 zeigt zwei Beispielbilder, die durch Light Fields erzeugt wurden. Abbildung 7.4: beide Bilder gerendert mit Light Fields anhand von samples [LH96] 7.2.4 Zusammenfassung Light Field Rendering ermöglicht anhand vorhandener Bilder realistische Szenen mit realistischer Beleuchtung unter neuen Blickwinkeln in kurzer Zeit zu erzeugen. Mit heutiger Hardware ist das Generieren von Light Fields in Echtzeit möglich. 7.3. VIEW INTERPOLATION 144 Man sollte jedoch nicht vergessen, dass es auch gewisse Schwierigkeiten mit sich bringt, so z.B.: • - Hohe Anzahl an Samples für besseres Endergebnis (grosse Datenmengen notwendig) • - Genaue Positionierung der Kamera erfordert Automatisierung • - Statische Beleuchtung notwendig 7.3 View Interpolation Unter View Interpolation versteht man ein Verfahren, bei dem man mindestens zwei Referenzbilder einer Szene benutzt, um neue Bilder zu erzeugen. Gewöhnlich entstehen diese neuen Bilder aus einer Perspektive, die zwischen den beiden Referenzbildern liegt und werden durch das Interpolieren der Referenzbilder erzeugt. Abbildung 7.5: Das mittlere Bild wird anhand der beiden Referenzbilder interpoliert Das Verfahren, welches hier vorgestellt wird ist auf Chen und Williams (1993) ”View Interpolation for Image Synthesis” zurückzuführen[CW98]. Bei diesem Verfahren wird die Kamera im 2D Raum, parallel zu einer statischen Szene, bewegt und es werden mindestens zwei Quellbilder aufgenommen, anhand derer später neue Zwischenbilder erstellt werden sollen. Im Vergleich zu Light Field Rendering, wird bei View Interpolation implizitet Geometrie verwendet. Um eine Interpolation eines neuen Bildes aus zwei vorhandenen Bildern zu erreichen, sollten die beiden Eingabebilder nah aneinander aufgenommen sein, so dass es eine gewisse Überlappung gibt und man Punkte oder Geometrie eines, der beiden Bilder, im anderen wiederfindet. 7.3. VIEW INTERPOLATION 145 Das bedeutet, dass man Ähnlichkeiten und Korrespondenz in den beiden Bildern benötigt. Anhand dieser Ähnlichkeiten werden die Quellbilder ”gemorpht” und wenn nötig Fehler, die in dem neuen künstlichen Bild entstanden sein könnten, entfernt. Das Morphen von Bildern kommt in verschiedenen Bildbearbeitungsanwendungen vor. Bei dieser Bildverarbeitungstechnik können ein oder mehrere Motive miteinander verflochten und durch Veränderung von Betrachtungsparametern in ein anderes Motiv verwandelt werden. Verfahrensmäßig werden beim Morphing die Attribute zweier Objekte aufeinander abgestimmt. Die Zwischenobjekte werden über die Interpolation der Quellobjekte erstellt, wobei ein stufenloser Übergang das Ziel ist. Abbildung 7.6: Image Morphing. links - Original, rechts - Spiegelung, mitte - Morphed Image 7.3.1 Pixel Interpolation Mit vorgegebenem Bewegungsfeld, d.h. wenn die Bewegung der Kamera bekannt ist, und mindestens zwei benachbarte Quellbilder vorliegen, ist es möglich, die korrespondierenden Pixel aus einem der Quellbilder im anderen wiederzufinden (Abbildung 7.7). Da sich bei einer Kamerabewegung, die Objekte, welche sich näher an der Kamera befinden, schneller in die entgegengesetzte Richtung bewegen, als die im Hintergrund, kann eine relative 3D-Position jedes Pixels bzw. Objekts festgehalten werden. Auf diese Weise wird die Pixelkorrespondenz zwischen den Pixeln auf den beiden Quellbildern mit Hilfe einer Transformationsmatrix berechnet. Es wird 7.3. VIEW INTERPOLATION 146 Abbildung 7.7: Pixel Interpolation. Links und rechts sind die beiden Quellbilder und in der Mitte das interpolierte Zwischenbild. Bewegung der Kamera ist von links unten nach rechts oben. außerdem eine so genannte ”morph map”(”Bewegungskarte”) für jeden Pixel in den Quellbildern erstellt, welche die Bewegungsvektoren speichert. Beim Generieren des gewünschten Zwischenbildes anhand von zwei Quellbildern, werden die Bewegungsvektoren jedes Pixels der beiden Quellbilder linear interpoliert und somit die neue Position des Pixels im Zwischenbild berechnet. 7.3.2 Probleme Beim Interpolieren der beiden Ansichten muss man bedenken, dass gewisse Stellen der Szene durch andere Objekte verdeckt sein könnten und das neue Zwischenbild womöglich Lücken aufweist, da diese individuelle Stelle des Bildes in keinem der Quellbilder zu erkennen ist. Abbildung 7.8 verdeutlicht dieses Szenario. Diese Lücken sind Bereiche, die nicht von den Quellbildern festgehalten wurden und interpoliert werden müssen. Je näher die Quellbilder aneinander sind, umso besser ist das Zwischenbild (siehe Abschnitt 7.3.4). Abbildung 7.8: Die dunkleren Stellen sind in keinem der Quellbilder A und B zu sehen, jedoch in dem Zwischenbild M 7.3. VIEW INTERPOLATION 7.3.3 147 Lösung Eine der Lösungen dieses Problems ist z.B. das Übermalen dieser Lücken mit derselben Farbe der benachbarten Pixel. Dabei werden die Lücken zuerst mit der Farbe der Pixel, die eher im Hintergrund sind (geometrisch betrachtet weiter entfernt von der Kamera), übermalt und dann mit der Farbe der Pixel, die sich weiter vorne (näher an der Kamera) befinden. Falls man, anhand vorher gewonnener Information, die Geometrie der Szene ersehen kann (z.B. mit Hilfe der Bewegungsvektoren), wird ein besseres Ergebniss beim Übermalen erzielt, da keine Farbe der Objekte aus dem Hintergrund plötzlich im Vordergrund auftreten kann. Als Regel gilt - je mehr Quellbilder vorliegen und je kleiner der Abstand zwischen den Quellbildern, um so weniger Lücken entstehen und umso genauer kann das Übermalen dieser Lücken sein. 7.3.4 Beispiele Abbildung 7.9 verdeutlicht das Problem der Lücken (blaue Bereiche im Bild). In Abbildung 7.10 sieht man, wie das Entstehen von größeren Lücken vermieden wird (indem die Quellbilder sehr nah aneinander aufgenommen werden) und wie das interpolierte Endbild aussieht. Abbildung 7.9: Lücken, die entstehen, wenn man die Kamera nach rechts dreht Abbildung 7.10: (a) Lücken bei nur einem Quellbild; (b) bei zwei Quellbildern; (c) bei zwei Quellbildern, die sehr nah an einander aufgenommen wurden; (d) Lücken durch Interpolieren gefüllt 7.3. VIEW INTERPOLATION 7.3.5 148 Beipiel aus der Filmindustrie View Interpolation, View Morphing (ähnlich wie View Interpolation) und Image Morphing sind recht leistungsstarke Verfahren, um realistische Zwischenbilder anhand von vorhandenen realen Bildern zu erstellen. Schon heute werden diese Verfahren z.B. in der Filmindustrie erfolgreich angewendet, wie beispielsweise in dem Film ’The Matrix’[Sil03]. Der Bullet-Time Effekt wird realisiert, indem man viele einzelne Kameras um die Szene herum aufstellt, die sehr nah aneinander in einem Kreis oder Halbkreis angeordnet sind. Die Kameras nehmen, entweder zeitlich versetzt oder alle gleichzeitig, Bilder der Szene auf. Anschließend werden alle diese benachbarten Bilder interpoliert und man erhält einen weichen Übergang. Dabei entsteht der Effekt, als sei die Zeit in diesem Moment angehalten worden und eine Kamera bewege sich sehr schnell um die Szene herum. Abbildung 7.11: Die schwarzen Punkte im linken Bild sind einzelne Kameras. 7.3.6 Zusammenfassung View Interpolation ist ein einfaches Verfahren, um neue Zwischenbilder anhand von vorhandenen Bildern zu generieren, ohne einen grossen technischen Aufwand investieren zu müssen. Die erforderliche Datenmenge kann zwischen zwei einzelnen Bildern, bis zu n Bildern variieren, je nach dem wie gut das Endergebniss sein soll. Die Geometrie der Szene wird implizit einbezogen (bei Light Field Rendering keine Geometrieinformation notwendig). Je näher die Quellbilder aneinander sind, um so besser sieht das interpolierte Zwischenbild aus. Es können immernoch leicht verschwommene Stellen entstehen, wenn grössere Lücken übermalt werden müssen. Es ist vorteilhafter, wenn die Szene statisch ist und eine feste, statische Beleuchtung hat, weil dadurch weniger Missinterpretationen bei der Interpolation entstehen können. Es sollte noch erwähnt werden, dass man bei View Interpolation auch andere 7.4. IMAGE BASED LIGHTING MIT HIGH DYNAMIC RANGE IMAGES 149 Verfahren benutzt, um Tiefenunterschiede zu bestimmen, unter anderem Depth Fields [DML+ 99] und Stereobilder der Szene. Anhand dieser Bilder kann man erkennen, welche Teile der Szene näher an der Kamera sind und welche weiter im Hintergrund liegen und somit ein besseres Ergebniss beim Übermalen der Lücken erreichen (siehe Abbildung 7.12). Abbildung 7.12: Stereobild, Tiefenwirkung anhand von zwei Quellbildern [DML+ 99] 7.4 Image Based Lighting mit High Dynamic Range Images Image Based Lighting (IBL) [Deb02] ist ein Verfahren, bei dem eine reale oder synthetische Szene (bzw. ein 3D Objekt) realistisch beleuchtet wird. Realisiert wird dies mit Hilfe von Bildern des Lichtes, welche in der realen Welt aufgenommen wurden. Im Gegensatz zu bisherigen Verfahren (Radiosity, Raytraycing) findet hier keine physikalische Simulation statt. IBL erlaubt es künstlich erstellte, dreidimensionale Objekte und Szenen in Bilder der realen Welt realistisch einzubinden und schafft sehr realistische Reflexionen. Bei IBL kommen High-Dynamic-Range-Bilder (HDR-Bilder) zum Einsatz. HDR-Bilder sind Hochkontrastbilder einer realen Szene, die wesentlich mehr Information beinhalten, als nur eine Farbe pro Pixel. In der Computergrafik steht ”Dynamic Range”(Dynamikumfang) für den Quotienten aus größtem und kleinstem Helligkeitswert eines digitalen Bildes. 7.4. IMAGE BASED LIGHTING MIT HIGH DYNAMIC RANGE IMAGES 150 Vorgestellt wurde ”high dynamic range imaging”von Greg Ward [WAR94] und später weiterentwickelt von Paul Debevec [DM97], der als einer der führenden Entwickler auf diesem Gebiet gilt. Das menschliche Auge kann höhere Kontrastwerte wahrnehmen, als die gängigen Monitore darstellen können (Auge etwa 1:1 000 000, Monitor: 1:10 000 oder weniger). Die meisten uns bekannten Bildformate, wie z.B. JPEG, werden als LDR-Bilder bezeichnet (Low-dynamic-range-image). Die Unterscheidung, ob ein Bild ein LDR-Bild oder HDR-Bild ist, ist von den Bits pro Pixel abhängig. Die meisten LDR-Bildern sind 8-Bit-Bilder (aber auch 16-Bit). Das bedeutet, dass für jeden Farbkanal 8 Bits zu Verfügung stehen, also insgesamt 24 Bit für jeden Pixel für alle drei Farben (RGB). Solche LDR-Bilder repräsentieren nur einen Bruchteil des Dynamikumfangs (Dynamikumfang der Helligkeitswerte). Wenn eine Szene zu hell ist, werden die entsprechenden Pixel nur auf ihren Maximalwert gesättigt (in unserem Fall 255 bei 8 Bit), unabhängig davon wie hell die reale Szene tatsächlich ist. Bei HDR-Bildern werden 32 Bit für jeden Farbkanal verwendet (insgesamt 96 Bit pro Pixel). Die Farben werden mit Fließkommazahlen kodiert, wodurch sehr hohe Werte darstellbar sind (bei 32 Bit sind es über 4 Milliarden). Eine weitere Eigenschaft von HDR-Bildern ist es, dass die Pixelwerte linear 7.4. IMAGE BASED LIGHTING MIT HIGH DYNAMIC RANGE IMAGES 151 proportional zu der Lichtmenge der realen Welt sind. Einige HDR-Bildformate sind z.B. Radiance RGBE (.hdr) oder OpenEXR (.exr). [HDR07b] Um HDR-Bilder aufzunehmen, werden mehrere Bilder derselben Szene unter verschiedenen Belichtungsreihen aufgenommen um alle Helligkeitsbereiche abzudecken. Die Belichtungsreihe erstreckt sich von einer extremen Unterbelichtung bis hin zu einer extremen Überbelichtung. Abbildung 7.13: Unterschiedliche Belichtungsreihen Abbildung 7.14: Vergleich zwischen einem LDR- und einem HDR-Bild bei 1/32 Helligkeitsabnahme. In Abbildung 7.13 sieht man links 8 Bilder einer Szene, die unter verschiedenen Belichtungsreihen aufgenommen wurden. Mit Hilfe dieser 8 Bilder sehen wir rechts die Lichtintensität an jedem Punkt dieser Szene (blau: sehr wenig, rot: sehr helle Stellen) Abbildung 7.14 verdeutlicht den Unterschied zwischen einem LDR-Bild und einem HDR-Bild. Bei einer 1/32 Helligkeitsabnahme wirkt das HDR-Bild immernoch realistisch, da man immernoch einen guten Kontrast zwischen den hellen Fenstern und dem Rest des Raumes erkennt, was beim LDR-Bild nicht der Fall ist. 7.4. IMAGE BASED LIGHTING MIT HIGH DYNAMIC RANGE IMAGES 152 7.4.1 Light Probes Light Probe Bilder sind omnidirektionale (in jede Richtung im Raum), HighDynamic-Range-Bilder, die die Information über die einfallende Beleuchtung an einem bestimmten Punkt im Raum beinhalten. Neben der Eigenschaft omnidirektional zu sein, gibt es für jede Richtung des Raumes einen korrespondierenden Pixel in der Light Probe [Deb02]. Des Weiteren ist in jedem dieser Pixel die Information über die Lichtintensität und die Lichtmenge gespeichert. Abbildung 7.15: Einige Light Probes. Light Probe Image Gallery www.debevec.org Es gibt mehrere Möglichkeiten omnidirektionale Bilder der Umgebung aufzunehmen. Eine Möglichkeit ist es, eine verchromte Kugel auf einem Stativ im Raum zu platzieren und diese Kugel mit einer Kamera aufzunehmen. Damit erfasst man fast die komplette Umgebung. Weitere Methoden sind z.B. mit Hilfe einer Panoramakamera oder ”Fischaugekamera”. Man kann auch Bilder in jede Richtung der Umgebung aufnehmen und diese dann später zusammenfügen. Bei der Aufnahme mit Hilfe einer spiegelnden Kugel werden in der Regel mehrere Bilder dieser Kugel aufgenommen. Gewöhnlich nimmt man zwei Bilder unter einem Winkel von 90◦ auf. Das ermöglicht die Kamera und den Fotografen in der Mitte der Kugel zu übermalen, so dass diese im Bild nicht zu sehen sind. Die Reflexionen an den Rändern dieser Kugel weisen jedoch leichte Verzerrungen und Streckungen auf [HDR07a]. Es ist möglich seine eigenen Light Probes zu erstellen. Dafür gibt es einige Software Lösungen, um normale Bilder in .hdr Bilder umzuwandeln (Bsp. HDRShop http://www.ict.usc.edu/graphics/HDRShop/), aber man findet auch genug fertige Light Probes im Internet (Bsp. http://www.debevec.org/Research/HDR), die man direkt mit den meisten gängigen 3D-Programmen benutzen kann (Bsp. 3dsmax, Maya, Cinema4D). 7.4. IMAGE BASED LIGHTING MIT HIGH DYNAMIC RANGE IMAGES 153 Abbildung 7.16: Aufnahme der Umgebung mit einer Kugel und ein Fishauge-Objektiv 7.4.2 Environment Mapping Die eigentliche 3D-Szene wird entweder mit einer riesigen Kugel (Sphere) oder einem Quader (Cube) übersehen, die quasi unendlich weit entfernt sind. Auf diese Sphere , bzw. Cube wird dann das HDR-Bild projiziert. Das Motiv auf dem HDR-Bild wird somit zur Environment Map (Umgebungsbild), welche sich in den Objekten der Szene widerspiegelt. Dadurch wirkt die Szene, vor allem spiegelnde Objekte wie Metall oder Glas, besonders realistisch. Da das Cube Mapping als Verbesserung von Spherical Mapping entwickelt wurde, hat es in manchen Fällen Vorteile, da es beim letzteren teilweise zu Unkorrektheiten kommen kann. Der Grund dafür ist, dass bei Spherical Mapping eine Light Probe von einer spiegelnden Kugel verwendet wird und, wie oben schon erwähnt, sind die Ränder dieser Kugel gestreckt und verzerrt, wodurch die Reflexionen in den Objekten der Szene manchmal unkorrekt oder verschwommen wirken können. [HDR07a] Abbildung 7.17: Spherical und Cubical Environment Mapping 7.4. IMAGE BASED LIGHTING MIT HIGH DYNAMIC RANGE IMAGES 154 7.4.3 Beispiele Die folgenden Beispiele sollen die Vorteile und den Photorealismus, den man mit Hilfe von IBL und HDRI erreicht, verdeutlichen. In der folgenden Szene habe ich fünf verschiedene Kugeln platziert und mit unterschiedlichen Texturen und Materialen übersehen. Die Kugeln sind aus unterschiedlichen Glasstrukturen, Metall und Spiegel. Abbildung 7.18: links: ambiente Standardbeleuchtung; rechts: globale Beleuchtung(Raytracing) In Abbildung 7.18 (links) wurde eine Standardbeleuchtung benutzt (ambiente Beleuchtung der Szene mit einer festen Lichtquelle). Das ist der Grund für das künstliche Aussehen. Ausserdem ist es schwer die Materialbeschaffenheit der rechten beiden Kugeln zu erkennen. Das Bild rechts (Abbildung 7.18) wurde mit Hilfe von globalen Beleuchtung (hier:Raytraycing) erstellt. Die Szene wirkt realistischer, jedoch fehlen mehr Reflexionen der Umgebung und die Beleuchtung ist überall monoton und gleichmäßig. Die Bilder in Abbildung 7.19 wurden mit unterschiedlichen Light Probes gerendert. Es sind viele Überstrahlungen und sehr helle Stellen an den gläsernen Kugeln zu sehen. Die Reflexionen der Umgebung verleihen den Bildern einen starken photorealistischen Effekt und man kann deutlicher erkennen aus welchen Materialien die Kugeln sind. Auch wenn es den Eindruck erweckt, als seien die Bilder unter grossem Berechnungsaufwand und längeren Renderzeiten entstanden, benötigt man mit heutigen Mittelklasserechnern (X2 4200+, 2GB RAM, DirectX 9 Grafikkarte) für so ein Bild etwa 2-4 Minuten Renderzeit bei einer Auflösung von 640x480 Pixeln. 7.4. IMAGE BASED LIGHTING MIT HIGH DYNAMIC RANGE IMAGES 155 Abbildung 7.19: Renderings mit 4 verschiedenen HDRImages Ein weiteres Beispiel ist in Abbildung 7.20 zu sehen. 7.4.4 Einsatz von IBL in der Industrie Image Based Lighting kommt in verschiedenen Bereichen zum Einsatz: in Industrial Design, Filmindustrie. In der Videospielindustrie wird zur Zeit nur HDR-Rendering benutzt. Die Möglichkeit ein synthetisches Objekt in eine reale Szene einzubinden, damit es realistisch in dieser Szene wirkt, erlaubt es einiges an Kosten zu ersparen. So kann man neue Produkte modellieren und sie in eine reale Szene übertragen. Das kann besonders bei Bauunternehmen, oder bei größeren Fahrzeugprototypen, Materialkosten ersparen. Auch in der Filmindustrie (siehe Spider Man 2 und The Matrix Trilogy) werden realistische Szenen mit Hilfe von IBL umgesetzt. 7.4. IMAGE BASED LIGHTING MIT HIGH DYNAMIC RANGE IMAGES 156 Abbildung 7.20: links: Standardbeleuchtungsmodell, rechts: dasselbe Objekt (selbe Material) aber mit IBL Abbildung 7.21: Das Spiel Far Cry mit und ohne HDR Rendering 7.4.5 Zusammenfassung IBL ist ein leistungsstarkes Verfahren, welches sehr realistische Beleuchtung und Reflexionen schafft. Es findet schon heute in vielen Bereichen der Industrie Verwendung. Mit Hilfe von HDRI-Technik und IBL kann man 3D-Szenen in die reale Welt überführen und ein künstliches 3D-Objekt in eine reale Szene einbinden. IBL ist so gut wie in jedem gängigen 3D-Grafikprogramm vorhanden und HDRBilder lassen sich mit geringem Aufwand erstellen. Somit ist diese Technik allen zugänglich und leicht zu realisieren (schon ab DX7-Schnittstelle möglich). Es wird vermutlich auch weiterhin entwickelt und verbessert und schon bald verbreitete Verwendung auch in der Videospielindustrie finden. Schon heute gibt es Möglichkeiten IBL in Echtzeit zu realisieren ( Masaki Kawase, rthdribl v.1.2 (DirectX9), Real-Time High Dynamic Range Image-Based Lighting ). Literaturverzeichnis [AB91] Edward H. Adelson and James R. Bergen. The plenoptic function and the elements of early vision. Computational Models of Visual Processing, pages 3–20, 1991. [AK89] James Arvo and David Kirk. A survey of ray tracing acceleration techniques. In Andrew Glassner, editor, An Introduction to Ray Tracing. Academic Press Ltd, 1989. [Coo89] Robert L. Cook. Stochastic sampling and distributed ray tracing. In Andrew Glassner, editor, An Introduction to Ray Tracing. Academic Press Ltd, 1989. [CW98] Shenchang Eric Chen and Lance Williams. View interpolation for image synthesis. SIGGRAPH 1998, pages 381–390, 1998. [dB93] Mark de Berg. Ray Shooting, Depth Orders and Hidden Surface Removal. Springer-Verlag, 1993. [Deb02] Paul E. Debevec. A tutorial on image-based lighting. In IEEE Computer Graphics and Applications, 2002. [DG05] Stefan Turek Dominik Goddeke, Robert Strzodka. Double precision on gpus, 2005. http://numod.ins.uni-bonn.de/research/ papers/public/GoStTu05double.pdf. [DM97] Paul E. Debevec and Jitendra Malik. Recovering high dynamic range radiance maps from photographs. In SIGGRAPH ’97: Proceedings of the 24th annual conference on Computer graphics and interactive techniques, pages 369–378, New York, NY, USA, 1997. ACM Press. [DML+ 99] Paul E. Debevec, M.Cohen, L.McMillan, C.Bregler, R.Szeliski, and F. Sillion. Image-based modeling, rendering, and lighting. Course Notes for Course #39 at SIGGRAPH 1999. SIGGRAPH 1999, 1999. [DSC93] Heiko Duin, Günter Symanzik, and Ute Claussen. Beleuchtungsalgorithmen in der Computergrafik. Springer-Verlag, 1993. 157 LITERATURVERZEICHNIS 158 [FK03] Randima Fernando and Mark J. Kilgard. The Cg Tutorial. Addison Wesley, 2003. [Fou06a] OpenGL Foundation. Opengl specifications 2.1, 2006. http://www.opengl.org/documentation/specs/ version2.1/glspec21.pdf. [Fou06b] OpenGL Foundation. Opengl specifications 2.1, 2006. http://www.opengl.org/documentation/specs/ version2.1/glspec21.pdf Page 90 ff. [Fou07] GPGPU Foundation. Gpgpu, 2007. http://www.gpgpu.org. [Gib07] Steve Gibson. How subpixel font rendering works, [Stand: 16.11.2007]. http://www.grc.com/ctwhat.htm. [Gla89] Andrew S. Glassner. Surface physics for ray tracing. In Andrew Glassner, editor, An Introduction to Ray Tracing. Academic Press Ltd, 1989. [Hai89] Eric Haines. Essential ray tracing algorithms. In Andrew Glassner, editor, An Introduction to Ray Tracing. Academic Press Ltd, 1989. [Han89] Pat Hanrahan. A survey of ray-surface intersection algorithms. In Andrew Glassner, editor, An Introduction to Ray Tracing. Academic Press Ltd, 1989. [HB97] Ronald Hearn and Pauline Baker. Ch3: Output primitives. In Computer Graphics, C Version Second Edition, Upper Saddle River, New Jersey, 1997. Prentice Hall. [HDR07a] HDRShop. Creating a light probe, 2007. http://gl.ict.usc. edu/HDRShop/tutorial/tutorial5.html. [HDR07b] HDRSoft. Faq - hdr images for photography, 2007. http://www. hdrsoft.com/resources/dri.html. [HS00] H.Shum and S.B.Kang. A review of image-based rendering techniques. In Microsoft Research, 2000. [Inc07] Ziff Davis Media Inc. 3d pipelining, 2007. http: //www.extremetech.com/article2/0,1697,1155159, 00.asp. [Ins07] National Instruments. Pci express - an overview of the pci express standard, 2007. http://zone.ni.com/devzone/cda/tut/ p/id/3767. LITERATURVERZEICHNIS 159 [Kom07] Elektronik Kompendium. Grafikkarte, 2007. http: //www.elektronik-kompendium.de/sites/com/ 0506191.htm. [LH96] Marc Levoy and Pat Hanrahan. Light field rendering. In SIGGRAPH ’96: Proceedings of the 23rd annual conference on Computer graphics and interactive techniques, pages 31–42, New York, NY, USA, 1996. ACM Press. [Mic07] Microsoft. Microsoft typography, [Stand: 16.11.2007]. http://www. microsoft.com/typography/default.mspx. [MPS07] Andrew Moss, Dan Page, and Nigel Smart. Toward acceleration of rsa using 3d graphics hardware. In Cryptography and Coding, pages 369–388. Springer-Verlag LNCS 4887, December 2007. [nVi06a] nVidia. Nvidia geforce 8800 architecture technical brief, 2006. http: //www.nvidia.com/object/IO_37100.html. [nVi06b] nVidia. Nvidia geforce 8800 architecture technical brief, 2006. http: //www.nvidia.com/object/IO_37100.html. [nVi07] nVidia. Compute unified device architecture, 2007. developer.nvidia.com/object/cuda.html. [PR] POV-Ray. Pov-ray hall of fame. http://de.wikipedia.org/ wiki/Raytracing. Stand: 11.11.2007. [Pyg07] Pygame. Grafik-apis im Überblick, 2007. http://www.pygame. de/news/grafik-apis-im-uberblick/. [Shi05] Peter Shirley. Fundamentals of Computer Graphics. A K Peters, 2005. [Sil03] Steve Silberman. Matrix2, 2003. http://www.wired.com/ wired/archive/11.05/matrix2_pr.html. [TB94] Spencer W. Thomas and Rod G. Bogart. Ii.3: Color dithering. In Graphics Gem 2, University of Michigan Ann Arbor, Michigan, 1994. Academic Press. [Uni07] Stanford University. Folding@home, 2007. http://folding. stanford.edu/. [uotad99] The university of texas at dallas. Hazards, 1999. http://www. utdallas.edu/˜cantrell/ee2310/s1hazard.pdf. [WAR94] G. J. WARD. Real pixels. In Graphics Gems IV. Academic Press, Boston, 1994. http:// LITERATURVERZEICHNIS 160 [Wat93] Alan Watt. 3D Computer Graphics. Addison-Wesley, 1993. [Wik] Wikipedia. Raytracing. http://de.wikipedia.org/wiki/ Raytracing. Stand: 11.11.2007. [Wik07a] Wikipedia. Comparison of nvidia graphics processing units, 2007. http://en.wikipedia.org/wiki/Comparison_ of_NVIDIA_Graphics_Processing_Units. [Wik07b] Wikipedia. Grafikkarte, 2007. http://de.wikipedia.org/ wiki/Grafikkarte. [Wyv93] Brian Wyvill. 2d rendering. In Graphics Gem 1, University of Calgary Alberta, Canada, 1993. Elsevier LTD, Oxford.