Integration von 3D-Visualisierungstechniken in 2D-Grafiksystemen
Integration von 3D-Visualisierungstechniken in 2D-Grafiksystemen
Integration von 3D-Visualisierungstechniken in 2D-Grafiksystemen
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Bachelorarbeit im Rahmen des Studiengangs<br />
Scientific Programm<strong>in</strong>g<br />
Fachhochschule Aachen, Campus Jülich<br />
Fachbereich 9 – Mediz<strong>in</strong>technik und Technomathematik<br />
<strong>Integration</strong> <strong>von</strong> <strong>3D</strong>-<strong>Visualisierungstechniken</strong><br />
<strong>in</strong> <strong>2D</strong>-<strong>Grafiksystemen</strong><br />
Jülich, den 15. August 2012<br />
Florian Rhiem
Erklärung<br />
Diese Arbeit ist <strong>von</strong> mir selbstständig angefertigt und verfasst. Es s<strong>in</strong>d ke<strong>in</strong>e anderen<br />
als die angegebenen Quellen und Hilfsmittel verwendet worden.<br />
Sie wurde im Peter Grünberg Institut/Jülich Centre for Neutron Science – Technische<br />
und Adm<strong>in</strong>istrative Infrastruktur – Wissenschaftliche IT-Systeme der Forschungszentrum<br />
Jülich GmbH konzipiert.<br />
Unterschrift<br />
Diese Arbeit wurde betreut <strong>von</strong>:<br />
1. Prüfer: Prof. Dr. rer. nat. Karl Ziemons<br />
2. Prüfer: Josef He<strong>in</strong>en
Wissenschaftler am Peter Grünberg Institut/Jülich Centre for Neutron Science untersuchen<br />
<strong>in</strong> Experimenten und Simulationen Form und Dynamik <strong>von</strong> Materialen wie<br />
Polymeren, Zusammenlagerungen großer Moleküle und biologischen Zellen sowie die<br />
elektronischen Eigenschaften <strong>von</strong> Festkörpern. Für die Präsentation der <strong>in</strong> diesem<br />
Zusammenhang anfallenden Forschungsergebnisse <strong>in</strong> Vorträgen und Verö entlichungen<br />
werden häufig Darstellungen <strong>von</strong> Kristall- und Molekülstrukturen <strong>in</strong> höchster<br />
Qualität benötigt.<br />
Basierend auf der <strong>in</strong> e<strong>in</strong>er Sem<strong>in</strong>ararbeit erstellten O screen Render<strong>in</strong>g-Bibliothek<br />
(GLor) zur <strong>Integration</strong> OpenGL-basierter <strong>3D</strong>-Grafiken <strong>in</strong> <strong>2D</strong>-Grafikwerkzeuge und<br />
Anwendungsschnittstellen soll die dafür entwickelte Schnittstelle im Rahmen dieser<br />
Bachelorarbeit erweitert und <strong>in</strong> vorhandene Visualisierungsprogramme <strong>in</strong>tegriert werden.<br />
Dabei ist zunächst e<strong>in</strong> Verfahren zu entwickeln, welches die Möglichkeiten konventioneller<br />
<strong>2D</strong>-Grafik und <strong>in</strong>teraktiver <strong>3D</strong>-Systeme vere<strong>in</strong>t.<br />
Anschließend ist dieses Verfahren <strong>in</strong> zwei Programmsystemen konkret umzusetzen:<br />
Zum e<strong>in</strong>en soll die am PGI/JCNS entwickelte GR-Visualisierungbibliothek um<br />
die neuen <strong>3D</strong>-Funktionen erweitert werden, zum anderen soll e<strong>in</strong>e Anwendung zur<br />
Darstellung <strong>von</strong> Molekülstrukturen (Moldyn) refaktoriert und um die Möglichkeit<br />
der Visualisierung <strong>von</strong> Elektronensp<strong>in</strong>s erweitert werden. Im Zuge dieser Umstellung<br />
sollen die Ausgabemöglichkeiten der Bibliothek zudem um <strong>in</strong>teraktiv nutzbare<br />
<strong>3D</strong>-Anzeigefenster und alternative Ausgabeformate, wie JavaScript-basierte WebGL-<br />
Skripte oder Szenenbeschreibungen für e<strong>in</strong> Raytrac<strong>in</strong>g-Programm (POV-Ray), ergänzt<br />
werden.
Inhaltsverzeichnis<br />
1. Motivation 1<br />
2. Grundlagen 2<br />
2.1. <strong>2D</strong>-Grafiksysteme ............................. 2<br />
2.1.1. Das Graphische Kernsystem und die GR-Bibliothek ...... 2<br />
2.2. <strong>3D</strong>-<strong>Visualisierungstechniken</strong> ....................... 3<br />
2.2.1. Szenen im dreidimensionalen Raum ............... 3<br />
2.2.2. OpenGL .............................. 4<br />
2.2.3. HMTL5/JavaScript und WebGL ................. 4<br />
2.2.4. Persistence of Vision Raytracer (POV-Ray) .......... 5<br />
3. Realisierung 7<br />
3.1. Konzept der Bibliothek .......................... 7<br />
3.1.1. Die Bibliothek GR3 <strong>in</strong> der Grafik<strong>in</strong>frastruktur ......... 7<br />
3.1.2. Entwurf der Schnittstelle ..................... 9<br />
3.1.2.1. Allgeme<strong>in</strong>e Funktionen ................. 9<br />
3.1.2.2. Szenenbeschreibungsfunktionen ............ 9<br />
3.1.2.3. Funktionen zum Zeichnen und Export der Szene ... 9<br />
3.2. Statische Ausgabe der Szene ....................... 12<br />
3.2.1. POV-Ray Szenenbeschreibung .................. 12<br />
3.2.2. Rasterisierung <strong>in</strong> OpenGL .................... 16<br />
3.2.2.1. Der OpenGL-Kontext ................. 16<br />
3.2.2.2. Render<strong>in</strong>g mit Framebu er Objekten ......... 18<br />
3.2.2.3. Erstellung <strong>von</strong> Rastergrafiken mit OpenGL ..... 18<br />
3.2.2.4. Erstellung <strong>von</strong> Grafiken <strong>in</strong> hohen Auflösungen .... 21<br />
3.2.2.5. Kantenglättung mit Supersampl<strong>in</strong>g Antialias<strong>in</strong>g ... 22<br />
3.2.3. HTML5-Dokument mit e<strong>in</strong>em <strong>in</strong>teraktiven WebGL-Canvas .. 24<br />
3.3. Grafikanzeige zur Laufzeit ........................ 27<br />
3.3.1. Zeichnen <strong>von</strong> Pixmaps mit der GR-Bibliothek ......... 28<br />
3.3.2. <strong>Integration</strong> <strong>in</strong> OpenGL-Anwendungen .............. 29<br />
3.4. Erstellung e<strong>in</strong>er Anb<strong>in</strong>dung für Python ................. 29<br />
4. Ergebnisse 31<br />
4.1. Benutzung der Schnittstelle ....................... 31<br />
4.1.1. E<strong>in</strong> e<strong>in</strong>faches Beispiel: Visualisierung dreier Kugeln ...... 31<br />
4.1.2. E<strong>in</strong> komplexes Beispiel: E<strong>in</strong>e Funktion als <strong>3D</strong>-Fläche ..... 33<br />
i
Inhaltsverzeichnis<br />
4.2. Moldyn – E<strong>in</strong> Anwendungsbeispiel ................... 35<br />
4.2.1. Erstellung und Verwaltung des Anzeigefensters ......... 37<br />
4.2.2. Aufbau e<strong>in</strong>er Szene aus den Moleküldaten ........... 38<br />
4.2.3. Darstellung der Moleküle zur Laufzeit .............. 41<br />
4.2.4. Export <strong>in</strong> Ausgabedateien .................... 43<br />
4.2.5. Zusammenfassung der <strong>Integration</strong> <strong>von</strong> GR3 <strong>in</strong> MolDyn .... 44<br />
4.3. Verwendung des Python-Wrappers ................... 45<br />
5. Ausblick 46<br />
Literaturverzeichnis 48<br />
Anhang 51<br />
A. Funktionsreferenz 53<br />
A.1. Allgeme<strong>in</strong>e Funktionen .......................... 53<br />
A.2. Szenenbeschreibungsfunktionen ..................... 54<br />
A.3. Export- und Zeichenfunktionen ..................... 60<br />
B. Codebeispiele 63<br />
B.1. Visualisierung dreier Kugeln ....................... 63<br />
B.2. E<strong>in</strong>e Funktion als <strong>3D</strong>-Fläche ....................... 64<br />
ii
Abbildungsverzeichnis<br />
2.1. Pr<strong>in</strong>zip e<strong>in</strong>es Raytracers ......................... 6<br />
3.1. GR3 <strong>in</strong> der Grafik<strong>in</strong>frastruktur ..................... 8<br />
3.2. Vere<strong>in</strong>fachte Darstellung der verschiedenen Ausgabemöglichkeiten .. 10<br />
3.3. Die <strong>von</strong> POV-Ray gerenderte Szene ................... 14<br />
3.4. Erstellung e<strong>in</strong>er Rastergrafik mit GR3 und POV-Ray ......... 15<br />
3.5. Die OpenGL Core Profile Pipel<strong>in</strong>e[17, S. 11][15, S. 7] .......... 17<br />
3.6. Die w<strong>in</strong>kelabhängige Intensität des reflektierten Lichts nach dem Lambert’schen<br />
Kos<strong>in</strong>usgesetz ......................... 19<br />
3.7. Skizze e<strong>in</strong>es symmetrischen Pyramidenstumpfes mit Unterteilungen<br />
(Schnitt entlang der y-z-Ebene) ..................... 21<br />
3.8. Supersampl<strong>in</strong>g Antialias<strong>in</strong>g ....................... 23<br />
3.9. E<strong>in</strong>e mit WebGL dargestellte Szene ................... 25<br />
3.10. Das Koord<strong>in</strong>atensystem des Browsers (schwarz), das aktuelle Koord<strong>in</strong>atensystem<br />
der Kamera (rot), die Änderung der Mausposition und<br />
die daraus berechnete Rotationsachse (blau) .............. 26<br />
3.11. Zeichenbereich <strong>von</strong> gr3_drawimage im Anwendungsfenster ...... 27<br />
3.12. GKS-Fenster (X11-Treiber) mit <strong>2D</strong>- und <strong>3D</strong>-Inhalten ......... 28<br />
4.1. Die erzeugte Grafik ............................ 32<br />
4.2. Die Funktion f(x, y) = s<strong>in</strong>( 4<br />
9x2 )+ y2<br />
für x, y œ [≠5; 5] ......... 9<br />
4.3. E<strong>in</strong> Ge-Sb-Te-Phasenwechselmaterial <strong>in</strong> Moldyn (ohne GR3) .....<br />
35<br />
36<br />
4.4. E<strong>in</strong> Punkt (r,„,◊) <strong>in</strong> Kugelkoord<strong>in</strong>aten ................. 41<br />
4.5. E<strong>in</strong> Ge-Sb-Te-Phasenwechselmaterial <strong>in</strong> Moldyn (mit GR3) ...... 43<br />
iii
List<strong>in</strong>gverzeichnis<br />
iv<br />
3.1. Funktionen zum Setzen der Qualität und Export <strong>in</strong> e<strong>in</strong>e Datei .... 10<br />
3.2. Funktion zum Auslesen e<strong>in</strong>er Pixmap .................. 10<br />
3.3. Zwei mögliche Signaturen e<strong>in</strong>er Funktion zum Zeichnen <strong>in</strong> e<strong>in</strong> beliebiges<br />
Ziel mit beliebigen Optionen ....................... 11<br />
3.4. Funktion zum Zeichnen <strong>in</strong> e<strong>in</strong> beliebiges Ziel mit festgelegten Optionen 12<br />
3.5. E<strong>in</strong>e Szenenbeschreibungsdatei für POV-Ray (Teil 1) ......... 12<br />
3.6. E<strong>in</strong>e Szenenbeschreibungsdatei für POV-Ray (Teil 2, gekürzt) .... 13<br />
3.7. E<strong>in</strong> Beispiel für e<strong>in</strong>en mesh-Block .................... 14<br />
3.8. Verwenden e<strong>in</strong>es bestehenden OpenGL-Kontextes mit CGL, GLX und<br />
WGL .................................... 16<br />
3.9. E<strong>in</strong> GLSL 1.2 Vertex-Shader für e<strong>in</strong>e Lambert’sche Oberfläche (di use<br />
Beleuchtung) ............................... 19<br />
3.10. E<strong>in</strong> GLSL 1.2 Fragment-Shader ..................... 20<br />
3.11. Vertex Bu er Objekte <strong>in</strong> C ........................ 24<br />
3.12. Vertex Bu er Objekte <strong>in</strong> JavaScript ................... 24<br />
3.13. IDL-Beschreibung 6 des canvas-Elements ................ 24<br />
3.14. Funktion zum Zeichnen <strong>in</strong> e<strong>in</strong> beliebiges Ziel mit festgelegten Optionen 27<br />
3.15. Funktion zum Zeichnen e<strong>in</strong>er Rastergrafik mit GR ........... 28<br />
3.16. Python-Wrapper für gr3_setquality mit ctypes ........... 30<br />
4.1. Initialisierung und Freigabe <strong>von</strong> GR3 .................. 31<br />
4.2. Setzen <strong>von</strong> globalen Eigenschaften .................... 32<br />
4.3. H<strong>in</strong>zufügen <strong>von</strong> Kugeln zur Szene .................... 32<br />
4.4. Exportieren der Szene <strong>in</strong> e<strong>in</strong>e PNG-Datei ................<br />
4.5. f(x, y),<br />
32<br />
ˆf ˆf<br />
, , e<strong>in</strong>e Funktion zur Normalisierung <strong>von</strong> Vektoren und<br />
ˆx ˆy<br />
e<strong>in</strong>e Funktion zur Transformation der Intervalle [0; 100] für x und [0;10]<br />
für y auf [-5;5] ............................... 33<br />
4.6. Darstellung e<strong>in</strong>er Funktion als Dreiecksgitter .............. 34<br />
4.7. Exportieren der Szene <strong>in</strong> e<strong>in</strong> HTML5-Dokument ............ 35<br />
4.8. Erstellen des Anzeigefensters und Setzen der Callback-Funktionen .. 37<br />
4.9. H<strong>in</strong>zufügen der Atome zur Szene .................... 38<br />
4.10. H<strong>in</strong>zufügen der Atomb<strong>in</strong>dungen zur Szene (Teil 1) ........... 40<br />
4.11. H<strong>in</strong>zufügen der Atomb<strong>in</strong>dungen zur Szene (Teil 2) ........... 40<br />
4.12. Umrechnen des Koord<strong>in</strong>atensystems der Kamera ............ 42<br />
4.13. Zeichnen der Szene ............................ 42<br />
4.14. Export der Szene <strong>in</strong> e<strong>in</strong>e Datei ...................... 44
List<strong>in</strong>gverzeichnis<br />
4.15. Beispiel 1 <strong>in</strong> Python ........................... 45<br />
B.1. Darstellung <strong>von</strong> drei Kugeln mit GR3 .................. 63<br />
B.2. <strong>3D</strong>-Plot der Funktion f(x, y) =cos(0.66x) · s<strong>in</strong>(0.2y) ......... 65<br />
v
1. Motivation<br />
E<strong>in</strong> perspektivisch gezeichnetes Bild, e<strong>in</strong>e Animation am Computerbildschirm, e<strong>in</strong><br />
Film im <strong>3D</strong>-K<strong>in</strong>o, e<strong>in</strong> Hologramm: die <strong>3D</strong>-Visualisierung hat viele Formen und die<br />
Schnittmenge liegt <strong>in</strong> den Inhalten, die dargestellt werden können. Dabei ist die<br />
Spannweite der verschiedenen Inhalte – <strong>von</strong> Mess- oder Simulationsdaten bis zu präzisen<br />
Entwürfen <strong>von</strong> Masch<strong>in</strong>enteilen – genau so groß, wie die Möglichkeiten ihrer<br />
Darstellung. Die Visualisierung <strong>von</strong> dreidimensionalen Inhalten macht diese meist<br />
e<strong>in</strong>facher verständlich.<br />
An e<strong>in</strong>em normalen Arbeitsplatzrechner kann man heute verschiedene solche Darstellungen<br />
erzeugen: Statische Rastergrafiken auf der e<strong>in</strong>en und aus vielen E<strong>in</strong>zelbildern<br />
bestehende, dynamische und <strong>in</strong>teraktive Inhalte auf der anderen Seite. Auch<br />
Vektorgrafiken oder genormte Szenenbeschreibungen, die zur Anzeige erst <strong>in</strong> Rastergrafiken<br />
umgewandelt werden müssen, s<strong>in</strong>d möglich. Um dies zu erreichen gibt es<br />
Programme und Bibliotheken, die verschiedene Ansätze verfolgen um e<strong>in</strong>e bestimmte<br />
Form der Ausgabe zu erzeugen. Die Schnittstellen s<strong>in</strong>d dabei meist sehr komplex<br />
gestaltet, um die Ausgabe den eigenen Wünschen entsprechend genau anpassen zu<br />
können oder die Performance zu erhöhen.<br />
Mit dieser hohen Komplexität können zwar zunehmend realistischere Grafiken <strong>in</strong><br />
Echtzeit erstellt werden, doch die Benutzung dieser Systeme setzt e<strong>in</strong>e zeit<strong>in</strong>tensive<br />
E<strong>in</strong>arbeitung voraus und sie s<strong>in</strong>d üblicherweise auf wenige Ausgabemedien spezialisiert.<br />
Im wissenschaftlichen Umfeld ist es allerd<strong>in</strong>gs oft das Ziel, die Daten zu<br />
visualisieren ohne Fotorealismus anzustreben. Deshalb ist e<strong>in</strong>e e<strong>in</strong>fache Schnittstelle<br />
s<strong>in</strong>nvoller, die verschiedene Möglichkeiten der Ausgabe bietet.<br />
Das Ziel dieser Arbeit ist daher die Entwicklung e<strong>in</strong>er Bibliothek, die mit e<strong>in</strong>er e<strong>in</strong>heitlichen,<br />
e<strong>in</strong>fach gestalteten Schnittstelle die Möglichkeit bietet, dreidimensionale<br />
Inhalte zu visualisieren und die so erzeugten <strong>3D</strong>-Grafiken <strong>in</strong> mehreren Ausgabeformaten<br />
zu exportieren. Sie soll <strong>in</strong>sbesondere <strong>in</strong> <strong>2D</strong>-Grafiksysteme <strong>in</strong>tegrierbar se<strong>in</strong>, so<br />
dass bestehende Anwendungen um statische oder dynamische <strong>3D</strong>-Grafiken erweitert<br />
werden können.<br />
1
2. Grundlagen<br />
2.1. <strong>2D</strong>-Grafiksysteme<br />
2.1.1. Das Graphische Kernsystem und die GR-Bibliothek<br />
Das Graphische Kernsystem (GKS) ist e<strong>in</strong>e standardisierte Schnittstelle für die Erstellung<br />
<strong>von</strong> <strong>2D</strong>-Vektorgrafiken. Durch die Abstraktion der Ausgabemedien und e<strong>in</strong>e<br />
auf grafische Primitiven e<strong>in</strong>geschränkte Funktionalität bietet das GKS die Möglichkeit<br />
Zeichenbefehle unabhängig <strong>von</strong> der späteren Anzeige zu gestalten und dennoch<br />
e<strong>in</strong>e sehr hohe Qualität zu erzielen. Die vom GKS unterstützten grafischen Primitiven<br />
s<strong>in</strong>d[1][3, Abschnitt 2.1]:<br />
• L<strong>in</strong>ienzüge (Polyl<strong>in</strong>es)<br />
• Symbole, z. B. Kreise oder Sterne (Polymarker)<br />
• E<strong>in</strong>farbig gefüllte oder schra erte Flächen (Fill Area)<br />
• Schrift (Text)<br />
• Farbmatrizen (Cell Array)<br />
Im Gegensatz zu e<strong>in</strong>igen anderen funktionalen ISO-Standards gibt es zum GKS ke<strong>in</strong>e<br />
o zielle Referenzimplementierung. Statt dessen gibt es mehrere Implementierungen,<br />
<strong>in</strong> welchen die Plattformunabhängigkeit über zwei verschiedene Schichten realisiert<br />
wird. E<strong>in</strong>e obere Schicht ist vollkommen plattformunabhängig und erfüllt die vom<br />
Standard vorgegebene Schnittstelle. Diese gibt über e<strong>in</strong>e zweite, implementierungsabhängige<br />
Schnittstelle die Zeichenbefehle an e<strong>in</strong> oder mehrere logische Gerätetreiber<br />
weiter. E<strong>in</strong> solcher Treiber realisiert die geräteabhängigen Zeichenoperationen für e<strong>in</strong><br />
Ausgabemedium, e<strong>in</strong>e sogenannte GKS-Workstation 1 [1].<br />
Solche Gerätetreiber gibt es für sehr verschiedene Arten der Anzeige, wie beispielsweise<br />
für verschiedene Toolkits für grafische Benutzeroberflächen (z. B. Qt4), als Web<br />
Frontend, aber auch für Dateiformate wie Scalable Vector Graphics (SVG) oder das<br />
Portable Document Format (PDF).<br />
Da das GKS nur grundlegende Möglichkeiten der Grafik def<strong>in</strong>iert, wie beispielsweise<br />
L<strong>in</strong>ien oder Texte, wurden darauf aufbauende Systeme entwickelt. Die im ehemaligen<br />
Institut für Festkörperforschung 2 entwickelte GR-Bibliothek ermöglicht auch die<br />
2<br />
1 Dieses Konzept wird auch device-<strong>in</strong>dependent device-dependent genannt.<br />
2 Heute: Peter Grünberg Institut (PGI) und Jülich Centre for Neutron Science (JCNS)
2.2. <strong>3D</strong>-<strong>Visualisierungstechniken</strong><br />
Erstellung komplexer grafischer Elemente und wird <strong>in</strong> Visualisierungs- und Analyseanwendungen<br />
e<strong>in</strong>gesetzt.<br />
Zu der erweiterten Funktionalität <strong>von</strong> GR zählen unter anderem:<br />
• Transformationen<br />
• Koord<strong>in</strong>atenachsen und -gitter<br />
• Fehlerbalken<br />
• Spl<strong>in</strong>e-Funktionen<br />
Intern verwendet GR nur die Anweisungen des GKS, daher werden weder Qualität<br />
noch Ausgabearten e<strong>in</strong>geschränkt. Die GR-Bibliothek ist <strong>in</strong> der Programmiersprache<br />
C geschrieben, neben der C Schnittstelle kann sie allerd<strong>in</strong>gs auch aus anderen<br />
Programmiersprachen wie Python oder Fortran verwendet werden.<br />
2.2. <strong>3D</strong>-<strong>Visualisierungstechniken</strong><br />
Da im Rahmen dieser Arbeit <strong>3D</strong>-Grafiken <strong>in</strong> <strong>2D</strong>-Grafiksysteme wie das GKS <strong>in</strong>tegriert<br />
werden sollen, werden <strong>in</strong> diesem Abschnitt e<strong>in</strong>ige Ansätze und Techniken zur <strong>3D</strong>-<br />
Visualisierung vorgestellt. So wie im Bereich der <strong>2D</strong>-Grafik zwischen Vektorgrafiken<br />
und Rastergrafiken unterschieden werden kann, gibt es im Bereich der <strong>3D</strong>-Grafik e<strong>in</strong>e<br />
ähnliche Unterscheidung: Neben dreidimensionalen Vektorgrafiken, <strong>in</strong> welchen Körper<br />
durch ihre Oberflächen beschrieben werden können, gibt es auch Volumengrafiken, die<br />
gitterförmig im Raum angeordneten Punkten e<strong>in</strong>e Dichte oder ähnliches zuordnen.<br />
Diese Arbeit beschäftigt sich ausschließlich mit der Visualisierung <strong>von</strong> Vektorgrafiken.<br />
2.2.1. Szenen im dreidimensionalen Raum<br />
Mit den im Folgenden vorgestellten <strong>Visualisierungstechniken</strong> sollen <strong>3D</strong>-Szenen darstellbar<br />
werden. Die Beschreibung dieser Szenen durch den Anwendungsentwickler<br />
wird den Hauptteil se<strong>in</strong>er Interaktion mit der Bibliothek darstellen. Daher soll geklärt<br />
werden, woraus e<strong>in</strong>e solche Szene besteht. Der <strong>in</strong> dieser Arbeit verwendete Begri der<br />
„Szene“ beschreibt:<br />
1. e<strong>in</strong>e Konstellation <strong>von</strong> Objekten im dreidimensionalen Raum,<br />
2. den sichtbaren Ausschnitt des Raums und<br />
3. die Beleuchtung der Objekte.<br />
Dabei haben Objekte verschiedene Eigenschaften, nämlich Position, Orientierung, sowie<br />
die Form, Normalen und Farbe der Oberfläche.<br />
3
Kapitel 2. Grundlagen<br />
2.2.2. OpenGL<br />
Die Open Graphics Library (OpenGL) ist die Spezifikation e<strong>in</strong>er Software-Schnittstelle<br />
zur Grafikhardware[16, Abschnitt 1.2]. Die Grafikhardware wird so weit abstrahiert,<br />
dass e<strong>in</strong>e allgeme<strong>in</strong>e, plattformunabhängige Schnittstelle genutzt werden<br />
kann. Diese Abstraktionsebene ist noch immer hardwarenah genug, um e<strong>in</strong> e zientes<br />
Erzeugen <strong>von</strong> <strong>3D</strong>-Grafiken <strong>in</strong> Echtzeit zu erreichen.<br />
OpenGL-Implementierungen s<strong>in</strong>d auf den meisten Arbeitsplatzrechnern vorhanden.<br />
Unter Microsoft W<strong>in</strong>dows ist allerd<strong>in</strong>gs die Installation e<strong>in</strong>es (proprietären) Grafikkartentreibers<br />
sehr wichtig, da die ansonsten auf diesem System vorhandene Implementierung<br />
nur der Version 1.1 des OpenGL-Standards entspricht 3 . Falls ke<strong>in</strong>e Hardwarebeschleunigung<br />
vorhanden ist, können sogenannte Software-Renderer, re<strong>in</strong> auf<br />
dem Hauptprozessor arbeitende OpenGL-Implementierungen, genutzt werden. Diese<br />
s<strong>in</strong>d natürlich deutlich weniger leistungsfähig als Implementierungen, welche e<strong>in</strong>e<br />
Grafikkarte verwenden.<br />
Die OpenGL-API bietet zwei verschiedene Ansätze zum „Zeichnen“:<br />
• Die traditionelle Methode ist die Fixed Function Pipel<strong>in</strong>e, <strong>in</strong> der man die Art<br />
der Projektion, Beleuchtung, etc. durch Variablen kontrolliert. Wie die e<strong>in</strong>zelnen<br />
Schritte, <strong>von</strong> e<strong>in</strong>er aus Primitiven (Punkt, L<strong>in</strong>ie, Dreieck) bestehenden E<strong>in</strong>gabe<br />
zur fertigen Grafik, ablaufen, ist dabei fest im Treiber implementiert.<br />
• Bei dem „modernen“ Ansatz wird e<strong>in</strong>e Shader-basierte Pipel<strong>in</strong>e verwendet, d. h.<br />
e<strong>in</strong> Teil der Schritte (z. B. Transformation oder E<strong>in</strong>färben <strong>von</strong> Pixeln) wird<br />
durch kle<strong>in</strong>e, vom Anwendungsentwickler geschriebene Programme, die sogenannten<br />
Shader-Programme, auf der Grafikhardware ausgeführt.<br />
Die Erzeugung <strong>von</strong> Grafiken erfolgt <strong>in</strong> OpenGL nach dem Pr<strong>in</strong>zip der Rasterisierung,<br />
d. h. die Objekte der Szene werden als e<strong>in</strong>e Art Vektorgrafik an die Implementierung<br />
übergeben und dort <strong>in</strong> e<strong>in</strong>e Rastergrafik umgewandelt. Dabei wird mit e<strong>in</strong>em Tiefenpu<br />
er, e<strong>in</strong>em Speicherbereich <strong>in</strong> dem für jeden Pixel e<strong>in</strong> Tiefenwert gespeichert<br />
wird, sicher gestellt, dass im dreidimensionalen Raum näher an der Kamera liegende<br />
Punkte weiter entfernte Punkte verdecken.<br />
Die Spezifikation wird durch e<strong>in</strong> Non-Profit-Industriekonsortium <strong>von</strong> Mitgliedern<br />
wie Nvidia, AMD und Intel, der Khronos Group[5], verwaltet und weiter entwickelt.<br />
Die aktuelle Version wird auf der Webseite http://www.opengl.org/registry/ verö<br />
entlicht.<br />
2.2.3. HMTL5/JavaScript und WebGL<br />
E<strong>in</strong>e noch relativ neue Entwicklung im Bereich der <strong>3D</strong>-Visualisierung ist die WebGL-<br />
API. Der ebenfalls <strong>von</strong> der Khronos Group entwickelte Web-Standard ermöglicht<br />
e<strong>in</strong> plattformunabhängiges, hardwarebeschleunigtes Rendern <strong>von</strong> <strong>3D</strong>-Grafik im Webbrowser.<br />
Das auf OpenGL ES 2.0 basierende WebGL stellt e<strong>in</strong>en sehr großen Teil<br />
4<br />
3 Version 1.1 wurde 1997 verö entlicht; aktuell s<strong>in</strong>d die Versionen 3.3 und 4.3
2.2. <strong>3D</strong>-<strong>Visualisierungstechniken</strong><br />
der Funktionalität <strong>von</strong> OpenGL über e<strong>in</strong>e JavaScript-Schnittstelle zur Verfügung, sodass<br />
auch komplizierte, <strong>in</strong>teraktive <strong>3D</strong>-Grafiken <strong>in</strong> e<strong>in</strong>e Webseite e<strong>in</strong>gebunden werden<br />
können.<br />
Bis zu dieser Erweiterung des Browserumfangs um e<strong>in</strong>e <strong>3D</strong>-Grafik-API konnte<br />
über Umwege, beispielsweise mit JOGL über das Java Plug-In, <strong>3D</strong>-Grafik erstellt<br />
werden. Die Benutzung <strong>von</strong> WebGL kann jedoch direkt als Teil der Webseite erfolgen<br />
und benötigt somit ke<strong>in</strong>e zusätzlichen Plug-Ins oder externe Bibliotheken[6].<br />
Mit Hilfe des Event-Systems <strong>von</strong> JavaScript können diese <strong>3D</strong>-Grafiken auf Benutzere<strong>in</strong>gaben,<br />
wie Mausbewegungen oder -klicks, reagieren. E<strong>in</strong>er solchen Webseite<br />
liegt die Beschreibungssprache HTML5 zu Grunde, e<strong>in</strong>e neue Version der Hypertext<br />
Markup Language, die Webanwendungsentwicklern unter anderem zusätzliche<br />
Multimedia-Schnittstellen 4 zur Verfügung stellt. Die Entwicklung und Standardisierung<br />
<strong>von</strong> HTML5 bei der WHATWG 5 und dem W3C 6 ist zum aktuellen Zeitpunkt<br />
noch nicht abgeschlossen. Der aktuelle Stand der Spezifikation <strong>von</strong> HTML5 wird unter<br />
http://www.w3.org/TR/html5/ verö entlicht.<br />
Da mehrere Browser 7 bereits HTML5 und WebGL unterstützen, würde e<strong>in</strong> HTML-<br />
Dokument als Ausgabe die Möglichkeit darstellen, die zu visualisierende Szene als e<strong>in</strong>e<br />
Art „<strong>in</strong>teraktiven Screenshot“ im World Wide Web zu verö entlichen, den Dritte<br />
betrachten können ohne sich e<strong>in</strong> zusätzliches Programm zu <strong>in</strong>stallieren.<br />
2.2.4. Persistence of Vision Raytracer (POV-Ray)<br />
E<strong>in</strong>en vollkommen anderen Ansatz zur Erzeugung <strong>von</strong> Rastergrafiken aus <strong>3D</strong>-Inhalten<br />
verfolgen sogenannte Raytrac<strong>in</strong>gverfahren (siehe Abbildung 2.1). Anstelle der hardwarebeschleunigten<br />
Rasterisierung wird beim Raytrac<strong>in</strong>g, zu deutsch (Licht-)„Strahlverfolgung“,<br />
die Farbe jedes Pixels bestimmt, <strong>in</strong> dem der Weg, dem e<strong>in</strong> Lichtstrahl<br />
<strong>von</strong> e<strong>in</strong>er Lichtquelle hätte folgen müssen um dieses Pixel zu erreichen, nachverfolgt<br />
wird. Dabei wird der Weg vom Pixel, beziehungsweise der Kamera, aus so lange verfolgt,<br />
bis der Strahl e<strong>in</strong>e Objektoberfläche schneidet. Von diesem Punkt aus werden,<br />
abhängig <strong>von</strong> verschiedenen Materialeigenschaften der Oberfläche, e<strong>in</strong> oder mehrere<br />
Lichtstrahlen unter Berücksichtigung <strong>von</strong> Reflektion, Refraktion und sonstigen optischen<br />
Phänomenen verfolgt.<br />
Dieser Ansatz ermöglicht e<strong>in</strong>en hohen Grad an Realismus, da Schatten, Lichtbrechung<br />
und Spiegelungen sehr gut dargestellt werden können, während Rasterisierer<br />
wie OpenGL diese E ekte nur aufwändig simulieren können. Da Raytracer meist nicht<br />
hardwarebeschleunigt s<strong>in</strong>d, sondern alle<strong>in</strong> auf dem Hauptprozessor arbeiten und die<br />
rekursive Verfolgung der Lichtstrahlen aufwendig ist, dauert das Erstellen e<strong>in</strong>es e<strong>in</strong>zelnen<br />
Bildes jedoch auch deutlich länger als e<strong>in</strong> vergleichbares Bild <strong>in</strong> OpenGL.<br />
Raytrac<strong>in</strong>gverfahren eignen sich daher besonders zur Erzeugung <strong>von</strong> E<strong>in</strong>zelbildern,<br />
nicht jedoch für Animationen <strong>in</strong> Echtzeit.<br />
4 z. B. Audio und Video [4, Abschnitt 4.8]<br />
5 Web Hypertext Application Technology Work<strong>in</strong>g Group<br />
6 World Wide Web Consortium<br />
7 z. B. Mozilla Firefox und Google Chrome [11]<br />
5
Kapitel 2. Grundlagen<br />
Kamera<br />
Strahlen<br />
Schnittpunkt<br />
Lichtquelle<br />
Objekte<br />
Abbildung 2.1.: Pr<strong>in</strong>zip e<strong>in</strong>es Raytracers<br />
Der Persistence of Vision Raytracer (POV-Ray) erzeugt Grafiken mit Raytrac<strong>in</strong>g<br />
und kann damit sehr realitätsnahe Resultate erzielen. Als E<strong>in</strong>gabe erhält er e<strong>in</strong>e<br />
Szenenbeschreibung <strong>in</strong> der POV-Ray eigenen Szenenbeschreibungssprache POV-Ray<br />
SDL 8 . Diese Beschreibung enthält die Informationen über<br />
• Objekte <strong>in</strong> der Szene,<br />
• die Kamerae<strong>in</strong>stellung,<br />
• vorhandene Lichtquellen und<br />
• eventuell weitere E<strong>in</strong>stellungen[12, Abschnitt 2.2].<br />
Durch e<strong>in</strong>en Export der aktuellen Szene <strong>in</strong> die SDL und e<strong>in</strong> anschließendes Render<strong>in</strong>g<br />
mit POV-Ray kann die Bibliothek somit hochwertige Grafiken erstellen.<br />
6<br />
8 scene description language
3. Realisierung<br />
3.1. Konzept der Bibliothek<br />
Im Rahmen der Realisierung soll nun zuerst die gewünschte Funktionalität der Bibliothek<br />
genauer beschrieben werden. Die Bibliothek soll e<strong>in</strong>e e<strong>in</strong>heitliche, <strong>von</strong> den zur<br />
Verfügung stehenden Ausgabeformaten unabhängige Schnittstelle bieten. Die Schnittstelle<br />
soll dabei möglichst kle<strong>in</strong> und e<strong>in</strong>fach benutzbar se<strong>in</strong>, sodass e<strong>in</strong> Anwender sie<br />
nach e<strong>in</strong>er kurzen E<strong>in</strong>arbeitungszeit nutzen kann.<br />
E<strong>in</strong> erster Schritt dazu, ist die E<strong>in</strong>schränkung der darstellbaren Inhalte. Der Fokus<br />
der Bibliothek liegt auf abstrahierten Szenen, nicht auf Fotorealismus. Die Bibliothek<br />
soll sich auf e<strong>in</strong>gefärbte Objekte aus Dreiecksgittern beschränken, Objekte mit<br />
Texturen sollen nicht darstellbar se<strong>in</strong>. Die Beleuchtung der Szene soll durch e<strong>in</strong>e e<strong>in</strong>zelne<br />
Lichtquelle erfolgen. Schattenwurf, Spiegelungen und Ähnliches müssen nicht<br />
dargestellt werden können.<br />
Die Bibliothek soll plattformunabhängig se<strong>in</strong>, das bedeutet konkret, dass sie unter<br />
den Betriebssystemen Microsoft W<strong>in</strong>dows, Apple Mac OS X und GNU/L<strong>in</strong>ux-<br />
Distributionen funktionieren und auf weitere Systeme portierbar se<strong>in</strong> soll. Als Programmiersprache<br />
wird daher C verwendet, allerd<strong>in</strong>gs soll die Schnittstelle so geschrieben<br />
se<strong>in</strong>, dass sie auch aus anderen Sprachen benutzbar ist. Dies soll am Beispiel e<strong>in</strong>er<br />
Python-Anb<strong>in</strong>dung umgesetzt werden.<br />
Die Bibliothek wird im folgenden GR3 genannt, <strong>in</strong> Anlehnung an die GR-Bibliothek<br />
und die Darstellung <strong>von</strong> dreidimensionalen Inhalten.<br />
3.1.1. Die Bibliothek GR3 <strong>in</strong> der Grafik<strong>in</strong>frastruktur<br />
Die zur Erstellung der Grafiken verwendeten Programme und Bibliotheken sollen <strong>von</strong><br />
GR3 abstrahiert werden, so dass der Anwendungsentwickler nur e<strong>in</strong>e e<strong>in</strong>zige Schnittstelle<br />
beherrschen muss, um Grafiken zu erstellen. Neben GR3 kann er natürlich auch<br />
andere Bibliotheken, wie GUI-Toolkits, GKS/GR oder OpenGL selbst, nutzen.<br />
Mit OpenGL oder POV-Ray können aus den dreidimensionalen Szenen zweidimensionale<br />
Rastergrafiken erzeugt werden. Diese stellen e<strong>in</strong>e gute Möglichkeit zur <strong>Integration</strong><br />
der Bibliothek <strong>in</strong> <strong>2D</strong>-Grafiksysteme dar. Solche Pixmaps können <strong>in</strong> den meisten<br />
GUI-Toolkits, aber auch im Graphischen Kernsystem angezeigt werden. Wenn der<br />
Anwendungsentwickler mit der Bibliothek arbeitet, ist es s<strong>in</strong>nvoll das Anzeigen der<br />
Rastergrafik direkt anzubieten, um die Benutzung zu erleichtern. Im Rahmen dieser<br />
Arbeit soll e<strong>in</strong>e derartige <strong>Integration</strong> für GKS/GR erfolgen.<br />
7
Kapitel 3. Realisierung<br />
Dieser Ansatz hat jedoch den Nachteil, dass bei jeder Veränderung der Szene, die<br />
dargestellt werden soll, e<strong>in</strong>e neue Pixmap erstellt und an die Anwendung übergeben<br />
werden muss. Falls OpenGL zum Erstellen der Grafik benutzt wird, muss diese also<br />
aus dem Grafikkartenspeicher <strong>in</strong> den Hauptspeicher, und dann, falls sie <strong>in</strong> e<strong>in</strong>em<br />
OpenGL-Fenster dargestellt wird, wieder zurück <strong>in</strong> den Grafikkartenspeicher kopiert<br />
werden. Dieser Umweg sorgt bei <strong>in</strong>teraktiven Anwendungen für deutliche Verzögerungen.<br />
Statt dessen sollte die Bibliothek, wenn OpenGL zum Darstellen genutzt wird,<br />
die Szene auch <strong>in</strong> das bestehende OpenGL-Fenster zeichnen können.<br />
GR<br />
POV-Ray<br />
Generator<br />
POV-Ray<br />
GKS<br />
O screen<br />
Render<strong>in</strong>g<br />
Anwendung<br />
GR3<br />
Direktes<br />
Render<strong>in</strong>g<br />
JavaScript<br />
Generator<br />
Browser<br />
WebGL<br />
OpenGL & WGL/CGL/GLX<br />
Abbildung 3.1.: GR3 <strong>in</strong> der Grafik<strong>in</strong>frastruktur<br />
...<br />
GLUT Qt<br />
Das Schichtendiagramm (Abb. 3.1) verdeutlicht die E<strong>in</strong>bettung der Bibliothek <strong>in</strong><br />
der Grafik<strong>in</strong>frastruktur: Die Anwendung <strong>in</strong>teragiert zur Erstellung <strong>von</strong> Grafiken primär<br />
mit GR3, andere Schnittstellen können parallel dazu genutzt werden. Unter der<br />
e<strong>in</strong>heitlichen GR3-Schnittstelle liegen Module für die e<strong>in</strong>zelnen Ausgabemethoden:<br />
Funktionen, um mit OpenGL Rastergrafiken zu erzeugen, und Generatoren für POV-<br />
Ray Szenenbeschreibungen sowie HTML5/JavaScript-Dateien, die WebGL nutzen.<br />
Außerdem kann die Szene direkt <strong>in</strong> e<strong>in</strong>em bestehenden OpenGL-Zeichenbereich gerendert<br />
werden. Die Szenenbeschreibungen können mit POV-Ray <strong>in</strong> Rastergrafiken<br />
umgewandelt werden und zusammen mit den mit OpenGL erstellten Rastergrafiken<br />
können diese dann an die GR-Bibliothek zur Darstellung mit GKS übergeben werden.<br />
Die HTML-Dateien können <strong>in</strong> e<strong>in</strong>em Browser betrachtet werden, dieser verwendet zur<br />
Darstellung e<strong>in</strong>e WebGL-Implementierung, welche u. U. wieder auf OpenGL zurückgreift.<br />
8
3.1.2. Entwurf der Schnittstelle<br />
3.1. Konzept der Bibliothek<br />
Die Schnittstelle <strong>von</strong> GR3 ist stark an die <strong>in</strong> e<strong>in</strong>er früheren Arbeit vorgestellte GLor-<br />
API 1 [15] angelehnt. Die Funktionen s<strong>in</strong>d dabei <strong>in</strong> mehrere Kategorien aufgeteilt.<br />
3.1.2.1. Allgeme<strong>in</strong>e Funktionen<br />
Es gibt Funktionen zum Initialisieren und Term<strong>in</strong>ieren der Bibliothek. Außerdem<br />
werden Hilfsfunktionen benötigt, wie beispielsweise e<strong>in</strong>e Funktion um Fehlercodes <strong>in</strong><br />
Fehlernamen umzusetzen.<br />
3.1.2.2. Szenenbeschreibungsfunktionen<br />
Die meisten Funktionen der API dienen dazu, die Szene zu beschreiben. Zum e<strong>in</strong>en<br />
gibt es Funktionen zum Erstellen, Zeichnen und Löschen <strong>von</strong> Dreiecksgittern, zum<br />
anderen können die Eigenschaften der Kamera und der Beleuchtung gesetzt werden.<br />
Um die Benutzung zu erleichtern gibt es außerdem Funktionen zum Zeichnen <strong>von</strong><br />
Kugeln, Kegeln und Zyl<strong>in</strong>dern.<br />
Diesen Funktionen steht <strong>in</strong>nerhalb der Bibliothek e<strong>in</strong>e Szenenverwaltung gegenüber,<br />
<strong>in</strong> welcher die Dreiecksgitter, Zeichenaufrufe und globale Eigenschaften gespeichert<br />
s<strong>in</strong>d.<br />
3.1.2.3. Funktionen zum Zeichnen und Export der Szene<br />
Während die GLor-API nur e<strong>in</strong>e e<strong>in</strong>zelne Funktion zum Erzeugen und Auslesen e<strong>in</strong>er<br />
Pixmap hatte, s<strong>in</strong>d <strong>in</strong> dieser Kategorie nun weitere Funktionen nötig. Speziell müssen<br />
drei verschiedene Aktionen ausgeführt werden können:<br />
• Die Szene <strong>in</strong> verschiedene Dateiformate exportieren<br />
• E<strong>in</strong>e Pixmap an die Anwendung zurückgeben<br />
• Die Szene mit GKS/GR oder OpenGL <strong>in</strong> e<strong>in</strong>em Fenster der Anwendung darstellen<br />
In Abbildung 3.2 s<strong>in</strong>d die verschiedenen Wege der Szene <strong>von</strong> der Anwendung zu<br />
e<strong>in</strong>er der Ausgabemöglichkeiten vere<strong>in</strong>facht dargestellt. Diese drei Aufgaben lassen<br />
sich durch jeweils entsprechende Funktionen erfüllen. Die grundsätzliche Qualität der<br />
erzeugten Grafiken, also beispielsweise ob die Grafik über OpenGL oder POV-Ray<br />
erzeugt werden soll, oder ob Kantenglättung verwendet werden soll, kann <strong>in</strong> e<strong>in</strong>er<br />
weiteren, da<strong>von</strong> getrennten Funktion angegeben werden. Der Export <strong>in</strong> Dateien lässt<br />
sich allgeme<strong>in</strong> durch e<strong>in</strong>e Funktion lösen, welche den Namen der Zieldatei und die gewünschte<br />
Auflösung (für den Fall e<strong>in</strong>er Rastergrafik) erhält. Anhand der verwendeten<br />
Dateiendung kann erkannt werden, welches Exportformat verwendet werden soll; der<br />
Nutzer muss dieses nicht explizit auswählen.<br />
1 OpenGL o screen renderer<br />
9
Kapitel 3. Realisierung<br />
HTML5/JavaScript-<br />
Dokument<br />
JavaScript<br />
Generator<br />
.html<br />
.pov<br />
Anwendung<br />
Szenenverwaltung<br />
POV-Ray<br />
Generator<br />
POV-Ray<br />
OpenGL-<br />
Funktionen<br />
OpenGL<br />
jpeglib libpng Anwendung GR<br />
.jpeg<br />
Szene<br />
Szenenbeschreibung<br />
Export <strong>in</strong> e<strong>in</strong>e Datei<br />
.png<br />
Rastergrafik<br />
Pixmap<br />
auslesen<br />
Fenster der<br />
Anwendung<br />
Zeichnen <strong>in</strong> GKS/GR<br />
oder OpenGL<br />
Abbildung 3.2.: Vere<strong>in</strong>fachte Darstellung der verschiedenen Ausgabemöglichkeiten<br />
Die Signaturen dieser beiden Funktionen können <strong>in</strong> C wie folgt aussehen:<br />
1 <strong>in</strong>t gr3_setquality(<strong>in</strong>t quality);<br />
2 <strong>in</strong>t gr3_export( const char filename , <strong>in</strong>t width , <strong>in</strong>t height) ;<br />
List<strong>in</strong>g 3.1: Funktionen zum Setzen der Qualität und Export <strong>in</strong> e<strong>in</strong>e Datei<br />
Das Auslesen (und dadurch impliziert auch das Erstellen) e<strong>in</strong>er Pixmap benötigt<br />
ebenfalls die gewünschte Auflösung. Anstelle des Date<strong>in</strong>amens muss das Ziel für die<br />
Pixmap e<strong>in</strong> Speicherbereich se<strong>in</strong>. E<strong>in</strong>e Zusatz<strong>in</strong>formation, welche die Arbeit mit unterschiedlichen<br />
Toolkits für den Benutzer deutlich erleichtern kann, ist e<strong>in</strong>e Angabe<br />
ob die Pixmap neben Rot, Grün und Blau auch den Alpha-Wert e<strong>in</strong>es jeden Pixels,<br />
also dessen Deckkraft, enthalten soll. E<strong>in</strong>e mögliche Funktionssignatur wäre dann die<br />
folgende:<br />
1 <strong>in</strong>t gr3_getimage( <strong>in</strong>t width , <strong>in</strong>t height , <strong>in</strong>t use_alpha , char pixels);<br />
10<br />
List<strong>in</strong>g 3.2: Funktion zum Auslesen e<strong>in</strong>er Pixmap
3.1. Konzept der Bibliothek<br />
Die letzte Funktion, das Zeichnen <strong>in</strong> e<strong>in</strong>en bestehenden Zeichenbereich, benötigt e<strong>in</strong>e<br />
weitere Überlegung über zukünftige Anwendungsfälle. Die Bibliothek soll grundsätzlich<br />
um Unterstützung <strong>von</strong> beliebigen GUI-Toolkits und ähnlichen Bibliotheken erweiterbar<br />
se<strong>in</strong> und bezüglich der parallelen Verwendbarkeit mehrerer solcher Systeme<br />
soll sie ke<strong>in</strong>en limitierenden Faktor darstellen. Falls e<strong>in</strong>e Anwendung also gleichzeitig<br />
mit z. B. wxWidgets, OpenGL, DirectX und GKS/GR arbeitet, darf das Konzept <strong>von</strong><br />
GR3 dem nicht im Wege stehen. In e<strong>in</strong>er solchen Situation muss zum e<strong>in</strong>en entschieden<br />
werden, welche Zeichenfläche das Ziel darstellt und zum anderen ob und welche<br />
Parameter übergeben werden.<br />
List<strong>in</strong>g 3.3 zeigt zwei Möglichkeiten dies zu realisieren:<br />
1 <strong>in</strong>t drawimage( <strong>in</strong>t draw<strong>in</strong>g_target , . . . ) ;<br />
2<br />
3 //oder :<br />
4 typedef struct {<br />
5 char name ;<br />
6 void value ;<br />
7 } option_t ;<br />
8 const option_t LAST_OPTION = {NULL, NULL};<br />
9<br />
10 <strong>in</strong>t drawimage( <strong>in</strong>t draw<strong>in</strong>g_target , const option_t options) ;<br />
List<strong>in</strong>g 3.3: Zwei mögliche Signaturen e<strong>in</strong>er Funktion zum Zeichnen <strong>in</strong> e<strong>in</strong> beliebiges<br />
Ziel mit beliebigen Optionen<br />
Während die erste Variante für den Benutzer grundsätzlich e<strong>in</strong>e e<strong>in</strong>fache Benutzung<br />
darstellt, haben variadische Funktionen mehrere Nachteile: Die Portierung <strong>in</strong> andere<br />
Sprachen könnte schwieriger se<strong>in</strong> als die Portierung e<strong>in</strong>er normalen Funktion, je<br />
nachdem <strong>in</strong>wieweit sie <strong>in</strong> der Zielsprache unterstützt werden. Benutzungsfehler, wie<br />
das Verwenden e<strong>in</strong>es falschen Datentyps, das Vergessen e<strong>in</strong>er eventuell nötigen Markierung<br />
des Endes der Argumentenliste oder das Übergeben überzähliger Argumente,<br />
führen nicht zu Kompilierungsfehlern, sondern zu nicht vorhersehbarem Laufzeitverhalten.<br />
Dies reicht <strong>von</strong> e<strong>in</strong>em sofortigem Abbruch des Programms auf Grund e<strong>in</strong>es<br />
Speicherzugri sfehlers bis zu sche<strong>in</strong>bar korrektem Verhalten. Außerdem ist die<br />
Schnittstelle e<strong>in</strong>er variadischen Funktion nicht klar durch den Code selbst def<strong>in</strong>iert,<br />
sodass der Anwendungsentwickler deutlich stärker auf die Dokumentation angewiesen<br />
ist: Die Schnittstelle ist weniger <strong>in</strong>tuitiv.<br />
Der zweite Ansatz verwendet e<strong>in</strong>e Datenstruktur, um e<strong>in</strong> Name-Wert-Paar für jede<br />
Option <strong>in</strong> e<strong>in</strong>er null-term<strong>in</strong>ierten Liste anzugeben. Dadurch ist die Schnittstelle zwar<br />
klar def<strong>in</strong>iert, jedoch leidet die Benutzbarkeit und Fehler <strong>in</strong> der Benutzung führen<br />
eventuell zu ähnlich unvorhersehbaren Problemen wie die Verwendung e<strong>in</strong>er variadischen<br />
Funktion.<br />
E<strong>in</strong> dritter Ansatz wäre die Erweiterung der Schnittstelle mit e<strong>in</strong>er Funktion pro<br />
Zeichenbereich. In der Verwendung wäre diese Variante klar vorteilhaft, da für jede<br />
Drittbibliothek genau die benötigten Optionen def<strong>in</strong>iert s<strong>in</strong>d, jedoch wird dadurch<br />
e<strong>in</strong> großer Nachteil der beiden vorangegangenen Ansätze klar: Grundsätzlich ist die<br />
Funktion nur dafür da, die Szene <strong>in</strong> e<strong>in</strong>em beliebigen Zeichenbereich darzustellen.<br />
11
Kapitel 3. Realisierung<br />
Die Initialisierung dieses Zeichenbereichs oder e<strong>in</strong>e Kopplung zwischen diesem und<br />
GR3 s<strong>in</strong>d eigentlich nicht Teil dieser Aufgabe. Übernimmt man diese Aufgaben durch<br />
sehr weitgehende Funktionsparameter wird das (auf Funktionen erweiterte) Pr<strong>in</strong>zip<br />
der e<strong>in</strong>en Verantwortlichkeit 2 verletzt. Übernimmt man sie durch e<strong>in</strong>e Erweiterung<br />
der Schnittstelle, wird die Wiederverwendbarkeit des Codes e<strong>in</strong>geschränkt und die<br />
Schnittstelle wird eventuell unnötig groß. Der eigentliche Ort dafür ist e<strong>in</strong>e separate<br />
Initialisierungsmethode, beziehungsweise es sollte möglichst vermieden werden, dass<br />
e<strong>in</strong>e solche Kopplung zwischen GR3 und dem Zeichenbereich überhaupt notwendig<br />
wird.<br />
Daher wurde dies <strong>in</strong> GR3 so realisiert, dass die Auflösung der Szene (für den Fall,<br />
dass sie <strong>in</strong> e<strong>in</strong>e Rastergrafik umgewandelt werden muss) und das Zielrechteck im<br />
Zeichenbereich an die Funktion übergeben werden. Außerdem erhält sie noch e<strong>in</strong>e<br />
Ganzzahl anhand der die Art des Zeichenbereichs festgelegt werden kann. Weitere<br />
Parameter, wie beispielsweise e<strong>in</strong> Zeiger auf e<strong>in</strong>en speziellen Zeichenbereich, könnten<br />
über die Initialisierungsfunktion oder Umgebungsvariablen übergeben werden. Dies<br />
ist jedoch im Rahmen dieser Arbeit nicht nötig gewesen, da für das Zeichnen, sowohl<br />
<strong>in</strong> e<strong>in</strong> OpenGL-Fenster als auch <strong>in</strong> e<strong>in</strong> GKS-Fenster, e<strong>in</strong>e bessere Realisierung der<br />
Auswahl möglich war: GR3 rendert die Szene im aktuellen OpenGL-Kontext, beziehungsweise<br />
<strong>in</strong> der aktuellen GKS-Workstation.<br />
1 #def<strong>in</strong>e GR3_DRAWABLE_OPENGL 1<br />
2 #def<strong>in</strong>e GR3_DRAWABLE_GKS 2<br />
3 <strong>in</strong>t gr3_drawimage( float xm<strong>in</strong> , float xmax , float ym<strong>in</strong> , float ymax ,<br />
4 <strong>in</strong>t width , <strong>in</strong>t height , <strong>in</strong>t drawable_type) ;<br />
List<strong>in</strong>g 3.4: Funktion zum Zeichnen <strong>in</strong> e<strong>in</strong> beliebiges Ziel mit festgelegten Optionen<br />
3.2. Statische Ausgabe der Szene<br />
3.2.1. POV-Ray Szenenbeschreibung<br />
Die Ausgabe als POV-Ray Szenenbeschreibung entspricht <strong>von</strong> den im Folgenden vorgestellten<br />
Möglichkeiten am deutlichsten dem Konzept der Szene, welches die Bibliothek<br />
verwendet. E<strong>in</strong>e Szenenbeschreibungsdatei besteht dabei aus zwei Abschnitten:<br />
Aus globalen Eigenschaften und Objekten <strong>in</strong> der Szene. Das folgende Beispiel zeigt<br />
e<strong>in</strong>e e<strong>in</strong>fache POV-Ray Szenenbeschreibung und die daraus erstellte Grafik:<br />
1 camera {<br />
2 up <br />
3 right <br />
4 location <br />
5 look_at <br />
6 sky <br />
7 angle 45.000000<br />
8 }<br />
2 Das s<strong>in</strong>gle responsibility pr<strong>in</strong>ciple besagt, dass e<strong>in</strong>e Komponente e<strong>in</strong>es Softwaresystems nur genau<br />
e<strong>in</strong>e Verantwortlichkeit haben sollte[9, Abschnitt 3.1].<br />
12
9 light_source {<br />
3.2. Statische Ausgabe der Szene<br />
10 color rgb <br />
11 }<br />
12 background {<br />
13 color rgb <br />
14 }<br />
List<strong>in</strong>g 3.5: E<strong>in</strong>e Szenenbeschreibungsdatei für POV-Ray (Teil 1)<br />
Der erste Abschnitt besteht <strong>in</strong> diesem Beispiel wiederum aus drei kle<strong>in</strong>eren Blöcken.<br />
In den Zeilen 1 bis 8 werden <strong>in</strong> e<strong>in</strong>em camera-Block die Eigenschaften der metaphorischen<br />
„Kamera“ beschrieben:<br />
• Die Ausrichtung des Koord<strong>in</strong>atenverhältnisses (up- und right-Vektor)<br />
• Das Seitenverhältnis der erzeugten Rastergrafik (aspect = ||right||<br />
||up|| )<br />
• Position der Kamera (location)<br />
• Fokuspunkt (look_at)<br />
• E<strong>in</strong> Richtungsvektor, der im Koord<strong>in</strong>atensystem nach oben zeigt (oft up-Vektor<br />
genannt, hier ist es jedoch sky-Vektor)<br />
• Der vertikale Sichtfeldw<strong>in</strong>kel (angle)<br />
Anschließend folgt die Beschreibung e<strong>in</strong>er Lichtquelle. In diesem Beispiel handelt es<br />
sich um e<strong>in</strong>e e<strong>in</strong>fache, punktförmige, di use Lichtquelle, die weißes Licht aussendet.<br />
Dies entspricht der Art Beleuchtung, die GR3 realisieren können soll. Als letzte globale<br />
Eigenschaft wurde e<strong>in</strong> weißer H<strong>in</strong>tergrund gesetzt.<br />
Danach folgen die Objekte der Szene. In diesem Beispiel s<strong>in</strong>d es der E<strong>in</strong>fachheit halber<br />
Kugeln und Zyl<strong>in</strong>der, es können jedoch beliebige Dreiecksgitter angegeben werden<br />
und – dies ist e<strong>in</strong>e Besonderheit <strong>von</strong> POV-Ray – andere, mathematisch beschreibbare<br />
Objekte, wie beispielsweise Isoflächen[12, Abschnitt 2.4.4] oder Ausschnitte der<br />
Julia-Menge[12, Abschnitt 2.4.1.6].<br />
15 sphere {<br />
16 , 0.300000<br />
17 texture {<br />
18 pigment { color rgb }<br />
19 }<br />
20 }<br />
21 [. . . ]<br />
39 cyl<strong>in</strong>der {<br />
40 ,<br />
41 , 0.050000<br />
42 texture {<br />
43 pigment { color rgb }<br />
44 }<br />
45 }<br />
List<strong>in</strong>g 3.6: E<strong>in</strong>e Szenenbeschreibungsdatei für POV-Ray (Teil 2, gekürzt)<br />
13
Kapitel 3. Realisierung<br />
Abbildung 3.3.: Die <strong>von</strong> POV-Ray gerenderte Szene<br />
Die globalen Eigenschaften ergeben sich direkt aus den Eigenschaften, welche GR3<br />
benötigt und die über Funktionen gesetzt werden müssen. Um den zweiten Teil zu erzeugen<br />
kann die Liste der zu zeichnenden Objekte durchlaufen werden. Anhand e<strong>in</strong>er<br />
zusätzlichen Eigenschaft kann für jedes Dreiecksgitter gespeichert werden, ob es sich<br />
um normale, vom Anwendungsentwickler erstellte Dreiecksgitter handelt, oder um die<br />
drei <strong>von</strong> der Bibliothek zusätzlich unterstützten Körper: Kugel, Kegel und Zyl<strong>in</strong>der.<br />
Falls es sich um e<strong>in</strong>en <strong>von</strong> diesen Körpern handelt, wird <strong>in</strong> der POV-Ray Szenenbeschreibung<br />
ke<strong>in</strong> Dreiecksgitter gespeichert, sondern der entsprechende Körper, sodass<br />
diese glatten Körper ohne Dreiecks-„Facetten“ ersche<strong>in</strong>en.<br />
Um anstatt e<strong>in</strong>es vordef<strong>in</strong>ierten Körpers e<strong>in</strong> Dreiecksgitter zu erzeugen, kann <strong>in</strong><br />
der POV-Ray Szenenbeschreibungssprache e<strong>in</strong> mesh-Block verwendet werden, der<br />
e<strong>in</strong>e Liste <strong>von</strong> Dreiecken enthält. Dreiecke, deren Beleuchtung anhand e<strong>in</strong>es Normalenvektors<br />
für jeden der drei Ortsvektoren berechnet wird, werden mit e<strong>in</strong>em<br />
smooth_triangle-Block realisiert.<br />
1 mesh {<br />
2 #local tex = texture { pigment { color rgb } }<br />
3 smooth_triangle {<br />
4 , ,<br />
5 , ,<br />
6 , <br />
7 texture { tex }<br />
8 }<br />
9 [. . . ]<br />
10 }<br />
List<strong>in</strong>g 3.7: E<strong>in</strong> Beispiel für e<strong>in</strong>en mesh-Block<br />
In diesem Beispiel ist außerdem die Verwendung <strong>von</strong> Variablen gezeigt: Für jedes<br />
Dreieck muss e<strong>in</strong>e Farbe angegeben werden. Diese muss als Texturobjekt def<strong>in</strong>iert<br />
se<strong>in</strong>, daher wird <strong>in</strong> der zweiten Zeile e<strong>in</strong>e lokale Variable tex als texture-Block def<strong>in</strong>iert<br />
und <strong>in</strong> Zeile 7 im smooth_triangle-Block verwendet.<br />
14
3.2. Statische Ausgabe der Szene<br />
Um die Position und Orientierung des Körpers <strong>in</strong> die POV-Ray Szene e<strong>in</strong>zubeziehen,<br />
wird e<strong>in</strong>e 4 ◊ 4-Transformationsmatrix M def<strong>in</strong>iert, deren l<strong>in</strong>ke obere 3 ◊ 3-<br />
Untermatrix e<strong>in</strong>e Basistransformation <strong>in</strong> e<strong>in</strong> Orthonormalsystem entsprechend der<br />
gewünschten Ausrichtung erwirkt. Die Orts- und Normalenvektoren der Eckpunkte<br />
im Körper werden um e<strong>in</strong>e vierte Dimension w erweitert, wobei allen Ortsvektoren<br />
w =1und allen Normalenvektoren w =0zugeordnet wird. Durch die vierte Spalte<br />
der Matrix können die Ortsvektoren zusätzlich noch verschoben werden, sodass der<br />
Körper die gewünschte Position erhält.<br />
mit:<br />
Q<br />
rightx c<br />
M = c righty c<br />
a rightz up ˜ x<br />
up ˜ y<br />
up ˜ z<br />
forwardx<br />
forwardy<br />
forwardz<br />
positionx positiony positionz R<br />
d<br />
b<br />
0 0 0 1<br />
position ·<br />
= gewünschte Position<br />
forward ·<br />
= gewünschte Ausrichtung (nach vorne)<br />
up ·<br />
= gewünschte Ausrichtung (nach oben)<br />
left = forward ◊ up<br />
up ˜ = left ◊ forward<br />
right = ≠left<br />
Wie <strong>in</strong> Abbildung 3.2 dargestellt, soll neben dem Export der Szenenbeschreibung <strong>in</strong><br />
e<strong>in</strong>e Datei auch die Erstellung e<strong>in</strong>er Rastergrafik mit POV-Ray möglich se<strong>in</strong>. Das<br />
folgende Diagramm zeigt dafür den Weg der Daten:<br />
Anwendung<br />
Szene<br />
Szenenverwaltung<br />
libpng<br />
Szene<br />
POV-Ray<br />
Generator<br />
szene.png<br />
szene.pov<br />
Pixmap<br />
Rastergrafikexport<br />
Pixmap<br />
POV-Ray<br />
GR<br />
jpeglib<br />
libpng<br />
Anwendung<br />
Abbildung 3.4.: Erstellung e<strong>in</strong>er Rastergrafik mit GR3 und POV-Ray<br />
15
Kapitel 3. Realisierung<br />
Die Ausgabe des Generators wird dazu <strong>in</strong> e<strong>in</strong>e temporäre Datei geschrieben, <strong>von</strong><br />
POV-Ray verarbeitet und das Ergebnis wird mit Hilfe der libpng e<strong>in</strong>gelesen. Die so<br />
erhaltene Pixmap kann anschließend <strong>von</strong> e<strong>in</strong>er der verschiedenen Exportfunktionen<br />
weiterverarbeitet werden.<br />
3.2.2. Rasterisierung <strong>in</strong> OpenGL<br />
3.2.2.1. Der OpenGL-Kontext<br />
Um OpenGL-Funktionen zu verwenden, muss e<strong>in</strong> OpenGL-Kontext aktiv se<strong>in</strong>. Dieser<br />
enthält unter anderem Informationen darüber, welche OpenGL-Version verwendet<br />
wird und wo der Framebu er liegt. Jedoch ist nicht festgelegt, wie dieser aufgebaut<br />
ist. Die Spezifikation lässt dies o en, da die Erstellung dieses Kontextes nicht Teil<br />
<strong>von</strong> OpenGL selbst ist, sondern durch andere Bibliotheken, die e<strong>in</strong>e Schicht zwischen<br />
OpenGL und dem Betriebssystem bilden, erfolgt[16, S. 7]. Unter Apple Mac OS X<br />
stellt Core OpenGL (CGL) diese Schicht dar; unter L<strong>in</strong>ux, beziehungsweise immer<br />
wenn das X W<strong>in</strong>dow System verwendet wird, s<strong>in</strong>d es die OpenGL Extensions to<br />
the X W<strong>in</strong>dow System (GLX) und unter Microsoft W<strong>in</strong>dows s<strong>in</strong>d es die W<strong>in</strong>dows<br />
Extensions to OpenGL (WGL).<br />
Für die Bibliothek gibt es bezüglich des OpenGL-Kontextes zwei mögliche Fälle:<br />
Entweder existiert bereits e<strong>in</strong> Kontext, oder er muss erst erstellt werden. Falls bereits<br />
e<strong>in</strong> Kontext existiert, soll die Bibliothek diesen verwenden. Dazu gibt es <strong>in</strong> jeder<br />
der drei APIs e<strong>in</strong>e passende Funktion, die den Kontext zurückliefert. In CGL muss<br />
zusätzlich der Referenzzähler des Kontextes erhöht werden, um zu registrieren, dass<br />
die Bibliothek ihn ebenfalls nutzt und e<strong>in</strong>e Referenz dazu hält.<br />
1 // CGL:<br />
2 CGLContextObj ctx = CGLGetCurrentContext () ;<br />
3 if (ctx != NULL) {<br />
4 // <strong>in</strong>crease reference count for ctx<br />
5 CGLReta<strong>in</strong>Context( ctx ) ;<br />
6 }<br />
7<br />
10<br />
8 // GLX:<br />
9 GLXContext context = glXGetCurrentContext () ;<br />
11 // WGL:<br />
12 HGLRC g l r c = w g l G e t C u r r e n t C o n t e x t ( ) ;<br />
List<strong>in</strong>g 3.8: Verwenden e<strong>in</strong>es bestehenden OpenGL-Kontextes mit CGL, GLX und<br />
WGL<br />
Liefern diese Methoden NULL, gibt es ke<strong>in</strong>en aktuellen Kontext und die Bibliothek ist<br />
selber dafür verantworlich e<strong>in</strong>en solchen zu erstellen. In diesem Fall wird auf die Funktionen<br />
zur Erstellung e<strong>in</strong>es O screen Render<strong>in</strong>g Kontext aus GLor zurückgegri en.<br />
Diese werden <strong>in</strong> [15, Abschnitt 3.1.1] erläutert.<br />
16
3.2. Statische Ausgabe der Szene<br />
Pixel data Vertex data<br />
Pixel operations<br />
Rasterization<br />
Fragment shader<br />
Raster operations<br />
Framebu↵er<br />
Vertex shader<br />
Primitive assembly<br />
Geometry shader<br />
Abbildung 3.5.: Die OpenGL Core Profile Pipel<strong>in</strong>e[17, S. 11][15, S. 7]<br />
17
Kapitel 3. Realisierung<br />
3.2.2.2. Render<strong>in</strong>g mit Framebu er Objekten<br />
Um das Render<strong>in</strong>g <strong>von</strong> dem verwendeten OpenGL-Zeichenbereichs unabhängig zu<br />
machen, und hiermit sowohl O screen Render<strong>in</strong>g als auch Render<strong>in</strong>g <strong>in</strong> existierenden<br />
Fenstern zu ermöglichen, arbeiten die im folgenden Abschnitt beschriebenen Methoden<br />
zur Rasterisierung auf Framebu er Objekten. Dies hat im Falle e<strong>in</strong>es bereits<br />
existierenden OpenGL-Kontextes die Vorteile, dass der Standard-Framebu er nicht<br />
manipuliert wird und der verwendete Framebu er so stets e<strong>in</strong>e feste Größe hat. Weiterführende<br />
Informationen zur Erstellung und Verwendung <strong>von</strong> Framebu er Objekten<br />
s<strong>in</strong>d <strong>in</strong> [15, Abschnitt 3.1.2] zu f<strong>in</strong>den.<br />
3.2.2.3. Erstellung <strong>von</strong> Rastergrafiken mit OpenGL<br />
OpenGL ist <strong>von</strong> Konzepten wie e<strong>in</strong>er Szene unabhängig. Im Gegensatz zu Raytracern<br />
wie POV-Ray stehen bei OpenGL ke<strong>in</strong>e „Lichtstrahlen“ im Vordergrund, sondern die<br />
e<strong>in</strong>zelnen geometrischen Primitiven. Vere<strong>in</strong>facht gesagt, wird für jedes Dreieck bestimmt,<br />
welche Pixel es im Bild e<strong>in</strong>nimmt, und diese werden, wenn sie nicht bereits<br />
durch näher an der Kamera liegende Primitiven gesetzt wurden, den Eigenschaften<br />
des Dreiecks gemäß e<strong>in</strong>gefärbt. Die Interpretation dieser Dreiecke als Oberflächen<br />
dreidimensionaler Körper ist dem Nutzer <strong>von</strong> OpenGL überlassen. Dieser wird dennoch<br />
dabei unterstützt, Gruppen <strong>von</strong> Dreiecken als zusammenhängende Körper zu<br />
betrachten, da es Funktionen gibt, welche auf mehreren Dreiecken arbeiten (z. B.<br />
transformieren oder zeichnen). Diese werden dazu verwendet, die e<strong>in</strong>zelnen Körper<br />
der Szene zu beschreiben und zu zeichnen.<br />
Wie e<strong>in</strong>leitend beschrieben, gibt es zwei Varianten der OpenGL-Rasterisierungs-<br />
Pipel<strong>in</strong>e. Im Folgenden wird beschrieben, wie die Shader-basierte Pipel<strong>in</strong>e (siehe Abbildung<br />
3.5) genutzt wurde, um e<strong>in</strong>e Rastergrafik zu erzeugen. Die realisierte Funktionalität<br />
ist mit der Fixed-Function-Pipel<strong>in</strong>e ebenfalls umsetzbar und wurde aus<br />
Gründen der Abwärtskompatibilität auch als Teil <strong>von</strong> GR3 implementiert.<br />
Die mit den Funktionen der Szenenverwaltung erstellten Dreiecksgitter werden <strong>in</strong><br />
OpenGL als Vertex Bu er Objekte behandelt. Dies s<strong>in</strong>d Bereiche des Grafikkartenspeichers,<br />
<strong>in</strong> welche die Daten der e<strong>in</strong>zelnen Vertices geschrieben werden. Für jeden<br />
Vertex müssen dessen Position, Oberflächennormale und Farbe gespeichert werden.<br />
Sie werden als float gespeichert, sodass e<strong>in</strong> Vertex <strong>in</strong>sgesamt 36 Byte Speicher benötigt.<br />
Die Vertices e<strong>in</strong>es solchen Vertex Bu er Objektes werden durch e<strong>in</strong>en Aufruf der<br />
Funktion glDrawArrays zur E<strong>in</strong>gabe der Pipel<strong>in</strong>e. Dort werden sie (unter anderem)<br />
durch den Vertex-Shader bearbeitet, und die e<strong>in</strong>zelnen Pixel können dann im<br />
Fragment-Shader e<strong>in</strong>gefärbt werden.<br />
Bei der Berechnung der Farbe e<strong>in</strong>es jeden Pixels wird da<strong>von</strong> ausgegangen, dass die<br />
Oberfläche ideal di us ist, das heißt, dass sie das e<strong>in</strong>fallende Licht <strong>in</strong> alle Richtungen<br />
gleichmäßig streut. Für solche Oberflächen gilt das Lambert’sche Gesetz, welches die<br />
Intensität des reflektierten Lichts abhängig vom W<strong>in</strong>kel zwischen den e<strong>in</strong>fallenden<br />
Lichtstrahlen und der Oberflächennormalen beschreibt (s. Abb. 3.6). Für diesen W<strong>in</strong>-<br />
18
3.2. Statische Ausgabe der Szene<br />
kel ◊ ist die w<strong>in</strong>kelabhängige Intensität I(◊) proportional zu cos(◊) [17, S. 243][21].<br />
I(✓) ·~r<br />
Imax · ~n<br />
✓<br />
Lambert’sche Fläche<br />
Abbildung 3.6.: Die w<strong>in</strong>kelabhängige Intensität des reflektierten Lichts nach dem<br />
Lambert’schen Kos<strong>in</strong>usgesetz<br />
Für den normalisierten Richtungsvektor zur Lichtquelle ˛r, die Oberflächennormale ˛n<br />
und e<strong>in</strong>en Farbvektor ˛c (RGB-Werte) ergibt sich dann die Formel:<br />
˛cpixel = ˛csurface · I(◊)<br />
= ˛csurface · cos(◊)<br />
= ˛csurface · (˛r · ˛n)<br />
˛˜cpixel = abs(˛cpixel)<br />
Anhand <strong>von</strong> ˛˜cpixel kann somit die Pixelfarbe ohne Berücksichtigung <strong>von</strong> Vor- und<br />
Rückseite gesetzt werden. Außerdem müssen noch Skalierungen und andere Transformationen<br />
durchgeführt werden: zum e<strong>in</strong>en auf die Position des Vertex, zum anderen<br />
auch auf die Normale, da diese sich im selben Koord<strong>in</strong>atensystem bef<strong>in</strong>den muss wie<br />
der Vektor ˛r, um obige Rechnung durchzuführen. Im Gegensatz zu der Position sollte<br />
die Normale jedoch nicht skaliert werden; daher wird vorausgesetzt, dass die Transformationsmatrizen<br />
orthonormal s<strong>in</strong>d.<br />
Das folgende List<strong>in</strong>g zeigt, wie die beschriebenen Rechnungen <strong>in</strong> der OpenGL Shad<strong>in</strong>g<br />
Language realisiert werden können:<br />
1 #version 120<br />
2 uniform mat4 ProjectionMatrix ;<br />
3 uniform mat4 ViewMatrix ;<br />
4 uniform mat4 ModelMatrix ;<br />
19
Kapitel 3. Realisierung<br />
5 uniform vec3 LightDirection ;<br />
6 uniform vec3 Scales ;<br />
7 attribute vec3 <strong>in</strong>_Vertex ;<br />
8 attribute vec3 <strong>in</strong>_Normal ;<br />
9 attribute vec3 <strong>in</strong>_Color ;<br />
10 vary<strong>in</strong>g vec4 Color ;<br />
11<br />
12 void ma<strong>in</strong>( void) {<br />
13 vec4 Position = ViewMatrix ModelMatrix ( vec4(Scales <strong>in</strong>_Vertex ,1) ) ;<br />
14 gl_Position=ProjectionMatrix Position ;<br />
15 vec3 Normal = vec3(ViewMatrix ModelMatrix vec4(<strong>in</strong>_Normal,0)).xyz;<br />
16 Color = vec4(<strong>in</strong>_Color ,1) ;<br />
17 float diffuse = Normal.z;<br />
18 if (dot(LightDirection ,LightDirection) > 0.001) {<br />
19 diffuse = dot(normalize(LightDirection),Normal);<br />
20 }<br />
21 diffuse = abs(diffuse);<br />
22 Color . rgb = diffuse Color . rgb ;<br />
23 }<br />
List<strong>in</strong>g 3.9: E<strong>in</strong> GLSL 1.2 Vertex-Shader für e<strong>in</strong>e Lambert’sche Oberfläche (di use<br />
Beleuchtung)<br />
Zum Verständnis muss gesagt werden, dass das Produkt zweier Vektoren <strong>in</strong> der GLSL<br />
standardmäßig das elementweise Produkt ist. Das Skalarprodukt ist <strong>in</strong> der (überladenen)<br />
Funktion dot(v,u) realisiert. Als uniform deklarierte Variablen s<strong>in</strong>d zur<br />
Laufzeit des Shader-Programms Konstanten, attribute Variablen s<strong>in</strong>d per-Vertex<br />
E<strong>in</strong>gaben und vary<strong>in</strong>g Variablen s<strong>in</strong>d per-Vertex Ausgaben des Vertex-Shaders (und<br />
per-Fragment E<strong>in</strong>gaben des Fragment-Shaders) 3 . Durch die zusätzliche Abfrage ob<br />
˛r ·˛r = ||˛r|| 2 ∫ 0 ist, wird sichergestellt, dass die Richtung zur Lichtquelle nicht auf<br />
den Nullvektor gesetzt wurde. Ist dies jedoch der Fall, dann wird stattdessen der<br />
Absolutbetrag der z-Komponente des Normalenvektors als Intensität verwendet. Dies<br />
entspricht e<strong>in</strong>er Lichtquelle h<strong>in</strong>ter der Kamera.<br />
Der zugehörige Fragment-Shader muss die vary<strong>in</strong>g Variable Color nur noch für den<br />
jeweiligen Pixel, beziehungsweise das jeweilige Fragment, setzen. Dabei wird implizit<br />
bil<strong>in</strong>ear <strong>in</strong>terpoliert, damit die per-Vertex berechneten Farben gleichmäßig <strong>in</strong>e<strong>in</strong>ander<br />
übergehen.<br />
1 #version 120<br />
2 vary<strong>in</strong>g vec4 Color ;<br />
3 void ma<strong>in</strong>( void) {<br />
4 gl_FragColor=Color ;<br />
5 }<br />
List<strong>in</strong>g 3.10: E<strong>in</strong> GLSL 1.2 Fragment-Shader<br />
3 Ab GLSL 1.3 wurden attribute und vary<strong>in</strong>g durch die besser verständlichen <strong>in</strong> und out ersetzt.<br />
Aus Gründen der Kompatibilität wurde allerd<strong>in</strong>gs die GLSL Version 1.2 verwendet, denn diese<br />
ist begleitend zu OpenGL 2.1 spezifiziert worden.<br />
20
3.2.2.4. Erstellung <strong>von</strong> Grafiken <strong>in</strong> hohen Auflösungen<br />
3.2. Statische Ausgabe der Szene<br />
Um sehr hochauflösende Grafiken mit OpenGL erstellen zu können, müssen mehrere<br />
limitierende Faktoren betrachtet werden. Zum e<strong>in</strong>en stellt der zur Verfügung stehende<br />
Grafikspeicher e<strong>in</strong>e physikalische Obergrenze für die maximale Auflösung der<br />
erzeugten Grafiken dar, zum anderen gibt es seitens der OpenGL-Implementierung<br />
e<strong>in</strong>e Obergrenze für die Viewport-Dimensionen, also für die Auflösung der Grafik. In<br />
[15, S. 21-23] wurde e<strong>in</strong> Verfahren vorgestellt, mit dem die Limitierung durch Aufteilen<br />
der Grafik <strong>in</strong> Teilbilder umgangen werden kann. Dazu wurde im Rahmen der<br />
Bibliothek GLor die OpenGL Viewport-Transformation genutzt. In e<strong>in</strong>igen OpenGL-<br />
Implementierungen s<strong>in</strong>d die maximalen Viewport-Dimensionen u. U. jedoch kle<strong>in</strong>er<br />
als die gewünschte Auflösung.<br />
Daher wurde e<strong>in</strong> alternatives Verfahren entwickelt, welche auf demselben Ansatz<br />
der Zerlegung <strong>in</strong> Teilbilder aufbaut, diese aber nicht mit Hilfe der Viewport-Transformation<br />
realisiert. Statt dessen arbeitet dieses Verfahren mit e<strong>in</strong>er Projektionsmatrix,<br />
welche stets nur e<strong>in</strong>en Teil des eigentlichen Sichtbereichs <strong>in</strong> die normalisierten Gerätekoord<strong>in</strong>aten<br />
transformiert.<br />
Üblicherweise wird e<strong>in</strong> symmetrischer Pyramidenstumpf (s. Abb. 3.7) als Sichtbereich<br />
verwendet 4 , um e<strong>in</strong>e perspektivische Projektion zu erreichen.<br />
y<br />
top<br />
bottom<br />
–<br />
2<br />
–<br />
near far<br />
Abbildung 3.7.: Skizze e<strong>in</strong>es symmetrischen Pyramidenstumpfes mit Unterteilungen<br />
(Schnitt entlang der y-z-Ebene)<br />
Folgendes ist e<strong>in</strong>e Projektionsmatrix für e<strong>in</strong>en solchen Pyramidenstumpf[19]:<br />
Q<br />
c<br />
PMsymm = c<br />
a<br />
f<br />
aspect<br />
0<br />
0<br />
0<br />
f<br />
0<br />
0<br />
0<br />
0<br />
0<br />
far+near<br />
0 0<br />
near≠far<br />
≠1<br />
far·near 2 · near≠far<br />
0<br />
R<br />
d<br />
b<br />
mit f = cotan( –<br />
2 )<br />
und aspect = widthimage<br />
heightimage 4 Das view<strong>in</strong>g frustum, so wie es mit der Funktion gluPerspective erzeugt werden kann.<br />
z<br />
21
Kapitel 3. Realisierung<br />
Dabei handelt es sich um e<strong>in</strong>e vere<strong>in</strong>fachte Form der Projektionsmatrix für e<strong>in</strong>en<br />
allgeme<strong>in</strong>en Pyramidenstumpf[18]:<br />
Q<br />
2<br />
c<br />
PMallg = c<br />
a<br />
near<br />
right≠left<br />
0<br />
0<br />
0<br />
near 2top≠bottom 0<br />
right+left<br />
right≠left<br />
top+bottom<br />
top≠bottom<br />
far+near<br />
near≠far<br />
0<br />
0<br />
2 · far·near<br />
near≠far<br />
R<br />
d<br />
b<br />
0 0 ≠1 0<br />
Falls es sich um e<strong>in</strong>en symmetrischen Pyramidenstumpf handelt, lassen sich die E<strong>in</strong>gangsgrößen<br />
dieser Matrix anhand e<strong>in</strong>er Skizze auf e<strong>in</strong>en W<strong>in</strong>kel –, welcher das vertikale<br />
Sichtfeld beschreibt, das Seitenverhältnis und die Distanzen zwischen dem Ursprung<br />
und der nahen, beziehungsweise der fernen Clipp<strong>in</strong>g-Ebene (near und far)<br />
reduzieren.<br />
Die Zusammenhänge top(= ≠bottom) =near · tan( – ) und (begründet durch das<br />
2<br />
Seitenverhältnis) right(= ≠left) =top · widthimage/heightimage s<strong>in</strong>d <strong>in</strong> Abbildung 3.7 erkennbar.<br />
Durch E<strong>in</strong>setzen und Vere<strong>in</strong>fachen ergibt sich so wieder die Matrix PMsymm.<br />
Um den für das Gesamtbild gewünschten symmetrischen Pyramidenstumpf <strong>in</strong> die<br />
für die Teilbilder nötigen Teilstücke zu zerteilen, kann mit Hilfe e<strong>in</strong>er l<strong>in</strong>earen Transformation<br />
zwischen top und bottom <strong>in</strong> der Vertikalen, so wie zwischen left und right<br />
<strong>in</strong> der Horizontalen, e<strong>in</strong>e Zerlegung vorgenommen werden, und für jedes Teilstück<br />
können neue Werte für top, bottom, left und right errechnet werden (t, b, l und r).<br />
Das Teilbild (x, y) hat <strong>in</strong> diesem Fall die (Viewport-)Dimensionen widthpart und<br />
heightpart für die gilt:<br />
widthpart = m<strong>in</strong>(widthframebu er, widthimage ≠ x · widthframebu er)<br />
height part = m<strong>in</strong>(height framebu er, height image ≠ y · height framebu er)<br />
Dann berechnen sich t, b, l und r als:<br />
l = left +(right ≠ left) · x · widthframebu er<br />
widthimage<br />
r = left +(right ≠ left) · x · widthframebu er + widthpart<br />
widthimage<br />
b = bottom +(top ≠ bottom) · y · height framebu er<br />
height image<br />
t = bottom +(top ≠ bottom) · y · height framebu er + height part<br />
height image<br />
Diese Werte werden dann <strong>in</strong> die Formel für PMallg e<strong>in</strong>gesetzt um die für das Teilbild<br />
(x, y) zu verwendende Projektionsmatrix zu erhalten.<br />
3.2.2.5. Kantenglättung mit Supersampl<strong>in</strong>g Antialias<strong>in</strong>g<br />
E<strong>in</strong>e Vektorgrafik kann zum<strong>in</strong>dest theoretisch beliebig genau se<strong>in</strong>, während e<strong>in</strong>e Rastergrafik<br />
nur e<strong>in</strong>e feste Anzahl an Pixeln mit e<strong>in</strong>er bestimmten Auswahl an Farben zur<br />
22
3.2. Statische Ausgabe der Szene<br />
Verfügung hat, um etwas darzustellen. Daher kommt es bei der Rasterisierung speziell<br />
an kontrastreichen Kanten zu unerwünschten E ekten. Die Pixel, durch welche<br />
die Kante verläuft, s<strong>in</strong>d Flächen, doch im Rahmen der Rasterisierung werden sie als<br />
Punkte angenähert, für die e<strong>in</strong> Farbwert bestimmt wird. Diese sogenannten Samples<br />
liegen entweder auf der e<strong>in</strong>en Seite der Kante, oder der anderen und entsprechend<br />
wird die gesamte Fläche des Pixels e<strong>in</strong>gefärbt. Wie <strong>in</strong> Abbildung 3.8 zu sehen wird<br />
die eigentlich geradl<strong>in</strong>ige Kante <strong>in</strong> (a) zu e<strong>in</strong>er Art „Treppe“ <strong>in</strong> (b).<br />
Um solche Quantisierungse ekte zu verh<strong>in</strong>dern, gibt es verschiedene Kantenglättungsalgorithmen.<br />
E<strong>in</strong>er da<strong>von</strong> ist das Supersampl<strong>in</strong>g Antialias<strong>in</strong>g, bei dem für jedes<br />
Pixel nicht e<strong>in</strong> e<strong>in</strong>zelnes Sample, sondern mehrere verwendet werden. Die für diese<br />
Sample berechneten Farbwerte <strong>in</strong> (c) werden gemittelt und dadurch wird die Kante<br />
geglättet, was <strong>in</strong> (d) durch Graustufen erkennbar ist.<br />
Dieser e<strong>in</strong>fach zu realisierende Algorithmus erzielt gute Ergebnisse, jedoch dauert<br />
die Erstellung e<strong>in</strong>es Bildes damit deutlich länger, da zum e<strong>in</strong>en e<strong>in</strong> vielfach größeres<br />
Bild erzeugt werden muss, weshalb die Rasterisierung auch e<strong>in</strong> Vielfaches länger<br />
dauert, und zum anderen zur Erstellung der endgültigen Grafik die Mittelung für<br />
jeden Pixel zusätzlich nötig ist. Diese ist im Rahmen dieser Arbeit nur auf der CPU<br />
realisiert worden.<br />
Es gibt Alternativen zu diesem Algorithmus, die ke<strong>in</strong> starres Gitter verwenden,<br />
sondern stattdessen die Samples nach Mustern anordnen, welche unter Umständen<br />
bessere Ergebnisse, beziehungsweise ähnliche Ergebnisse mit weniger Samples erreichen,<br />
oder die nur im Bereich der Kanten e<strong>in</strong>e Glättung anwenden. Die Anwendung<br />
solcher Algorithmen stellt e<strong>in</strong>e mögliche Erweiterung dar.<br />
(a) Vektorgrafik (b) 16x16 Pixel, ohne SSAA<br />
(c) 32x32 Pixel, ohne SSAA (d) 16x16 Pixel, mit 2x-SSAA<br />
Abbildung 3.8.: Bild (d) verwendet Informationen aus Bild (c), daher kann der Farbwert<br />
jedes Pixels aus vier statt nur e<strong>in</strong>em Sample berechnet werden.<br />
Daher werden neben Schwarz und Weiß auch drei Grauwerte zur Darstellung<br />
der Kante verwendet und die Quantisierungse ekte, die <strong>in</strong><br />
Bild (b) zu sehen s<strong>in</strong>d, werden abgeschwächt.<br />
23
Kapitel 3. Realisierung<br />
3.2.3. HTML5-Dokument mit e<strong>in</strong>em <strong>in</strong>teraktiven WebGL-Canvas<br />
Die Ausgabe e<strong>in</strong>es HTML5-Dokuments stellt e<strong>in</strong>e Mischung aus statischer und dynamischer<br />
Ausgabe dar, denn es handelt sich um e<strong>in</strong>e Art <strong>in</strong>teraktiven Screenshot.<br />
Mit allen nötigen Informationen ausgestattet, kann das erstellte Dokument später<br />
<strong>in</strong> e<strong>in</strong>em Browser geö net und betrachtet werden, wobei der Blickw<strong>in</strong>kel nicht fest<br />
vorgegeben ist, sondern durch den Nutzer verändert werden kann.<br />
WebGL ist <strong>in</strong> der Benutzung durch den Entwickler sehr ähnlich zum modernen,<br />
Shader-basierten OpenGL. Der größte Unterschied ist die Zielsprache, denn während<br />
die OpenGL-Schnittstelle auf C basiert, wurde WebGL für JavaScript entworfen. Wie<br />
die folgenden Code-Ausschnitte zeigen, s<strong>in</strong>d die e ektiven Unterschiede dank der fast<br />
identischen API jedoch ger<strong>in</strong>g:<br />
1 GLu<strong>in</strong>t vbo ;<br />
2 glGenBuffers(1,&vbo) ;<br />
3 glB<strong>in</strong>dBuffer(GL_ARRAY_BUFFER, vbo) ;<br />
List<strong>in</strong>g 3.11: Vertex Bu er Objekte <strong>in</strong> C<br />
1 var vbo = gl . createBuffer () ;<br />
2 gl . b<strong>in</strong>dBuffer(gl .ARRAY_BUFFER, vbo) ;<br />
List<strong>in</strong>g 3.12: Vertex Bu er Objekte <strong>in</strong> JavaScript<br />
E<strong>in</strong> deutlicher Unterschied liegt <strong>in</strong> der Erstellung des OpenGL, bzw. WebGL Kontext.<br />
Im Rahmen der Erweiterung der Hypertext Markup Language um multimediale<br />
Inhalte wurde unter anderem das canvas-Element 5 <strong>in</strong> den Standard aufgenommen.<br />
Dieses Element stellt e<strong>in</strong>e Zeichenfläche im HTML5-Dokument dar, die mit JavaScript<br />
für <strong>2D</strong>- oder <strong>3D</strong>-Grafiken verwendet werden kann. Das Element selbst ist dabei<br />
<strong>in</strong> [4, Abschnitt 4.8.11] wie folgt def<strong>in</strong>iert:<br />
1 <strong>in</strong>terface HTMLCanvasElement : HTMLElement {<br />
2 attribute unsigned long width ;<br />
3 attribute unsigned long height ;<br />
4<br />
5 DOMStr<strong>in</strong>g toDataURL( optional DOMStr<strong>in</strong>g type , any ... args);<br />
6 void toBlob( FileCallback? _callback , optional DOMStr<strong>in</strong>g type , any ...<br />
args) ;<br />
7<br />
8 object? getContext(DOMStr<strong>in</strong>g contextId , any ... args);<br />
9 };<br />
List<strong>in</strong>g 3.13: IDL-Beschreibung 6 des canvas-Elements<br />
Daran ist erkennbar, dass das canvas-Element selber ke<strong>in</strong>e Zeichenoperationen anbietet,<br />
sondern nur zwei Methoden zum Auslesen der Bilddaten und die Methode<br />
5 Das Wort canvas ist englisch für „Le<strong>in</strong>wand“ und wird <strong>in</strong> der GUI-Programmierung oft für Zei-<br />
chenbereiche verwendet.<br />
6 Interface Description Language<br />
24
3.2. Statische Ausgabe der Szene<br />
getContext. Wenn der Parameter contextId den Wert „webgl“, bzw. „experimentalwebgl“[11]<br />
hat, und der Browser WebGL unterstützt, wird e<strong>in</strong> WebGL Kontext erstellt.<br />
Dieser Kontext hat Gegenstücke zu den aus OpenGL bekannten Funktionen<br />
und Konstanten als Methoden und Attribute.<br />
Um e<strong>in</strong>e Szene zu exportieren muss daher e<strong>in</strong> HTML5-Dokument mit e<strong>in</strong>em canvas-<br />
Element und dem zur Darstellung der Szene nötigen JavaScript Code erstellt werden.<br />
Dieser Code muss als erstes den WebGL Kontext erstellen, dann die Shader-<br />
Programme laden, kompilieren und l<strong>in</strong>ken, und als letztes die Daten der Szene verarbeiten.<br />
Die Shader-Programme für WebGL s<strong>in</strong>d ebenfalls <strong>in</strong> GLSL geschrieben, sodass<br />
diese aus der Implementierung für OpenGL (List<strong>in</strong>gs 3.9 und 3.10) übernommen<br />
werden können. Da die GLSL-Variante für OpenGL ES 2.0 verwendet wird, muss allerd<strong>in</strong>gs<br />
noch e<strong>in</strong>e Angabe über die Genauigkeit <strong>von</strong> float<strong>in</strong>g po<strong>in</strong>t Zahlen h<strong>in</strong>zugefügt<br />
werden[20, Abschnitt 4.5].<br />
Um die Szene <strong>in</strong> JavaScript zu repräsentieren, werden zwei Array-Variablen angelegt.<br />
E<strong>in</strong>e da<strong>von</strong> enthält die Daten der Dreiecksgitter, e<strong>in</strong>e andere enthält deren<br />
Positionen, Orientierungen und Farben. Mit der ersten der beiden Variablen werden<br />
beim Laden der Seite Vertex Bu er Objekte erstellt, die andere Variable wird zum<br />
Zeichnen durchlaufen.<br />
Abbildung 3.9.: E<strong>in</strong>e mit WebGL dargestellte Szene<br />
25
Kapitel 3. Realisierung<br />
Um dem Anwender zu ermöglichen die Szene aus mehr als e<strong>in</strong>er Perspektive zu betrachten,<br />
wird das Event-System <strong>von</strong> JavaScript verwendet. Die Bewegungen der<br />
Maus werden über das mousemove-Event verfolgt, und die „Kamera“ wird entsprechend<br />
bewegt. E<strong>in</strong> Problem, welches sich dabei stellt, ist die Auswahl e<strong>in</strong>es geeigneten<br />
Verfahrens für die Positionsveränderung der Kamera abhängig <strong>von</strong> der Mausbewegung.<br />
E<strong>in</strong> ideales Verfahren ermöglicht dem Benutzer die Auswahl e<strong>in</strong>es Objektes im<br />
dreidimensionalen Raum durch e<strong>in</strong>en Maustastendruck, und bei anschließender Bewegung<br />
des Mauszeigers über der Zeichenfläche sollte dieses Objekt dem Mauszeiger<br />
folgen. Auf diesem Weg sollte die Szene aus allen Richtungen betrachtbar se<strong>in</strong>, e<strong>in</strong>e<br />
e<strong>in</strong>fache Verschiebung wäre also nicht ausreichend.<br />
Es müssen weitere Eigenschaften festgelegt werden, um e<strong>in</strong>e solche Kamerabewegung<br />
realisieren zu können. Es soll ke<strong>in</strong>e tatsächliche Auswahl <strong>von</strong> Objekten <strong>in</strong>nerhalb<br />
der Szene realisiert werden, damit der Nutzer dasselbe Bewegungsverhalten der<br />
Kamera auch bei e<strong>in</strong>em Klick auf e<strong>in</strong>e freie Fläche feststellt. Weiterh<strong>in</strong> sollen ke<strong>in</strong>e<br />
Verschiebungen des Fokuspunkts der Kamera verwendet werden.<br />
Abbildung 3.10.: Das Koord<strong>in</strong>atensystem des Browsers (schwarz), das aktuelle Koord<strong>in</strong>atensystem<br />
der Kamera (rot), die Änderung der Mausposition<br />
und die daraus berechnete Rotationsachse (blau)<br />
Diese Anforderungen können erfüllt werden, <strong>in</strong>dem das jeweils aktuelle Koord<strong>in</strong>atensystem<br />
um e<strong>in</strong>e <strong>von</strong> der Richtung der Mausbewegung abhängige Rotationsachse<br />
um e<strong>in</strong>en <strong>von</strong> der Länge der Mausbewegung abhängigen W<strong>in</strong>kel rotiert wird. Sei<br />
( x, y) T die Änderung der Mausposition, und ( ˛ right, ˛up, forward) ˛ die Orthonormalbasis<br />
des aktuellen Koord<strong>in</strong>atensystems, so berechnet sich die Rotationsachse axis ˛<br />
als:<br />
Q<br />
R<br />
26<br />
axis<br />
˛˜<br />
c<br />
= c<br />
a<br />
˛<br />
axis =<br />
up x right x<br />
up y right y<br />
up z right z<br />
˛˜<br />
axis<br />
|| ˛˜<br />
axis||<br />
d<br />
b ·<br />
Q<br />
a x<br />
y<br />
R<br />
b
3.3. Grafikanzeige zur Laufzeit<br />
Diese Rechnung ergibt sich daraus, dass e<strong>in</strong> zweidimensionales Orthonormalsystem<br />
<strong>in</strong> der Ebene des Bildschirms die Basis ( ˛ right, ≠ ˛up) hat, denn im Browser zeigt die<br />
y-Achse nach unten und der Ursprung liegt <strong>in</strong> der oberen l<strong>in</strong>ken Ecke. Der Vektor<br />
( x, y) T , der e<strong>in</strong>e Bewegung um die gesuchte Rotationsachse darstellt, sollte<br />
senkrecht auf dieser stehen. Der Vektor (≠ y, x) T <strong>in</strong> diesem System erfüllt diese<br />
Bed<strong>in</strong>gung. Durch e<strong>in</strong>e Basistransformation erhält man aus diesem den Vektor axis. ˛<br />
Wird nun e<strong>in</strong> <strong>von</strong> der Länge des Vektors ( x, y) T abhängiger W<strong>in</strong>kel – gewählt,<br />
kann das aktuelle Koord<strong>in</strong>atensystem nach jeder Mausbewegung rotiert werden. Dies<br />
geschieht durch Multiplikation der Basisvektoren mit e<strong>in</strong>er Rotationsmatrix A und<br />
der Verwendung e<strong>in</strong>er aus diesen Basisvektoren berechnetes View-Matrix.<br />
Dabei gilt:<br />
mit:<br />
A =<br />
Q<br />
c<br />
a<br />
x 2 · (1 ≠ c)+c x· y · (1 ≠ c) ≠ z · s x· z · (1 ≠ c)+y · s<br />
x · y · (1 ≠ c)+z · s y 2 · (1 ≠ c)+c y· z · (1 ≠ c) ≠ x · s<br />
x · z · (1 ≠ c) ≠ y · s y· z · (1 ≠ c)+x · s z 2 · (1 ≠ c)+c<br />
(x, y, z) T = ˛<br />
axis, s = s<strong>in</strong>(–) und c =cos(–)<br />
3.3. Grafikanzeige zur Laufzeit<br />
Wie <strong>in</strong> Abschnitt 3.1.2 begründet, soll die folgende Funktionssignatur zur Darstellung<br />
der Szene zur Laufzeit verwendet werden:<br />
1 <strong>in</strong>t gr3_drawimage( float xm<strong>in</strong> , float xmax , float ym<strong>in</strong> , float ymax ,<br />
2 <strong>in</strong>t width , <strong>in</strong>t height , <strong>in</strong>t drawable_type) ;<br />
List<strong>in</strong>g 3.14: Funktion zum Zeichnen <strong>in</strong> e<strong>in</strong> beliebiges Ziel mit festgelegten Optionen<br />
ymax<br />
ym<strong>in</strong><br />
xm<strong>in</strong><br />
height<br />
width<br />
xmax<br />
Abbildung 3.11.: Zeichenbereich <strong>von</strong> gr3_drawimage im Anwendungsfenster<br />
R<br />
d<br />
b<br />
27
Kapitel 3. Realisierung<br />
Anhand des drawable_type-Parameters kann unterschieden werden, mit welchem<br />
Verfahren gezeichnet werden soll. Die anderen Parameter geben die Position der Grafik<br />
im Zeichenbereich des jeweiligen Toolkits o. Ä., und die gewünschte Auflösung<br />
im Fall e<strong>in</strong>er Rastergrafik. Im Rahmen dieser Arbeit wurde dies <strong>in</strong> zwei Systemen<br />
implementiert: Zum e<strong>in</strong>en <strong>in</strong> GKS/GR, zum anderen <strong>in</strong> OpenGL.<br />
3.3.1. Zeichnen <strong>von</strong> Pixmaps mit der GR-Bibliothek<br />
Die <strong>Integration</strong> <strong>von</strong> GR3 <strong>in</strong> GR kann als Zeichnen e<strong>in</strong>er Pixmap realisiert werden.<br />
Das Graphische Kernsystem unterstützt Rastergrafiken nur <strong>in</strong> Form e<strong>in</strong>er Farbmatrix,<br />
Cell Array genannt[3]. Die GR-Bibliothek bietet e<strong>in</strong>e darauf aufbauende Funktion für<br />
allgeme<strong>in</strong>e Rastergrafiken:<br />
1 <strong>in</strong>t gr_drawimage( float xm<strong>in</strong> , float xmax , float ym<strong>in</strong> , float ymax ,<br />
2 <strong>in</strong>t width , <strong>in</strong>t height , <strong>in</strong>t pixels);<br />
List<strong>in</strong>g 3.15: Funktion zum Zeichnen e<strong>in</strong>er Rastergrafik mit GR<br />
Unter Verwendung dieser Funktion kann gr3_drawimage als e<strong>in</strong>e Komb<strong>in</strong>ation aus<br />
gr3_getimage und gr_drawimage realisiert wurden, d. h. es wird e<strong>in</strong>e Rastergrafik<br />
erstellt und die GR3-Implementierung übernimmt die Darstellung im GKS.<br />
Da GR sicherstellt, dass das GKS <strong>in</strong>itialisiert wird, kann diese Funktion ohne Vorbed<strong>in</strong>gungen<br />
genutzt werden. Falls die Anwendung selbst das GKS oder GR verwendet<br />
und <strong>in</strong>itialisiert, zeichnet GR3 <strong>in</strong> dieselbe GKS-Workstation, ansonsten wird durch<br />
GR automatische e<strong>in</strong>e neue Workstation geö net.<br />
28<br />
Abbildung 3.12.: GKS-Fenster (X11-Treiber) mit <strong>2D</strong>- und <strong>3D</strong>-Inhalten
3.3.2. <strong>Integration</strong> <strong>in</strong> OpenGL-Anwendungen<br />
3.4. Erstellung e<strong>in</strong>er Anb<strong>in</strong>dung für Python<br />
Bei der Implementierung der Funktion gr3_drawimage für OpenGL, gibt es zwei<br />
Möglichkeiten die Szene darzustellen:<br />
1. Zeichnen e<strong>in</strong>er Rastergrafik als <strong>2D</strong>-Inhalt im dreidimensionalen Raum (Billboard<strong>in</strong>g),<br />
oder<br />
2. Zeichnen der Szenen als <strong>3D</strong>-Objekte, unter Beibehaltung der Tiefen<strong>in</strong>formationen.<br />
Der erste Ansatz erlaubt das E<strong>in</strong>b<strong>in</strong>den <strong>von</strong> mit Raytrac<strong>in</strong>g erstellten Rastergrafiken<br />
oder Antialias<strong>in</strong>g, jedoch gehen die Tiefen<strong>in</strong>formationen verloren. Behält man diese<br />
bei, können weitere <strong>2D</strong>- oder <strong>3D</strong>-Objekte <strong>in</strong> die Szene e<strong>in</strong>gefügt werden, nicht nur<br />
davor oder dah<strong>in</strong>ter. Da es beispielsweise gewünscht se<strong>in</strong> könnte Beschriftungen an<br />
e<strong>in</strong>zelne Objekte <strong>in</strong> e<strong>in</strong>er Szene anzufügen, ohne das diese „über“ der gesamten Szenen<br />
liegen, fiel die Entscheidung zu der zweiten Variante.<br />
Die Parameter width und height werden <strong>in</strong> diesem Fall ignoriert – die Auflösung<br />
der erzeugten Grafik richtet sich nach der Größe des Fensters und der anderen Parameter,<br />
entsprechend der Abbildung auf der vorherigen Seite.<br />
Wie <strong>in</strong> Abschnitt 3.2.2 auf Seite 16 beschrieben, kann der aktuelle OpenGL-Kontext<br />
verwendet werden und anstelle e<strong>in</strong>es Framebu er Objektes kann <strong>in</strong> den Standard-<br />
Framebu er gerendert werden. Alle sonstigen Funktionen zum Zeichnen mit OpenGL<br />
s<strong>in</strong>d vom Zielbereich unabhängig.<br />
3.4. Erstellung e<strong>in</strong>er Anb<strong>in</strong>dung für Python<br />
Wie <strong>in</strong> Abschnitt 3.1 angeführt, war die Möglichkeit die Schnittstelle aus e<strong>in</strong>er anderen<br />
Sprache heraus zu verwenden ebenfalls e<strong>in</strong> Kriterium beim Entwurf des Konzeptes.<br />
Parallel zur Entwicklung der Bibliothek GR3 wurde daher mit gr3.py e<strong>in</strong>e Anb<strong>in</strong>dung<br />
für die Programmiersprache Python entworfen. Dabei handelt es sich um e<strong>in</strong> Python-<br />
Modul, welches e<strong>in</strong>e GR3 ähnliche Schnittstelle anbietet und diese durch Verwendung<br />
der entsprechenden Bibliotheksfunktionen erfüllt.<br />
Zur Erstellung e<strong>in</strong>er solchen Anb<strong>in</strong>dung gibt es zwei Ansätze:<br />
1. Python-Modul <strong>in</strong> Python mit ctypes<br />
2. Python-Extension <strong>in</strong> C<br />
Das Modul ctypes ist Teil der Python Standardbibliothek und ermöglicht die Verwendung<br />
dynamischer Bibliotheken wie GR3 aus Python. Es erlaubt dabei das Laden der<br />
Bibliothek und das Aufrufen <strong>von</strong> solchen, beispielsweise <strong>in</strong> C geschriebenen Funktionen.<br />
Außerdem werden dem Entwickler Hilfen für die Verwendung <strong>von</strong> C-Datentypen<br />
gegeben, um die Argumente entsprechen zu konvertieren 7 , Rückgabewerte zu verarbeiten<br />
und mit Zeigern zu arbeiten.[2, Abschnitt 25.1]<br />
7 E<strong>in</strong> Python str ist beispielsweise nicht vollständig zu e<strong>in</strong>em char * aus C kompatibel.<br />
29
Kapitel 3. Realisierung<br />
E<strong>in</strong>e Python-Extension ist e<strong>in</strong>e <strong>in</strong> C geschriebene Erweiterung zu Python. Aus Python<br />
wie e<strong>in</strong> normales Modul benutzbar, kann e<strong>in</strong>e Extension auf den vollen Funktionsumfang<br />
<strong>von</strong> C zurückgreifen, <strong>in</strong>klusive der Verwendung <strong>von</strong> Bibliotheken wie GR3.<br />
Dabei muss die Python API 8 zum Arbeiten mit Python-Datentypen und zur <strong>in</strong>ternen<br />
Beschreibung des späteren Moduls genutzt werden.[2, Abschnitt 25.2]<br />
Die e<strong>in</strong>fache Benutzung <strong>von</strong> ctypes zur Erstellung e<strong>in</strong>es Wrappers, also e<strong>in</strong>es Moduls<br />
welches nur Python-Funktionen und Datentypen auf GR3, beziehungsweise C<br />
abbildet, führte zur Entscheidung den erstgenannten Lösungsansatz zu verfolgen. Als<br />
Beispiel für den Wrapper dient im folgenden List<strong>in</strong>g die Funktion gr3_setquality.<br />
Die globale Variable _gr3 ist e<strong>in</strong> Handle der Bibliothek, über welches auf die Funktionen<br />
zugegri en werden kann. Der Ganzzahl-Parameter quality wird automatisch<br />
<strong>in</strong> e<strong>in</strong>en C <strong>in</strong>t umgewandelt. Die Fehlerbehandlung, die <strong>in</strong> C über Rückgabewerte<br />
erfolgt, kann <strong>in</strong> Python mit Exceptions vere<strong>in</strong>facht werden.<br />
1 def setquality(quality):<br />
2 global _gr3<br />
3 err = _gr3. gr3_setquality(quality)<br />
4 if err :<br />
5 raise GR3_Exception( err )<br />
List<strong>in</strong>g 3.16: Python-Wrapper für gr3_setquality mit ctypes<br />
8 Die Python API ist e<strong>in</strong>e Programmierschnittstelle, welche die Arbeit mit Python-Objekten aus C<br />
30<br />
heraus ermöglicht[14].
4. Ergebnisse<br />
Die Bibliothek GR3 ist fertig implementiert und wurde im Rahmen des <strong>in</strong> Abschnitt<br />
4.2 vorgestellten Projekts bereits verwendet. Dabei hat sich gezeigt, dass der Programmcode<br />
deutlich vere<strong>in</strong>facht wird und im Umfang abnimmt (ca. 20% weniger<br />
Code nach dem Umstieg auf GR3), während ohne Zusatzaufwand die Unterstützung<br />
für HTML5-Dokumente als Ausgabe h<strong>in</strong>zugefügt werden konnte. Die verschiedenen<br />
Ausgabemöglichkeiten wurden abstrahiert und durch die Verwendung der <strong>in</strong> [15] vorgestellten<br />
Techniken ist die Bibliothek plattformunabhängig.<br />
In diesem Kapitel soll zum e<strong>in</strong>en exemplarisch die Benutzung der GR3-Schnittstelle<br />
demonstriert werden und zum anderen wird die <strong>Integration</strong> der GR3 Funktionalität<br />
<strong>in</strong> e<strong>in</strong>e komplexe, <strong>in</strong>teraktive Anwendung vorgestellt. E<strong>in</strong>e vollständige Funktionsreferenz<br />
ist im Anhang A.3 zu f<strong>in</strong>den. Die zwei im folgenden Abschnitt erläuterten<br />
Beispiele s<strong>in</strong>d <strong>in</strong> Anhang B.2 vollständig aufgeführt.<br />
4.1. Benutzung der Schnittstelle<br />
4.1.1. E<strong>in</strong> e<strong>in</strong>faches Beispiel: Visualisierung dreier Kugeln<br />
Das im Folgenden vorgestellte Beispielprogramm zeigt die grundlegende Benutzung<br />
<strong>von</strong> GR3 <strong>in</strong> C. Als erstes steht das Grundgerüst des Programms: E<strong>in</strong>b<strong>in</strong>den der<br />
Header-Datei gr3.h, die Initialisierung und die Freigabe <strong>von</strong> GR3. Während des Aufrufs<br />
<strong>von</strong> gr3_<strong>in</strong>it wird e<strong>in</strong> OpenGL-Kontext und e<strong>in</strong> Framebu er Objekt erstellt.<br />
Diese werden beim Auruf <strong>von</strong> gr3_term<strong>in</strong>ate wieder freigegeben.<br />
1 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude <br />
3<br />
4 <strong>in</strong>t ma<strong>in</strong>( void) {<br />
5 <strong>in</strong>t <strong>in</strong>it_attrs [] = {GR3_IA_END_OF_LIST};<br />
6 <strong>in</strong>t err = gr3_<strong>in</strong>it(<strong>in</strong>it_attrs);<br />
7 if (err) {<br />
8 fpr<strong>in</strong>tf(stderr ," Failed to <strong>in</strong>itialize GR3: %s \n" ,<br />
gr3_geterrorstr<strong>in</strong>g(err));<br />
9 return 1;<br />
10 }<br />
11 / ... /<br />
28 gr3_term<strong>in</strong>ate () ;<br />
29 return 0;<br />
30 }<br />
List<strong>in</strong>g 4.1: Initialisierung und Freigabe <strong>von</strong> GR3<br />
31
Kapitel 4. Ergebnisse<br />
Soll e<strong>in</strong>e Szene beschrieben werden, müssen deren globalen Eigenschaften gesetzt werden.<br />
Die Eigenschaften der Kamera müssen <strong>in</strong> jedem Programm festgelegt werden.<br />
Wird die H<strong>in</strong>tergrundfarbe nicht festgelegt, wird Schwarz (0, 0, 0, 1) verwendet. In<br />
diesem Beispiel wird stattdessen e<strong>in</strong> transparenter H<strong>in</strong>tergrund verwendet.<br />
11 / H<strong>in</strong>tergrundfarbe : Rot , Grün , Blau , Alpha /<br />
12 gr3_setbackgroundcolor (0 , 0, 0, 0) ;<br />
13 / Projektionsparameter : vertikales Sichtfeld <strong>in</strong> Grad , Nah≠ und<br />
14 Fern≠Clipp<strong>in</strong>g≠Abstand /<br />
15 gr3_setcameraprojectionparameters(45, 1, 100) ;<br />
16 / Kameraposition , Fokuspunkt , up≠Vektor /<br />
17 gr3_cameralookat (0 ,0 ,3 , 0 ,0 ,0 , 0 ,1 ,0) ;<br />
List<strong>in</strong>g 4.2: Setzen <strong>von</strong> globalen Eigenschaften<br />
Nun müssen die Objekte der Szene beschrieben werden. Für Kugeln, Zyl<strong>in</strong>der und<br />
Kegel stehen Hilfsfunktionen zur Verfügung, welche das Zeichnen dieser Körper erleichtern.<br />
Dabei müssen die Anzahl der zu zeichnenden Objekte und mehrere Eigenschaften<br />
(z. B. Positionen, Farben und Radien) als Parameter angegeben werden. Drei<br />
Kugeln lassen sich beispielsweise wie folgt zur Szene h<strong>in</strong>zufügen:<br />
18 {<br />
19 float positions [] = {≠2,0,0, 0,0,0, 2,0,0};<br />
20 float colors [] = {1,0,0, 0,1,0, 0,0,1};<br />
21 float radii [] = {1,1,1};<br />
22 gr3_drawspheremesh (3 , positions , colors , radii ) ;<br />
23 }<br />
List<strong>in</strong>g 4.3: H<strong>in</strong>zufügen <strong>von</strong> Kugeln zur Szene<br />
Abschließend kann die Szene angezeigt oder exportiert werden. Der folgende Code exportiert<br />
die Szene mit der Auflößung 3000◊1000 <strong>in</strong> e<strong>in</strong>e png-Datei unter Verwendung<br />
<strong>von</strong> OpenGL mit vierfachem Supersampl<strong>in</strong>g Antialias<strong>in</strong>g.<br />
24 gr3_setquality(GR3_QUALITY_OPENGL_4X_SSAA) ;<br />
25 gr3_export(" image . png" ,3000,1000) ;<br />
List<strong>in</strong>g 4.4: Exportieren der Szene <strong>in</strong> e<strong>in</strong>e PNG-Datei<br />
Abbildung 4.1 zeigt die Ausgabe dieses Programms:<br />
32<br />
Abbildung 4.1.: Die erzeugte Grafik
4.1. Benutzung der Schnittstelle<br />
4.1.2. E<strong>in</strong> komplexes Beispiel: E<strong>in</strong>e Funktion als <strong>3D</strong>-Fläche<br />
Als zweites Beispiel soll e<strong>in</strong>e Funktion f(x, y) :R 2 æ R dargestellt werden. Dazu<br />
muss e<strong>in</strong> Dreiecksgitter erstellt werden. Für die Funktion:<br />
gilt:<br />
f(x, y) = s<strong>in</strong>( 4<br />
9 x2 )+ y2<br />
9<br />
Q<br />
Òf (x, y) = a<br />
ˆf<br />
ˆx<br />
ˆf<br />
ˆy<br />
R<br />
Q<br />
b = a<br />
cos( 4<br />
9 x2 ) · 8<br />
9 x<br />
2<br />
9 y<br />
Bildet man daraus e<strong>in</strong>e Fläche im R3 , um diese darzustellen, ist der Normalenvektor<br />
jedes Punkts:<br />
˛n(x, y) = ˛ñ(x, y)<br />
||˛ñ(x, y)|| mit Q R<br />
c<br />
˛ñ(x, y) = c<br />
a<br />
d<br />
b<br />
R<br />
b<br />
≠ ˆf<br />
ˆx<br />
≠ ˆf<br />
ˆy<br />
1<br />
Dies s<strong>in</strong>d alle Informationen, die zur Darstellung benötigt werden. Diese Funktionen<br />
werden entsprechend als C Funktionen implementiert, sodass sie im Rahmen der<br />
Visualisierung verwendet werden können.<br />
5 float f(float x, float y) {<br />
6 return s<strong>in</strong>(x x/2.25) + y y/9.0;<br />
7 }<br />
8<br />
9 float dfdx( float x, float y) {<br />
10 return cos(x x/2.25) 2 x/2.25;<br />
11 }<br />
12<br />
13 float dfdy( float x, float y) {<br />
14 return 2 y/9.0;<br />
15 }<br />
16<br />
17 float normalize( float vec) {<br />
18 float tmp = 0 ;<br />
19 <strong>in</strong>t i;<br />
20 for (i = 0; i < 3; i++) tmp += vec[i] vec [ i ];<br />
21 tmp = s q r t (tmp) ;<br />
22 for (i = 0; i < 3; i++) vec[i]/=tmp;<br />
23 return vec ;<br />
24 }<br />
25<br />
26 void transform( <strong>in</strong>t x, <strong>in</strong>t y, float new_x , float new_y) {<br />
27 new_x = ( x≠50) /10.0;<br />
28 new_y = ( y≠5) ;<br />
29 }<br />
List<strong>in</strong>g 4.5: f(x, y), ˆf<br />
ˆx<br />
ˆf<br />
, , e<strong>in</strong>e Funktion zur Normalisierung <strong>von</strong> Vektoren und e<strong>in</strong>e<br />
ˆy<br />
Funktion zur Transformation der Intervalle [0; 100] für x und [0;10] für y<br />
auf [-5;5]<br />
33
Kapitel 4. Ergebnisse<br />
E<strong>in</strong> großer Teil des im vorherigen Beispiel gezeigten Codes kann identisch übernommen<br />
werden. Der entscheidende Unterschied liegt <strong>in</strong> den Objekten der Szene. Anstelle<br />
der drei Kugeln <strong>in</strong> List<strong>in</strong>g 4.3 muss e<strong>in</strong> allgeme<strong>in</strong>es Dreiecksgitter erstellt und zur<br />
Szene h<strong>in</strong>zugefügt werden.<br />
Dazu müssen die Ortsvektoren, Normalen und Farbwerte der Oberfläche berechnet<br />
werden. In diesem Beispiel wird e<strong>in</strong> 100 ◊ 10-Rechtecksgitter verwendet, bei dem<br />
jedes Rechteck aus zwei Dreiecken zusammengesetzt wird (also <strong>in</strong> der Summe 6000<br />
Eckpunkte). Diese Eckpunkte werden auf das Intervall [-5;5] transformiert, es werden<br />
f(x, y) und ˛n (x, y) berechnet und <strong>in</strong> zusammenhängende Speicherbereiche geschrieben.<br />
Anschließend werden diese an die Funktion gr3_createmesh übergeben: E<strong>in</strong><br />
neues Dreiecksgitter wird def<strong>in</strong>iert. Anhand der <strong>in</strong>t-Variablen mesh, deren Adresse<br />
ebenfalls an gr3_createmesh übergeben und <strong>von</strong> der Funktion gesetzt wird, kann dieses<br />
Dreiecksgitter verwendet werden. Nachdem das Dreiecksgitter mit der Funktion<br />
gr3_drawmesh zur Szene h<strong>in</strong>zugefügt wurde, kann es mit gr3_deletemesh gelöscht<br />
werden. Durch e<strong>in</strong>en Referenzzähler wird dabei sichergestellt, dass die <strong>in</strong>ternen Daten<br />
erst dann tatsächlich freigegeben werden, wenn das Gitter nicht mehr Teil der Szene<br />
ist, z. B. nach e<strong>in</strong>en Aufruf <strong>von</strong> gr3_clear.<br />
38 <strong>in</strong>t mesh ;<br />
39 <strong>in</strong>t i, x, y;<br />
40 <strong>in</strong>t dx [ 6 ] = {0 ,1 ,1 ,0 ,1 ,0};<br />
41 <strong>in</strong>t dy [ 6 ] = {0 ,0 ,1 ,0 ,1 ,1};<br />
42 float mesh_vertices [1000 6 3];<br />
43 float mesh_normals [1000 6 3];<br />
44 float mesh_colors [1000 6 3];<br />
45 float positions [3] = {0,0,0};<br />
46 float directions [3] = {0,0,1};<br />
47 float ups [3] = {0 ,1 ,0};<br />
48 float colors [3] = {1,1,1};<br />
49 float scales [3] = {1,1,1};<br />
50 for (x = 0; x < 100; x++) {<br />
51 for (y = 0; y < 10; y++) {<br />
52 for (i = 0; i < 6; i++) {<br />
53 <strong>in</strong>t ix = x+dx[ i ];<br />
54 <strong>in</strong>t iy = y+dy[ i ];<br />
55 float fx , fy ;<br />
56 transform(ix , iy ,&fx,&fy) ;<br />
57 mesh_vertices [(y 100+x) 6 3+ i 3+0] = fx ;<br />
58 mesh_vertices [(y 100+x) 6 3+ i 3+1] = fy ;<br />
59 mesh_vertices [(y 100+x) 6 3+ i 3+2] = f (fx , fy ) ;<br />
60<br />
61 mesh_normals [( y 100+x) 6 3+ i 3+0] = ≠dfdx(fx , fy ) ;<br />
62 mesh_normals [( y 100+x) 6 3+ i 3+1] = ≠dfdy(fx , fy ) ;<br />
63 mesh_normals [( y 100+x) 6 3+ i 3+2] = 1;<br />
64 normalize(mesh_normals+(y 100+x) 6 3+ i 3+0) ;<br />
65<br />
66 mesh_colors [(y 100+x) 6 3+ i 3+0] = 1;<br />
67 mesh_colors [(y 100+x) 6 3+ i 3+1] = 1;<br />
68 mesh_colors [(y 100+x) 6 3+ i 3+2] = 1;<br />
34
69 }<br />
70 }<br />
71 }<br />
4.2. Moldyn – E<strong>in</strong> Anwendungsbeispiel<br />
72 gr3_createmesh(&mesh , 1000 6, mesh_vertices , mesh_normals,<br />
mesh_colors) ;<br />
73 gr3_drawmesh(mesh ,1 , positions , directions , ups , colors , scales ) ;<br />
74 gr3_deletemesh(mesh) ;<br />
List<strong>in</strong>g 4.6: Darstellung e<strong>in</strong>er Funktion als Dreiecksgitter<br />
Abbildung 4.2.: Die Funktion f(x, y) = s<strong>in</strong>( 4<br />
9x2 )+ y2<br />
9<br />
für x, y œ [≠5; 5]<br />
Abbildung 4.2 zeigt die Ausgabe als Rastergrafik – exportiert durch den Code aus<br />
List<strong>in</strong>g 4.4. Ist e<strong>in</strong>e alternative Ausgabe gewünscht, beispielsweise e<strong>in</strong> HTML5-Dokument,<br />
reicht es die Parameter der Funktion gr3_export anzupassen:<br />
1 gr3_export(" graph . html" ,800,800) ;<br />
List<strong>in</strong>g 4.7: Exportieren der Szene <strong>in</strong> e<strong>in</strong> HTML5-Dokument<br />
4.2. Moldyn – E<strong>in</strong> Anwendungsbeispiel<br />
Moldyn ist e<strong>in</strong>e Anwendung zur Visualisierung <strong>von</strong> Molekülen im balls-and-sticks-<br />
Stil 1 . Seit Ende der 80er Jahre <strong>von</strong> Josef He<strong>in</strong>en im Institut für Festkörperforschung<br />
1 Atome werden als Kugeln (balls) und Atomb<strong>in</strong>dungen als Zyl<strong>in</strong>der (sticks) dargestellt (siehe Ab-<br />
bildung 4.3).<br />
35
Kapitel 4. Ergebnisse<br />
entwickelt, unterstützt das Programm mittlerweile mehrere E<strong>in</strong>- und Ausgabeformate<br />
und ist e<strong>in</strong> nützliches Werkzeug für die Wissenschaftler des Instituts.<br />
Abbildung 4.3.: E<strong>in</strong> Ge-Sb-Te-Phasenwechselmaterial <strong>in</strong> Moldyn (ohne GR3)<br />
Das Programm ist <strong>in</strong> der Programmiersprache C geschrieben und verwendete <strong>2D</strong>-<br />
Zeichenbefehle aus X11, um dreidimensionale Grafiken darzustellen. Um Microsoft<br />
W<strong>in</strong>dows zu unterstützen wurde im Jahr 2000 die Verwendung <strong>von</strong> GDI 2 als Alternative<br />
zu X11 h<strong>in</strong>zugefügt. Im Jahr 2008 wurde Moldyn im Rahmen e<strong>in</strong>er Bachelorarbeit<br />
<strong>von</strong> Alexander Peters[13] so umgeschrieben, dass OpenGL statt X11 und GDI<br />
für die dynamische Anzeige zur Laufzeit verwendet wird. E<strong>in</strong>zelne Bilder können beispielsweise<br />
mit POV-Ray oder GLor erzeugt werden. Um zeitliche Veränderungen<br />
der Moleküle zu zeigen, können aber auch ganze Bilderserien ausgegeben werden, die<br />
dann zu Videos encodiert werden.<br />
Es musste bisher redundanter Visualisierungscode für jedes gewünschte Ausgabeformat<br />
verwendet werden. Dies soll durch den Umstieg auf GR3 nicht mehr nötig se<strong>in</strong><br />
und gleichzeitig soll das aus ca. 2700 Zeilen Code bestehende Programm <strong>in</strong> mehrere<br />
Module aus thematisch zusammengehörenden Funktionen gegliedert werden. Da es<br />
sich um „gewachsene Software“ mit über 20 Jahren Entwicklung handelt, <strong>in</strong> denen<br />
2 Graphics Device Interface<br />
36
4.2. Moldyn – E<strong>in</strong> Anwendungsbeispiel<br />
meist kle<strong>in</strong>e Änderungen gemacht wurden, bestand der erste Schritt dar<strong>in</strong>, den Code<br />
<strong>in</strong> mehrere Dateien aufzuteilen, die <strong>in</strong>haltlich jeweils e<strong>in</strong>en Teilbereich der Funktionalität<br />
abdecken. Dabei wurde der Fokus auf die Trennung der Visualisierung vom<br />
Rest der Anwendung gelegt.<br />
moldyn.c Der größte Teil der Funktionalität ist <strong>in</strong> dieser Datei geblieben: Interpretation<br />
der Programmparameter, E<strong>in</strong>lesen und Analyse <strong>von</strong> E<strong>in</strong>gabedateien und<br />
Steuerung der Anwendung. (ca. 1050 Zeilen)<br />
moldyn_graphics.c Die im Rahmen der Visualisierung anfallenden Aufgaben s<strong>in</strong>d<br />
<strong>in</strong> dieser Datei gelöst: Die Erzeugung <strong>von</strong> Ausgabedateien und die Anzeige zur<br />
Laufzeit <strong>in</strong> e<strong>in</strong>em Anzeigefenster. (ca. 1000 Zeilen)<br />
moldyn_element_<strong>in</strong>formation.c Informationen über die chemischen Elemente, also<br />
deren Namen und anzuzeigende Farben und Atomradien, s<strong>in</strong>d <strong>in</strong> dieser Datei<br />
<strong>in</strong> Form <strong>von</strong> globalen Variablen gespeichert.<br />
moldyn_utilities.c Diese Datei enthält Hilfsfunktionen, wie e<strong>in</strong>e Logg<strong>in</strong>g-Funktion<br />
und die Ausgabe der Benutzungsh<strong>in</strong>weise. (ca.70 Zeilen)<br />
4.2.1. Erstellung und Verwaltung des Anzeigefensters<br />
Das Anzeigefenster <strong>von</strong> Moldyn wird mit GLUT, dem OpenGL Utility Toolkit, erstellt.<br />
GLUT wurde <strong>von</strong> Mark J. Kilgard entwickelt und bietet e<strong>in</strong>e plattformunabhängige<br />
Schnittstelle zum Fenstersystem des jeweiligen Betriebssystems, um Fenster mit e<strong>in</strong>er<br />
OpenGL-Zeichenfläche zu erzeugen und sowohl Maus- als auch Tastature<strong>in</strong>gaben zu<br />
behandeln. GLUT steht unter e<strong>in</strong>er proprietären Lizenz, die ke<strong>in</strong>e Redistribution gestattet,<br />
jedoch gibt es auch freie Implementierungen der Schnittstelle, wie freeglut 3 ,<br />
sodass e<strong>in</strong>e GLUT-Implementierung auf fast allen Systemen <strong>in</strong>stalliert ist, auf denen<br />
auch OpenGL zur Verfügung steht. Die Verwendung <strong>von</strong> GLUT wurde im Rahmen der<br />
Umstellung auf GR3 beibehalten, da GLUT alle Anforderungen <strong>von</strong> Moldyn erfüllt.<br />
Die Ereignisbehandlung <strong>in</strong> GLUT verläuft durch Callback-Funktionen, das heißt<br />
GLUT wird mitgeteilt, welche Funktionen bestimmte Ereignisse behandeln sollen.<br />
Diese werden beim E<strong>in</strong>tritt des Ereignisses aufgerufen. Der Code-Ausschnitt <strong>in</strong> List<strong>in</strong>g<br />
4.8 zeigt die Funktion, welche GLUT <strong>in</strong>itialisiert (Zeile 2 bis 8), e<strong>in</strong> Anzeigefenster<br />
erstellt (Zeile 9 bis 12) und anschließend die Callback-Funktionen setzt (Zeile 14 bis<br />
20).<br />
1 static void moldyn_<strong>in</strong>it_glut( <strong>in</strong>t argcp , char argv , const char<br />
w<strong>in</strong>dow_name) {<br />
2 <strong>in</strong>t i = 0;<br />
3 if (argcp == NULL || argv == NULL) {<br />
4 argcp = &i ;<br />
5 argv = NULL;<br />
6 }<br />
3 http://freeglut.sourceforge.net/<br />
37
Kapitel 4. Ergebnisse<br />
7 glutInit(argcp , argv);<br />
8 glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DOUBLE |<br />
GLUT_DEPTH) ;<br />
9 glutInitW<strong>in</strong>dowSize(w<strong>in</strong>dow_width , w<strong>in</strong>dow_height) ;<br />
10 glutInitW<strong>in</strong>dowPosition(600, 400) ;<br />
11 glutCreateW<strong>in</strong>dow(w<strong>in</strong>dow_name) ;<br />
12 glutDisplayFunc(moldyn_display_callback) ;<br />
13 glutReshapeFunc( reshape ) ;<br />
14 glutMouseFunc(mouse) ;<br />
15 glutMotionFunc(motion) ;<br />
16 glutKeyboardFunc(keyboard) ;<br />
17 glutSpecialFunc(specialKey) ;<br />
18 }<br />
List<strong>in</strong>g 4.8: Erstellen des Anzeigefensters und Setzen der Callback-Funktionen<br />
Nach dem Aufrufen dieser Funktion kann GR3 wie <strong>in</strong> den vorherigen Beispielen <strong>in</strong>itialisiert<br />
werden, dabei wird dann allerd<strong>in</strong>gs ke<strong>in</strong> OpenGL-Kontext mehr erzeugt, sondern<br />
der Kontext des Anzeigefensters verwendet. Ist die Initialisierung abgeschlossen,<br />
wird die Funktion glutMa<strong>in</strong>Loop aufgerufen und damit die Kontrolle der Anwendungen<br />
an GLUT übergeben.<br />
4.2.2. Aufbau e<strong>in</strong>er Szene aus den Moleküldaten<br />
Die Moleküle s<strong>in</strong>d als Kugeln und Zyl<strong>in</strong>der dargestellt, das heißt alle<strong>in</strong> die <strong>in</strong> GR3<br />
vorgefertigten Körper reichen aus, um die Szene zu beschreiben. Die Datenstrukturen<br />
der Atompositionen s<strong>in</strong>d (wie <strong>in</strong> Fortran üblich) als drei Arrays x, y und z, die jeweils<br />
e<strong>in</strong>e Komponente der Vektoren enthielten, gespeichert gewesen. Die bereits existierende<br />
GLor-Zeichenfunktion hat neue Speicherbereiche angelegt und die Informationen<br />
so umkopiert, dass sie im für GLor passenden Format vorlagen. Stattdessen wurden<br />
nun die anderen Funktionen so angepasst, dass sie mit e<strong>in</strong>em Array <strong>von</strong> Vektoren<br />
arbeiten. Dadurch können die Atompositionen direkt an GR3 übergeben werden.<br />
Abhängig <strong>von</strong> e<strong>in</strong>er Option (colors) können entweder die bestehenden Farb<strong>in</strong>formationen<br />
verwendet werden, oder es muss e<strong>in</strong> Array erstellt und mit Weiß (1, 1, 1)<br />
gefüllt werden.<br />
Bevor die Atome zur Szene h<strong>in</strong>zugefügt werden, wird mit der Funktion gr3_clear<br />
die aktuelle Szene gelöscht. Außerdem ist es wichtig, dass die Speicherbereiche, deren<br />
Adressen an die Funktionen <strong>von</strong> GR3 übergeben werden, weiter <strong>von</strong> der Anwendung<br />
verwaltet werden und nicht <strong>von</strong> der Bibliothek. Daher müssen diese, falls sie dynamisch<br />
angelegt wurden, wie <strong>in</strong> Zeile 15 des folgenden Beispiels freigegeben werden.<br />
1 gr3_clear () ;<br />
2 if (num_atoms > 0) {<br />
3 if (colors) {<br />
4 gr3_drawspheremesh(num_atoms, atom_positions , atom_colors ,<br />
atom_radii) ;<br />
5 } else {<br />
38
4.2. Moldyn – E<strong>in</strong> Anwendungsbeispiel<br />
6 float atom_color_replacement = ( float )malloc(num_atoms<br />
sizeof( float) 3) ;<br />
7 if (!atom_color_replacement) {<br />
8 moldyn_error(" Failed to allocate memory for<br />
atom_color_replacement . " );<br />
9 } else {<br />
10 <strong>in</strong>t i;<br />
11 for (i = 0; i < num_atoms 3; i++) {<br />
12 atom_color_replacement [ i ] = 1.0 f ;<br />
13 }<br />
14 gr3_drawspheremesh(num_atoms, atom_positions ,<br />
atom_color_replacement , atom_radii) ;<br />
15 free(atom_color_replacement);<br />
16 }<br />
17 }<br />
18 }<br />
List<strong>in</strong>g 4.9: H<strong>in</strong>zufügen der Atome zur Szene<br />
Ob zwischen zwei Atomen e<strong>in</strong>e B<strong>in</strong>dung (bond) besteht, wird im Rahmen der Analyse<br />
der E<strong>in</strong>gangsdaten <strong>in</strong> e<strong>in</strong>er Adjazenzmatrix gespeichert. Bevor die B<strong>in</strong>dungen als<br />
Zyl<strong>in</strong>der zur Szene h<strong>in</strong>zugefügt werden können, müssen deren Daten daher <strong>in</strong> e<strong>in</strong>e<br />
entsprechende Form gebracht werden.<br />
Für e<strong>in</strong>e B<strong>in</strong>dung zwischen zwei Atomen an den Positionen ˛ai und ˛aj gilt:<br />
• Position:<br />
• Richtung:<br />
˛<br />
position = ˛ai<br />
˛<br />
direction = ˛aj-˛ai<br />
• Länge: length = || ˛<br />
direction||<br />
• Radius: radius = const.<br />
• Farbe: ˛<br />
color = const.<br />
Bevor diese Informationen zugeordnet werden können, muss allerd<strong>in</strong>gs zuerst die Anzahl<br />
der B<strong>in</strong>dungen bestimmt und genügend Speicher dynamisch angelegt werden:<br />
19 <strong>in</strong>t i, j, k;<br />
20 <strong>in</strong>t num_bonds = 0 ;<br />
21 float bond_positions ;<br />
22 float bond_directions ;<br />
23 float bond_colors ;<br />
24 float bond_radii ;<br />
25 float bond_lengths ;<br />
26<br />
27 for (i = 0; i < num_atoms; i++) {<br />
28 if (atom_numbers[ i ] == 0)<br />
29 cont<strong>in</strong>ue ;<br />
39
Kapitel 4. Ergebnisse<br />
30 for (j = i + 1; j < num_atoms; j++) {<br />
31 if (atom_numbers[ j ] && atom_adjacency_matrix[ i num_atoms+j<br />
]) {<br />
32 num_bonds++;<br />
33 }<br />
34 }<br />
35 }<br />
36<br />
37 bond_positions = ( float ) malloc( sizeof( float) 3 num_bonds) ;<br />
38 bond_directions = ( float ) malloc( sizeof( float) 3 num_bonds) ;<br />
39 bond_colors = ( float ) malloc( sizeof( float) 3 num_bonds) ;<br />
40 bond_radii = ( float ) malloc( sizeof( float) num_bonds) ;<br />
41 bond_lengths = ( float ) malloc( sizeof( float) num_bonds) ;<br />
List<strong>in</strong>g 4.10: H<strong>in</strong>zufügen der Atomb<strong>in</strong>dungen zur Szene (Teil 1)<br />
Anschließend können die angelegten Speicherbereiche mit den Informationen gefüllt,<br />
an die Funktion gr3_drawcyl<strong>in</strong>dermesh übergeben und wieder freigegeben werden:<br />
42 for (i = 0, j = 0, k = 0; i < num_atoms; i++) {<br />
43 if (atom_numbers[ i ] == 0) {<br />
44 cont<strong>in</strong>ue ;<br />
45 }<br />
46 for (j = i + 1; j < num_atoms; j++) {<br />
47 if (atom_numbers[ j ] && atom_adjacency_matrix[ i num_atoms+j<br />
]) {<br />
48 double vx , vy , vz ;<br />
49 bond_positions [3 k+0] = atom_positions [3 i+0];<br />
50 bond_positions [3 k+1] = atom_positions [3 i+1];<br />
51 bond_positions [3 k+2] = atom_positions [3 i+2];<br />
52<br />
53 vx = atom_positions [3 j+0] ≠ atom_positions [3 i+0];<br />
54 vy = atom_positions [3 j+1] ≠ atom_positions [3 i+1];<br />
55 vz = atom_positions [3 j+2] ≠ atom_positions [3 i+2];<br />
56<br />
57 bond_directions [3 k+0] = vx;<br />
58 bond_directions [3 k+1] = vy;<br />
59 bond_directions [3 k+2] = vz ;<br />
60<br />
61 bond_lengths [k] = sqrt (vx vx + vy vy + vz vz) ;<br />
62<br />
63 bond_radii [k] = cyl_rad ;<br />
64<br />
65 bond_colors [3 k+0] = 1;<br />
66 bond_colors [3 k+1] = 1;<br />
67 bond_colors [3 k+2] = 1;<br />
68 k++;<br />
69 }<br />
70 }<br />
71 }<br />
72 gr3_drawcyl<strong>in</strong>dermesh(num_bonds, bond_positions , bond_directions ,<br />
bond_colors , bond_radii , bond_lengths) ;<br />
40
73 free(bond_positions);<br />
74 free(bond_directions);<br />
75 free(bond_colors);<br />
76 free(bond_radii);<br />
77 free(bond_lengths);<br />
4.2. Moldyn – E<strong>in</strong> Anwendungsbeispiel<br />
List<strong>in</strong>g 4.11: H<strong>in</strong>zufügen der Atomb<strong>in</strong>dungen zur Szene (Teil 2)<br />
4.2.3. Darstellung der Moleküle zur Laufzeit<br />
Wann immer das Anzeigefenster neu gezeichnet werden muss, wird e<strong>in</strong>e Callback-<br />
Funktion aufgerufen (siehe Zeile 14 <strong>in</strong> List<strong>in</strong>g 4.8). Dies kann zwei Gründe haben:<br />
1. Teilbereiche des Fensters s<strong>in</strong>d durch Überlagerung durch andere Fenster oder<br />
Ähnliches ungültig geworden und die Anwendung wird vom Fenstersystem darüber<br />
<strong>in</strong>formiert. GLUT ruft <strong>in</strong> diesem Fall automatisch die Callback-Funktion<br />
auf.<br />
2. Durch Nutzere<strong>in</strong>gaben o. Ä. hat sich der darzustellende Inhalt geändert, beispielsweise<br />
soll die Kamera bewegt werden. In diesem Fall muss, aus der für die<br />
Änderung zuständigen Funktion, die Funktion glutPostRedisplay aufgerufen<br />
werden, welche nach Abarbeiten der anstehenden E<strong>in</strong>gaben e<strong>in</strong> Neuzeichnen<br />
auslöst.<br />
3 /2⇡<br />
0⇡<br />
✓<br />
r<br />
(r, ,✓)<br />
1⇡<br />
1 /2⇡<br />
Abbildung 4.4.: E<strong>in</strong> Punkt (r,„,◊) <strong>in</strong> Kugelkoord<strong>in</strong>aten<br />
41
Kapitel 4. Ergebnisse<br />
Innerhalb der mit glutDisplayFunc gesetzten Callback-Funktion kann die Funktion<br />
gr3_drawimage verwendet werden, dazu müssen jedoch die aktuellen Kameraeigenschaften<br />
gesetzt werden.<br />
Moldyn nutzt e<strong>in</strong> sehr e<strong>in</strong>faches Rotationsmodell, welches mit Kugelkoord<strong>in</strong>aten<br />
arbeitet. Dabei liegt die Kamera auf e<strong>in</strong>em Punkt, welcher auf der Oberfläche e<strong>in</strong>er<br />
Kugel positioniert ist. Die Position wird dabei als Radius der Kugel (r), Azimutw<strong>in</strong>kel<br />
„ 4 und Polarw<strong>in</strong>kel ◊ 5 ausgedrückt. Diese Angaben müssen <strong>in</strong> das Kameramodell<br />
<strong>von</strong> GR3 umgerechnet werden.<br />
1 double x, y, z, fx , fy , fz , ux, uy, uz;<br />
2 double c1 = cos ( torad(≠ rotation));<br />
3 double s1 = s<strong>in</strong> (torad(≠ rotation));<br />
4 double c2 = cos ( torad(≠ tilt));<br />
5 double s2 = s<strong>in</strong> (torad(≠ tilt));<br />
6 / Kamera≠Position : /<br />
7 x = ≠c1 xeye + s1 zeye ;<br />
8 y = s1 s2 xeye ≠ c2 yeye + s2 c1 zeye ;<br />
9 z = ≠c2 s1 xeye ≠ s2 yeye ≠ c2 c1 zeye ;<br />
10 / forward≠Vektor : /<br />
11 fx = x + s1 ;<br />
12 fy = y + s2 c1 ;<br />
13 fz = z ≠ c2 c1 ;<br />
14 / up≠Vektor : /<br />
15 ux = 0;<br />
16 uy = c2 ;<br />
17 uz = s2 ;<br />
18<br />
19 gr3_cameralookat(x, y, z , fx , fy , fz , ux, uy, uz) ;<br />
List<strong>in</strong>g 4.12: Umrechnen des Koord<strong>in</strong>atensystems der Kamera<br />
Anschließend kann durch e<strong>in</strong>en Aufruf <strong>von</strong> gr3_drawimage mit dem drawable_type<br />
GR3_DRAWABLE_OPENGL die Grafik <strong>in</strong>s Anzeigefenster gezeichnet werden.<br />
In Moldyn sollen zusätzlich zu den Molekülen auch weitere Darstellungselemente,<br />
wie beispielsweise Atombeschriftungen, angezeigt werden. Diese können mit GR3 nicht<br />
dargestellt werden, jedoch erlaubt die <strong>in</strong> Abschnitt 3.3.2 beschriebene Vorgehensweise<br />
e<strong>in</strong>e <strong>Integration</strong> dieser Elemente <strong>in</strong> die angezeigte Szene. Durch die im Tiefenpu er<br />
enthaltenen Informationen werden nach dem Aufruf <strong>von</strong> gr3_drawimage <strong>in</strong> die Szene<br />
e<strong>in</strong>gefügte Objekte korrekt vor bzw. h<strong>in</strong>ter bereits gezeichneten Körpern angezeigt.<br />
1 gr3_drawimage (0 , w<strong>in</strong>dow_width ,<br />
2 0, w<strong>in</strong>dow_height,<br />
3 w<strong>in</strong>dow_width , w<strong>in</strong>dow_height ,<br />
4 GR3_DRAWABLE_OPENGL) ;<br />
List<strong>in</strong>g 4.13: Zeichnen der Szene<br />
Wenn das Zeichnen abgeschlossen ist, kann mit der Funktion glutSwapBuffers das<br />
Anzeigefenster aktualisiert werden. Üblicherweise wird nicht direkt auf der Oberfläche<br />
4 <strong>in</strong> Moldyn rotation genannt<br />
5 <strong>in</strong> Moldyn tilt genannt<br />
42
4.2. Moldyn – E<strong>in</strong> Anwendungsbeispiel<br />
des Fensters gezeichnet, sondern auf e<strong>in</strong>em zweiten Framebu er. Durch die Funktion<br />
glutSwapBuffers werden Vordergrund- und H<strong>in</strong>tergrund-Bu er ausgetauscht (swap).<br />
Durch dieses als Double Bu er<strong>in</strong>g bezeichnete Vorgehen wird e<strong>in</strong> Flackern während<br />
des Neuzeichnens verh<strong>in</strong>dert. Außerdem gibt es plattformabhängige Funktionen, die es<br />
dem Anwendungsentwickler erlauben diesen Austauschprozess mit der Anzeige e<strong>in</strong>es<br />
Frames auf dem Monitor zu synchronisieren (vertical sync), um tear<strong>in</strong>g, e<strong>in</strong> Darstellungsfehler,<br />
der das angezeigte Bild <strong>in</strong> e<strong>in</strong>e aktuelle und e<strong>in</strong>e alte Hälfte zerteilt, zu<br />
verh<strong>in</strong>dern.<br />
Abbildung 4.5.: E<strong>in</strong> Ge-Sb-Te-Phasenwechselmaterial <strong>in</strong> Moldyn (mit GR3)<br />
4.2.4. Export <strong>in</strong> Ausgabedateien<br />
Die Namen der Ausgabedateien <strong>von</strong> Moldyn haben das Format:<br />
.<br />
43
Kapitel 4. Ergebnisse<br />
In Dateien, welche Moleküle bzw. Atome zu mehr als e<strong>in</strong>em Zeitpunkt enthalten,<br />
s<strong>in</strong>d diese als Blöcke angeordnet. E<strong>in</strong>e PNG-Grafik für den ersten Block e<strong>in</strong>er Datei<br />
Molecule.xyz hieße dementsprechend Molecule0001.png.<br />
Grundsätzlich gesehen könnte direkt die Funktion gr3_export zur Ausgabe der<br />
Szene <strong>in</strong> e<strong>in</strong>e Datei verwendet werden. Um die dynamische Erstellung des Date<strong>in</strong>amens<br />
zentral zu lösen, wurde jedoch die Funktion moldyn_export_ implementiert.<br />
Sie setzt den gewünschten Date<strong>in</strong>amen <strong>in</strong> e<strong>in</strong>em bestehenden char-Array zusammen<br />
und ruft die Funktion gr3_export auf, welche die Szene entsprechend exportiert.<br />
Dadurch wird das Speichern e<strong>in</strong>er Grafik deutlich vere<strong>in</strong>facht.<br />
1 static void moldyn_export_( <strong>in</strong>t type , <strong>in</strong>t width , <strong>in</strong>t height) {<br />
2 <strong>in</strong>t err ;<br />
3 char cp ;<br />
4 char extension ;<br />
5<br />
6 switch (type) {<br />
7 case MOLDYN_EXPORT_TO_JPEG:<br />
8 extension = " jpg" ;<br />
9 break ;<br />
10 case MOLDYN_EXPORT_TO_PNG:<br />
11 extension = " png" ;<br />
12 break ;<br />
13 case MOLDYN_EXPORT_TO_POV:<br />
14 extension = " pov" ;<br />
15 break ;<br />
16 case MOLDYN_EXPORT_TO_HTML:<br />
17 extension = " html" ;<br />
18 break ;<br />
19 }<br />
20<br />
21 spr<strong>in</strong>tf(path , "%s%4d.%s " , name, current_cycle , extension) ;<br />
22 for (cp = path; cp ; cp++) {<br />
23 if ( cp == ’ ’ ) {<br />
24 cp = ’ 0 ’ ;<br />
25 }<br />
26 }<br />
27<br />
28 err = gr3_export(path , width , height);<br />
29 moldyn_log(path) ;<br />
30 if (err) {<br />
31 moldyn_error( gr3_geterrorstr<strong>in</strong>g ( err ) ) ;<br />
32 }<br />
33 }<br />
List<strong>in</strong>g 4.14: Export der Szene <strong>in</strong> e<strong>in</strong>e Datei<br />
4.2.5. Zusammenfassung der <strong>Integration</strong> <strong>von</strong> GR3 <strong>in</strong> MolDyn<br />
An der Umstellung <strong>von</strong> e<strong>in</strong>zelnen Visualisierungslösungen zu GR3 hat sich gezeigt,<br />
dass das Konzept der Bibliothek aufgegangen ist. Es konnte e<strong>in</strong>e große Menge re-<br />
44
4.3. Verwendung des Python-Wrappers<br />
dundanten Codes entfernt und so die Wartbarkeit des Programms vere<strong>in</strong>facht werden.<br />
Auch die Komb<strong>in</strong>ation aus der mit GR3 beschriebenen Szene und zusätzlichen,<br />
mit OpenGL dargestellten Inhalten hat dadurch, dass der Tiefenbu er des Standard-<br />
Framebu ers verwendet wurde, ohne Probleme funktioniert.<br />
E<strong>in</strong>e Funktionalität, welche aus Sicht des Anwendungsentwicklers erstrebenswert<br />
wäre, ist die Möglichkeit L<strong>in</strong>ien und Texte <strong>in</strong> GR3 darzustellen, da diese Elemente <strong>in</strong><br />
der aktuellen Situation nachträglich <strong>in</strong> das Anzeigefenster e<strong>in</strong>gefügt werden müssen<br />
und nicht oder nur sehr umständlich <strong>in</strong> andere Ausgaben e<strong>in</strong>gefügt werden können.<br />
4.3. Verwendung des Python-Wrappers<br />
Das erste Beispiel aus 4.1.1 (vollständig <strong>in</strong> List<strong>in</strong>g B.1 auf Seite 63 zu f<strong>in</strong>den) kann<br />
<strong>in</strong> Python mit wenigen Codeänderungen umgesetzt werden. Die Verwendung des<br />
Python-Moduls erfolgt dabei ähnlich zur Benutzung der Bibliothek <strong>in</strong> C. Allerd<strong>in</strong>gs<br />
gibt es mehrere Unterschiede:<br />
• Das Präfix gr3_, dass <strong>in</strong> C verwendet wurde, wird durch gr3. ersetzt, da die<br />
Funktionen im Namensraum des Moduls liegen.<br />
• Anstelle <strong>von</strong> Arrays können Python-Datenstrukturen wie Listen, Tupel und<br />
auch verschachtelte Komb<strong>in</strong>ationen daraus verwendet werden. Dabei greift der<br />
Wrapper auf die e zienten, n-dimensionalen Datenstrukturen des Moduls numpy<br />
(http://numpy.scipy.org/) zurück; diese werden daher auch unterstützt.<br />
• Die Fehlerbehandlung ist über die Exception-Klasse GR3_Exception realisiert.<br />
1 import gr3<br />
2<br />
3 try :<br />
4 gr3 . <strong>in</strong>it ()<br />
5 gr3 . setbackgroundcolor (0 ,0 ,0 ,0)<br />
6 gr3 . setcameraprojectionparameters (6 , 1, 100)<br />
7 gr3 . cameralookat (0 ,0 ,20 , 0 ,0 ,0 , 0 ,1 ,0)<br />
8 positions = [(≠2,0,0), (0,0,0), (2,0,0)]<br />
9 colors = [(1 ,0 ,0) , (0,1,0) , (0,0,1) ]<br />
10 radii = [1 ,1 ,1]<br />
11 gr3 . drawspheremesh(3 , positions , colors , radii )<br />
12 gr3 . setquality (gr3 .GR3_Quality.GR3_QUALITY_OPENGL_4X_SSAA)<br />
13 gr3 . export(" image . png" ,3000,1000)<br />
14 gr3 . term<strong>in</strong>ate ()<br />
15 except gr3 .GR3_Exception as e:<br />
16 pr<strong>in</strong>t "GR3 error : " , gr3 . geterrorstr<strong>in</strong>g (e)<br />
List<strong>in</strong>g 4.15: Beispiel 1 <strong>in</strong> Python<br />
45
5. Ausblick<br />
Wie <strong>in</strong> Abschnitt 4.2.5 bereits angeführt, wäre e<strong>in</strong>e Erweiterung <strong>von</strong> GR3 um bestimmte<br />
Elemente, wie Punkte, L<strong>in</strong>ien und im dreidimensionalen Raum positionierbaren<br />
Text, s<strong>in</strong>nvoll. E<strong>in</strong> denkbarer Ansatz zur <strong>Integration</strong> <strong>von</strong> Texten wäre es, allgeme<strong>in</strong><br />
<strong>2D</strong>-Rastergrafiken <strong>in</strong> e<strong>in</strong>e Szene zu <strong>in</strong>tegrieren, welche entweder stets zum<br />
Betrachter (Billboard<strong>in</strong>g) gerichtet oder fest im Raum positioniert und ausgerichtet<br />
s<strong>in</strong>d.<br />
In Abschnitt 2.2 wurde erwähnt, dass es neben den <strong>von</strong> GR3 visualisierten Vektorgrafiken<br />
<strong>in</strong> Form <strong>von</strong> Dreiecksgittern auch Volumengrafiken gibt. Um e<strong>in</strong>e solche<br />
Volumengrafik zu visualisieren, wird oft e<strong>in</strong> Schwellwert verwendet, um Isoflächen zu<br />
bilden, welche als Gittermodell darstellbar s<strong>in</strong>d. Die <strong>Integration</strong> e<strong>in</strong>es Algorithmus zur<br />
Erzeugung <strong>von</strong> Dreiecksgittern aus Voxeldaten <strong>in</strong> die Bibliothek, wäre e<strong>in</strong> denkbarer<br />
Schritt, um dies zu vere<strong>in</strong>fachen. Der march<strong>in</strong>g cubes Algorithmus wäre e<strong>in</strong> möglicher<br />
Ansatz hierfür.<br />
E<strong>in</strong>e weitere s<strong>in</strong>nvolle Erweiterung stellt die <strong>Integration</strong> anderer Kantenglättungsalgorithmen<br />
dar. Supersampl<strong>in</strong>g Antialias<strong>in</strong>g (SSAA) liefert zwar gute Ergebnisse,<br />
jedoch kostet die Erzeugung e<strong>in</strong>es Bildes unter Verwendung des Algorithmus deutlich<br />
mehr Zeit. Zum e<strong>in</strong>en könnte der momentan auf der CPU erledigte Teil des<br />
Algorithmus auf die Grafikkarte verschoben werden, zum anderen gibt es mit Multisampl<strong>in</strong>g<br />
Antialias<strong>in</strong>g (MSAA) e<strong>in</strong>en sehr ähnlichen Algorithmus, welcher direkt bei<br />
der Erstellung der Grafik auf der Grafikkarte angewendet werden könnte (mit e<strong>in</strong>em<br />
Multisampl<strong>in</strong>g Framebu er Objekt).<br />
Da e<strong>in</strong>e leicht zu erlernende Schnittstelle e<strong>in</strong> wichtiges Ziel dieser Arbeit war, bleibt<br />
es außerdem abzuwarten, wie die Rückmeldungen zukünftiger Anwender <strong>von</strong> GR3<br />
ausfallen werden.<br />
46
Literaturverzeichnis<br />
[1] Bechlars, Jörg ; Buhtz, Ra<strong>in</strong>er: GKS <strong>in</strong> der Praxis. Spr<strong>in</strong>ger-Verlag, 1986. –<br />
ISBN 978–3–540–16139–2<br />
[2] Ernesti, Jonannes ; Kaiser, Peter:Python 3 – Das umfassende Handbuch. 2.<br />
aktualisierte Auflage. Galileo Comput<strong>in</strong>g, 2009. – ISBN 978–3–8362–1412–4<br />
[3] Heimbach, Ingo: Entwicklung e<strong>in</strong>es logischen GKS Gerätetreibers für die<br />
wxWidgets-Klassenbibliothek. Dezember2011<br />
[4] Hickson, Ian: HTML5. http://www.w3.org/TR/2012/WD-html5-20120329/,<br />
Abruf: 13. Juni 2012<br />
[5] Khronos Group: About The Khronos Group. http://www.khronos.org/<br />
about/, Abruf: 14. Juni 2012<br />
[6] Khronos Group: WebGL – OpenGL ES 2.0 for the Web. http://www.<br />
khronos.org/webgl/, Abruf: 13. Juni 2012<br />
[7] Khronos Group: WebGL Specification. http://www.khronos.org/registry/<br />
webgl/specs/latest/, Abruf: 13. Juni 2012<br />
[8] Kilgard, Mark J.: The OpenGL Utility Toolkit (GLUT) Programm<strong>in</strong>g Interface,<br />
API Version 3. http://www.opengl.org/resources/libraries/glut/glut-<br />
3.spec.ps, Abruf: 10. Juli 2012<br />
[9] Lahres, Bernhard ; Rayman, Gregor: Objektorientierte Programmierung. 2.,<br />
aktualisierte und erweiterte Auflage. Galileo Comput<strong>in</strong>g, 2009. – ISBN 978–3–<br />
8362–1401–8<br />
[10] Microsoft Corporation: wglGetCurrentContext function (W<strong>in</strong>dows). http:<br />
//msdn.microsoft.com/en-us/library/dd374383, Abruf: 11. Juni 2012<br />
[11] Mozilla Developer Network: WebGL - MDN. https://developer.<br />
mozilla.org/en/WebGL, Abruf: 13. Juni 2012<br />
[12] Persistence of Vision Raytracer Pty. Ltd.: POV-Ray: Documentation.<br />
http://www.povray.org/documentation/, Abruf: 11. Juni 2012<br />
[13] Peters, Alexander: Visualisierung <strong>von</strong> Daten aus Soft Matter Simulationen.<br />
Oktober 2008<br />
48
Literaturverzeichnis<br />
[14] Python Software Foundation: Python/C API Reference Manual – Introduction.<br />
http://docs.python.org/c-api/<strong>in</strong>tro.html, Abruf: 19. Juli 2012<br />
[15] Rhiem, Florian: <strong>Integration</strong> OpenGL-basierter Visualisierungs-Techniken <strong>in</strong> <strong>2D</strong>-<br />
<strong>Grafiksystemen</strong>. Dezember2011<br />
[16] Segal, Mark;Akeley, Kurt: The OpenGL ® Graphics System: A Specification,<br />
Version 4.2 (Core Profile) - April 27, 2012. http://www.opengl.org/<br />
registry/doc/glspec42.core.20120427.pdf, Abruf: 14. Juni 2012<br />
[17] Shre<strong>in</strong>er, Dave: OpenGL Programm<strong>in</strong>g Guide, Seventh Edition. Addison-<br />
Wesley, 2010. – ISBN 978–0–321–55262–8<br />
[18] Silicon Graphics, Inc.: OpenGL 2.1 Reference Pages – glFrustum. http://<br />
www.opengl.org/sdk/docs/man/xhtml/glFrustum.xml, Abruf: 11. Juni 2012<br />
[19] Silicon Graphics, Inc.: OpenGL 2.1 Reference Pages – gluPerspective. http:<br />
//www.opengl.org/sdk/docs/man/xhtml/gluPerspective.xml, Abruf: 11. Juni<br />
2012<br />
[20] Simpson, Robert J. ; Kessenich, John: The OpenGL ® ES Shad<strong>in</strong>g Language<br />
- May 12, 2009. http://www.khronos.org/registry/gles/specs/2.0/GLSL_<br />
ES_Specification_1.0.17.pdf, Abruf: 6. Juli 2012<br />
[21] Wikipedia: Lambert’s cos<strong>in</strong>e law. http://en.wikipedia.org/wiki/Lambert%<br />
27s_cos<strong>in</strong>e_law, Abruf: 27. Juni 2012<br />
49
Anhang
A. Funktionsreferenz<br />
Der Rückgabewert <strong>von</strong> Funktionen, welche e<strong>in</strong>en <strong>in</strong>t zurückgeben, ist e<strong>in</strong> Fehlercode.<br />
Mit der Funktion gr3_geterrorstr<strong>in</strong>g kann dieser Fehlercode <strong>in</strong> e<strong>in</strong>en Str<strong>in</strong>g umgesetzt<br />
werden. Ist ke<strong>in</strong> Fehler aufgetreten wird 0 (GR3_ERROR_NONE) zurückgegeben.<br />
A.1. Allgeme<strong>in</strong>e Funktionen<br />
gr3_<strong>in</strong>it<br />
Initialisiert die Bibliothek.<br />
1 #def<strong>in</strong>e GR3_IA_END_OF_LIST 0<br />
2 #def<strong>in</strong>e GR3_IA_FRAMEBUFFER_WIDTH 1<br />
3 #def<strong>in</strong>e GR3_IA_FRAMEBUFFER_HEIGHT 2<br />
4 <strong>in</strong>t gr3_<strong>in</strong>it(<br />
5 <strong>in</strong>t attrib_list<br />
6 );<br />
Parameter<br />
attrib_list<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> <strong>in</strong>t-Array. Dieser Array muss aus Paaren aus Attributname<br />
und -wert bestehen und mit GR3_IA_END_OF_LIST abgeschlossen werden. Mit<br />
den Attributen GR3_IA_FRAMEBUFFER_WIDTH und GR3_IA_FRAMEBUFFER_HEIGHT<br />
können Breite und Höhe des verwendeten Framebu er Objektes gesetzt werden.<br />
Standardmäßig wird für beides 512 verwendet.<br />
gr3_term<strong>in</strong>ate<br />
Gibt die Bibliothek und <strong>von</strong> ihr verwendete Ressourcen frei.<br />
1 void gr3_term<strong>in</strong>ate () ;<br />
gr3_getrenderpathstr<strong>in</strong>g<br />
Gibt e<strong>in</strong>en Zeiger auf e<strong>in</strong>e Zeichenkette zurück, welche Informationen über den Rendervorgang<br />
mit OpenGL liefert. Die Zeichenkette wird <strong>von</strong> der Bibliothek freigegeben.<br />
1 const char gr3_getrenderpathstr<strong>in</strong>g () ;<br />
53
Anhang A. Funktionsreferenz<br />
gr3_geterrorstr<strong>in</strong>g<br />
Gibt e<strong>in</strong>en Zeiger auf e<strong>in</strong>e Zeichenkette zurück, welche den Namen des angegebenen<br />
Fehlercodes enthält. Die Zeichenkette wird <strong>von</strong> der Bibliothek freigegeben.<br />
1 #def<strong>in</strong>e GR3_ERROR_NONE 0<br />
2 #def<strong>in</strong>e GR3_ERROR_INVALID_VALUE 1<br />
3 #def<strong>in</strong>e GR3_ERROR_INVALID_ATTRIBUTE 2<br />
4 #def<strong>in</strong>e GR3_ERROR_INIT_FAILED 3<br />
5 #def<strong>in</strong>e GR3_ERROR_OPENGL_ERR 4<br />
6 #def<strong>in</strong>e GR3_ERROR_OUT_OF_MEM 5<br />
7 #def<strong>in</strong>e GR3_ERROR_NOT_INITIALIZED 6<br />
8 #def<strong>in</strong>e GR3_ERROR_CAMERA_NOT_INITIALIZED 7<br />
9 #def<strong>in</strong>e GR3_ERROR_UNKNOWN_FILE_EXTENSION 8<br />
10 #def<strong>in</strong>e GR3_ERROR_CANNOT_OPEN_FILE 9<br />
11 #def<strong>in</strong>e GR3_ERROR_EXPORT 10<br />
12 const char gr3_geterrorstr<strong>in</strong>g(<br />
13 <strong>in</strong>t error<br />
14 );<br />
Parameter<br />
error<br />
E<strong>in</strong> Fehlercode<br />
gr3_setlogcallback<br />
Setzt die Callback-Funktion für Debug-Meldungen.<br />
1 void gr3_setlogcallback(<br />
2 void ( gr3_log_func)( const char log_message)<br />
3 );<br />
Parameter<br />
gr3_log_func<br />
E<strong>in</strong> Zeiger auf die Logg<strong>in</strong>g-Callback-Funktion. Sie wird mit Debug-Meldungen<br />
aus GR3 als log_message aufgerufen. Die übergebenen Zeichenketten werden<br />
nach dem Aufruf <strong>von</strong> der Bibliothek freigegeben.<br />
A.2. Szenenbeschreibungsfunktionen<br />
gr3_clear<br />
Löscht die aktuelle Szene.<br />
1 <strong>in</strong>t gr3_clear () ;<br />
54
gr3_cameralookat<br />
Setzt die Position und Ausrichtung der Kamera.<br />
1 void gr3_cameralookat(<br />
2 float camera_x , float camera_y , float camera_z ,<br />
3 float center_x , float center_y , float center_z ,<br />
4 float up_x , float up_y , float up_z<br />
5 );<br />
Parameter<br />
camera_x, camera_y, camera_z<br />
Die Position der Kamera<br />
center_x, center_y, center_z<br />
Der Fokuspunkt<br />
up_x, up_y, up_z<br />
E<strong>in</strong> Vektor, der im Bild nach oben zeigen soll<br />
gr3_setcameraprojectionparameters<br />
Setzt die Projektionsparameter der Kamera.<br />
1 <strong>in</strong>t gr3_setcameraprojectionparameters(<br />
2 float vertical_field_of_view ,<br />
3 float zNear ,<br />
4 float zFar<br />
5 );<br />
Parameter<br />
vertical_field_of_view<br />
Das vertikale Sichtfeld im Gradmaß<br />
zNear<br />
Die Distanz <strong>von</strong> der Kamera zur vorderen Clipp<strong>in</strong>g-Ebene<br />
zFar<br />
Die Distanz <strong>von</strong> der Kamera zur h<strong>in</strong>teren Clipp<strong>in</strong>g-Ebene<br />
gr3_setlightdirection<br />
A.2. Szenenbeschreibungsfunktionen<br />
Setzt die Richtung der Beleuchtung. Falls die Funktion mit (0, 0, 0) aufgerufen wird,<br />
wird die Blickrichtung der Kamera verwendet.<br />
1 void gr3_setlightdirection(<br />
2 float x, float y, float z<br />
3 );<br />
55
Anhang A. Funktionsreferenz<br />
Parameter<br />
x, y, z<br />
Die Richtung des Lichts<br />
gr3_setbackgroundcolor<br />
Setzt die H<strong>in</strong>tergrundfarbe.<br />
1 void gr3_setbackgroundcolor(<br />
2 float red ,<br />
3 float green ,<br />
4 float blue ,<br />
5 float alpha<br />
6 );<br />
Parameter<br />
red, green, blue<br />
Die H<strong>in</strong>tergrundfarbe<br />
alpha<br />
Die Alpha-Komponente des H<strong>in</strong>tergrunds (0 für transparent, 1 für blickdicht)<br />
gr3_createmesh<br />
Erstellt e<strong>in</strong> Dreiecksgitter.<br />
1 <strong>in</strong>t gr3_createmesh(<br />
2 <strong>in</strong>t mesh ,<br />
3 <strong>in</strong>t n,<br />
4 const float vertices ,<br />
5 const float normals ,<br />
6 const float colors<br />
7 );<br />
Parameter<br />
mesh<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong>e <strong>in</strong>t-Variable, <strong>in</strong> welche die ID des Dreiecksgitters geschrieben<br />
wird. Anhand dieser ID kann das Gitter anschließend identifiziert werden.<br />
n<br />
Die Anzahl der Eckpunkte<br />
vertices<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Ortsvektoren der Eckpunkte enthält<br />
56
A.2. Szenenbeschreibungsfunktionen<br />
normals<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Normalenvektoren der Eckpunkte<br />
enthält<br />
colors<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Farben der Eckpunkte enthält<br />
gr3_drawmesh<br />
Fügt e<strong>in</strong> mit gr3_createmesh erstelltes Dreiecksgitter e<strong>in</strong>- oder mehrmals zur Szene<br />
h<strong>in</strong>zu.<br />
1 void gr3_drawmesh(<br />
2 <strong>in</strong>t mesh ,<br />
3 <strong>in</strong>t n,<br />
4 const float positions ,<br />
5 const float directions ,<br />
6 const float ups ,<br />
7 const float colors ,<br />
8 const float scales<br />
9 );<br />
Parameter<br />
mesh<br />
Die ID des zu zeichnenden Dreiecksgitters<br />
n<br />
Die Anzahl der zu zeichnenden Dreiecksgitter<br />
positions<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Positionen der Dreiecksgitter enthält<br />
directions<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Vorwärts-Vektoren der Dreiecksgitter<br />
enthält<br />
ups<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Aufwärts-Vektoren der Dreiecksgitter<br />
enthält<br />
colors<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Farben der Dreiecksgitter enthält<br />
scales<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Skalierungsvektoren der Dreiecksgitter<br />
enthält<br />
57
Anhang A. Funktionsreferenz<br />
gr3_deletemesh<br />
Gibt e<strong>in</strong> Dreiecksgitter zum Löschen frei.<br />
1 void gr3_deletemesh(<br />
2 <strong>in</strong>t mesh<br />
3 );<br />
Parameter<br />
mesh<br />
Die ID des zu löschenden Dreiecksgitters<br />
gr3_drawconemesh<br />
Fügt e<strong>in</strong>en oder mehrere Kegel zur Szene h<strong>in</strong>zu.<br />
1 void gr3_drawconemesh(<br />
2 <strong>in</strong>t n,<br />
3 const float positions ,<br />
4 const float directions ,<br />
5 const float colors ,<br />
6 const float radii ,<br />
7 const float lengths<br />
8 );<br />
Parameter<br />
n<br />
Die Anzahl der zu zeichnenden Kegel<br />
positions<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Positionen der Kegel enthält<br />
directions<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Vorwärts-Vektoren der Kegel enthält<br />
colors<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Farben der Kegel enthält<br />
radii<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Basisradien der Kegel enthält<br />
lengths<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Länge, bzw. Höhe der Kegel enthält<br />
58
gr3_drawcyl<strong>in</strong>dermesh<br />
Fügt e<strong>in</strong>en oder mehrere Zyl<strong>in</strong>der zur Szene h<strong>in</strong>zu.<br />
1 void gr3_drawcyl<strong>in</strong>dermesh(<br />
2 <strong>in</strong>t n,<br />
3 const float positions ,<br />
4 const float directions ,<br />
5 const float colors ,<br />
6 const float radii ,<br />
7 const float lengths<br />
8 );<br />
Parameter<br />
n<br />
Die Anzahl der zu zeichnenden Zyl<strong>in</strong>der<br />
A.2. Szenenbeschreibungsfunktionen<br />
positions<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Positionen der Zyl<strong>in</strong>der enthält<br />
directions<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Vorwärts-Vektoren der Zyl<strong>in</strong>der<br />
enthält<br />
colors<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Farben der Zyl<strong>in</strong>der enthält<br />
radii<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Radien der Zyl<strong>in</strong>der enthält<br />
lengths<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Länge, bzw. Höhe der Zyl<strong>in</strong>der<br />
enthält<br />
gr3_drawspheremesh<br />
Fügt e<strong>in</strong>en oder mehrere Kugeln zur Szene h<strong>in</strong>zu.<br />
1 void gr3_drawspheremesh(<br />
2 <strong>in</strong>t n,<br />
3 const float positions ,<br />
4 const float colors ,<br />
5 const float radii<br />
6 );<br />
59
Anhang A. Funktionsreferenz<br />
Parameter<br />
n<br />
Die Anzahl der zu zeichnenden Kugeln<br />
positions<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Positionen der Kugeln enthält<br />
colors<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Farben der Kugeln enthält<br />
radii<br />
E<strong>in</strong> Zeiger auf e<strong>in</strong> float-Array, welches die Radien der Kugeln enthält<br />
A.3. Export- und Zeichenfunktionen<br />
gr3_getimage<br />
Erzeugt e<strong>in</strong>e Grafik und schreibt sie <strong>in</strong> e<strong>in</strong>en vom Anwendungsentwickler verwalteten<br />
Speicherbereich.<br />
1 <strong>in</strong>t gr3_getimage(<br />
2 <strong>in</strong>t width ,<br />
3 <strong>in</strong>t height ,<br />
4 <strong>in</strong>t use_alpha ,<br />
5 char pixels<br />
6 );<br />
Parameter<br />
width<br />
Die Breite der Grafik <strong>in</strong> Pixeln<br />
height<br />
Die Höhe der Grafik <strong>in</strong> Pixeln<br />
use_alpha<br />
E<strong>in</strong> Flag, ob Transparenz verwendet werden soll: 0 für Ne<strong>in</strong>, 1 für Ja<br />
pixels<br />
Der Speicherbereich, <strong>in</strong> welchen die Grafik geschrieben wird. Dieser Bereich<br />
muss width · height · components Byte groß se<strong>in</strong>, wobei components gleich 4 ist,<br />
falls Transparenz verwendet wird, oder 3, falls nicht.<br />
60
gr3_drawimage<br />
Zeichnet die Szene <strong>in</strong> e<strong>in</strong>en Zeichenbereich.<br />
1 #def<strong>in</strong>e GR3_DRAWABLE_OPENGL 1<br />
2 #def<strong>in</strong>e GR3_DRAWABLE_GKS 2<br />
3 <strong>in</strong>t gr3_drawimage(<br />
4 float xm<strong>in</strong> , float xmax ,<br />
5 float ym<strong>in</strong> , float ymax ,<br />
6 <strong>in</strong>t width ,<br />
7 <strong>in</strong>t height ,<br />
8 <strong>in</strong>t drawable_type<br />
9 );<br />
Parameter<br />
A.3. Export- und Zeichenfunktionen<br />
xm<strong>in</strong>, xmax<br />
Die m<strong>in</strong>imale und maximale Position der Grafik auf der x-Achse<br />
ym<strong>in</strong>, ymax<br />
Die m<strong>in</strong>imale und maximale Position der Grafik auf der y-Achse<br />
height<br />
Die Höhe der Grafik <strong>in</strong> Pixeln<br />
width<br />
Die Breite der Grafik <strong>in</strong> Pixeln<br />
drawable_type<br />
Die Art des Zeichenbereiches, welcher zur Darstellung verwendet werden soll<br />
gr3_export<br />
Schreibt die Grafik <strong>in</strong> e<strong>in</strong>e Datei. Unterstützte Dateiformate s<strong>in</strong>d PNG (.png), JPEG<br />
(.jpg/.jpeg), POV-Ray SDL (.pov) und HTML5 (.html).<br />
1 <strong>in</strong>t gr3_export(<br />
2 const char filename ,<br />
3 <strong>in</strong>t width ,<br />
4 <strong>in</strong>t height<br />
5 );<br />
Parameter<br />
filename<br />
Der Name der Ausgabedatei<br />
width<br />
Die Breite der Grafik <strong>in</strong> Pixeln<br />
height<br />
Die Höhe der Grafik <strong>in</strong> Pixeln<br />
61
Anhang A. Funktionsreferenz<br />
gr3_setquality<br />
Setzt die Qualität der Grafikerzeugung. Dies entscheidet, ob OpenGL oder POV-Ray<br />
und ob bzw. wie viel Kantenglättung verwendet werden soll.<br />
1 #def<strong>in</strong>e GR3_QUALITY_OPENGL_NO_SSAA 0<br />
2 #def<strong>in</strong>e GR3_QUALITY_OPENGL_2X_SSAA 2<br />
3 #def<strong>in</strong>e GR3_QUALITY_OPENGL_4X_SSAA 4<br />
4 #def<strong>in</strong>e GR3_QUALITY_OPENGL_8X_SSAA 8<br />
5 #def<strong>in</strong>e GR3_QUALITY_OPENGL_16X_SSAA 16<br />
6 #def<strong>in</strong>e GR3_QUALITY_POVRAY_NO_SSAA 1<br />
7 #def<strong>in</strong>e GR3_QUALITY_POVRAY_2X_SSAA 3<br />
8 #def<strong>in</strong>e GR3_QUALITY_POVRAY_4X_SSAA 5<br />
9 #def<strong>in</strong>e GR3_QUALITY_POVRAY_8X_SSAA 9<br />
10 #def<strong>in</strong>e GR3_QUALITY_POVRAY_16X_SSAA 17<br />
11 <strong>in</strong>t gr3_setquality(<br />
12 <strong>in</strong>t quality<br />
13 );<br />
Parameter<br />
quality<br />
Die gewünschte Qualitätsstufe<br />
62
B. Codebeispiele<br />
B.1. Visualisierung dreier Kugeln<br />
Der folgende Quelltext wird <strong>in</strong> Abschnitt 4.1.1 erläutert und Abbildung 4.1 auf Seite<br />
32 zeigt die Ergebnisgrafik.<br />
1 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude <br />
3<br />
4 <strong>in</strong>t ma<strong>in</strong>( void) {<br />
5 <strong>in</strong>t <strong>in</strong>it_attrs [] = {GR3_IA_END_OF_LIST};<br />
6 <strong>in</strong>t err = gr3_<strong>in</strong>it(<strong>in</strong>it_attrs);<br />
7 if (err) {<br />
8 fpr<strong>in</strong>tf(stderr ," Failed to <strong>in</strong>itialize GR3: %s \n" ,<br />
gr3_geterrorstr<strong>in</strong>g(err));<br />
9 return 1;<br />
10 }<br />
11 / H<strong>in</strong>tergrundfarbe : Rot , Grün , Blau , Alpha /<br />
12 gr3_setbackgroundcolor (0 , 0, 0, 0) ;<br />
13 / Projektionsparameter : vertikales Sichtfeld <strong>in</strong> Grad , Nah≠ und<br />
14 Fern≠Clipp<strong>in</strong>g≠Abstand /<br />
15 gr3_setcameraprojectionparameters (6 , 1, 100) ;<br />
16 / Kameraposition , Fokuspunkt , up≠Vektor /<br />
17 gr3_cameralookat (0 ,0 ,20 , 0 ,0 ,0 , 0 ,1 ,0) ;<br />
18 {<br />
19 float positions [] = {≠2,0,0, 0,0,0, 2,0,0};<br />
20 float colors [] = {1,0,0, 0,1,0, 0,0,1};<br />
21 float radii [] = {1,1,1};<br />
22 gr3_drawspheremesh (3 , positions , colors , radii ) ;<br />
23 }<br />
24 gr3_setquality(GR3_QUALITY_OPENGL_4X_SSAA) ;<br />
25 gr3_export(" image . png" ,3000,1000) ;<br />
26 gr3_term<strong>in</strong>ate () ;<br />
27 return 0;<br />
28 }<br />
List<strong>in</strong>g B.1: Darstellung <strong>von</strong> drei Kugeln mit GR3<br />
63
Anhang B. Codebeispiele<br />
B.2. E<strong>in</strong>e Funktion als <strong>3D</strong>-Fläche<br />
E<strong>in</strong>e Erläuterung des folgenden Quelltextes ist <strong>in</strong> Abschnitt 4.1.2 zu f<strong>in</strong>den. Abbildung<br />
4.2 auf Seite 35 zeigt die erzeugte Grafik.<br />
1 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude <br />
3 #<strong>in</strong>clude <br />
4<br />
5 float f(<strong>in</strong>t x, <strong>in</strong>t y) {<br />
6 return s<strong>in</strong>(x 0.66) cos(y 0.2) ;<br />
7 }<br />
8<br />
9 float dfdx( <strong>in</strong>t x, <strong>in</strong>t y) {<br />
10 return 0.66 cos (0.66 x) cos (0.2 y);<br />
11 }<br />
12<br />
13 float dfdy( <strong>in</strong>t x, <strong>in</strong>t y) {<br />
14 return ≠0.2 s<strong>in</strong> (0.66 x) s<strong>in</strong> (0.2 y);<br />
15 }<br />
16<br />
17 float normalize( float vec) {<br />
18 float tmp = 0 ;<br />
19 <strong>in</strong>t i;<br />
20 for (i = 0; i < 3; i++) tmp += vec[i] vec [ i ];<br />
21 tmp = s q r t (tmp) ;<br />
22 for (i = 0; i < 3; i++) vec[i]/=tmp;<br />
23 return vec ;<br />
24 }<br />
25<br />
26 <strong>in</strong>t ma<strong>in</strong>( void) {<br />
27 <strong>in</strong>t <strong>in</strong>it_attrs [] = {GR3_IA_END_OF_LIST};<br />
28 <strong>in</strong>t err = gr3_<strong>in</strong>it(<strong>in</strong>it_attrs);<br />
29 if (err) {<br />
30 fpr<strong>in</strong>tf(stderr ," Failed to <strong>in</strong>itialize GR3: %s \n" ,<br />
gr3_geterrorstr<strong>in</strong>g(err));<br />
31 return 1;<br />
32 }<br />
33 gr3_setbackgroundcolor (0 , 0, 0, 0) ;<br />
34 gr3_setcameraprojectionparameters(45, 1, 100) ;<br />
35 gr3_setlightdirection (0,0,1) ;<br />
36 gr3_cameralookat(5,≠6,12, 5,5,0, 0,1,0);<br />
37 {<br />
38 <strong>in</strong>t mesh ;<br />
39 <strong>in</strong>t i, x, y;<br />
40 <strong>in</strong>t dx [ 6 ] = {0 ,1 ,1 ,0 ,1 ,0};<br />
41 <strong>in</strong>t dy [ 6 ] = {0 ,0 ,1 ,0 ,1 ,1};<br />
42 float mesh_vertices [100 6 3];<br />
43 float mesh_normals [100 6 3];<br />
44 float mesh_colors [100 6 3];<br />
45 float positions [3] = {0,0,0};<br />
46 float directions [3] = {0,0,1};<br />
64
B.2. E<strong>in</strong>e Funktion als <strong>3D</strong>-Fläche<br />
47 float ups [3] = {0 ,1 ,0};<br />
48 float colors [3] = {1,1,1};<br />
49 float scales [3] = {1,1,1};<br />
50 for (x = 0; x < 10; x++) {<br />
51 for (y = 0; y < 10; y++) {<br />
52 for (i = 0; i < 6; i++) {<br />
53 <strong>in</strong>t ix = x+dx[ i ];<br />
54 <strong>in</strong>t iy = y+dy[ i ];<br />
55 mesh_vertices [(y 10+x) 6 3+ i 3+0] = ix ;<br />
56 mesh_vertices [(y 10+x) 6 3+ i 3+1] = iy ;<br />
57 mesh_vertices [(y 10+x) 6 3+ i 3+2] = f ( ix , iy ) ;<br />
58<br />
59 mesh_normals [( y 10+x) 6 3+ i 3+0] = ≠dfdx(ix , iy ) ;<br />
60 mesh_normals [( y 10+x) 6 3+ i 3+1] = ≠dfdy(ix , iy ) ;<br />
61 mesh_normals [( y 10+x) 6 3+ i 3+2] = 1;<br />
62 normalize(mesh_normals+(y 10+x) 6 3+ i 3+0) ;<br />
63<br />
64 mesh_colors [(y 10+x) 6 3+ i 3+0] = 1;<br />
65 mesh_colors [(y 10+x) 6 3+ i 3+1] = 1;<br />
66 mesh_colors [(y 10+x) 6 3+ i 3+2] = 1;<br />
67 }<br />
68 }<br />
69 }<br />
70 gr3_createmesh(&mesh , 100 6, mesh_vertices , mesh_normals,<br />
mesh_colors) ;<br />
71 gr3_drawmesh(mesh ,1 , positions , directions , ups , colors , scales ) ;<br />
72 gr3_deletemesh(mesh) ;<br />
73 }<br />
74 gr3_setquality(GR3_QUALITY_OPENGL_16X_SSAA) ;<br />
75 gr3_export(" graph . png" , 3000, 1000) ;<br />
76 gr3_term<strong>in</strong>ate () ;<br />
77 return 0;<br />
78 }<br />
List<strong>in</strong>g B.2: <strong>3D</strong>-Plot der Funktion f(x, y) =cos(0.66x) · s<strong>in</strong>(0.2y)<br />
65