05.10.2013 Aufrufe

Integration von 3D-Visualisierungstechniken in 2D-Grafiksystemen

Integration von 3D-Visualisierungstechniken in 2D-Grafiksystemen

Integration von 3D-Visualisierungstechniken in 2D-Grafiksystemen

MEHR ANZEIGEN
WENIGER ANZEIGEN

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

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!