05.08.2013 Aufrufe

Proseminar Computergrafik Thema: OpenGL Autor: Uygar Kalem

Proseminar Computergrafik Thema: OpenGL Autor: Uygar Kalem

Proseminar Computergrafik Thema: OpenGL Autor: Uygar Kalem

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.

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Einführung.................................................................................................................................. 3

Die Entstehung von OpenGL ..................................................................................................... 4

Funktionsweise des OpenGL API.............................................................................................. 6

Hilfsbibliotheken für OpenGL ................................................................................................... 8

GLu......................................................................................................................................... 8

GLX........................................................................................................................................ 8

Glut......................................................................................................................................... 8

Die Pipeline des OpenGL APIs.................................................................................................. 9

Die Geometriepipeline ......................................................................................................... 10

Der Rasterizer....................................................................................................................... 12

Per-Fragment Operationen ................................................................................................... 13

Ein kleines Programmbeispiel.................................................................................................. 15

Die Zukunft von OpenGL ........................................................................................................ 18

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Einführung

OpenGL, das eine Abkürzung für Open Graphics Library ist, ist mittlerweile als der Standard

im professionellen Grafikbereich anzusehen. OpenGL ist ein API (Application Programming

Interface), anhand dessen plattformübergreifende 2D und 3D Applikationen erstellt werden

können.

Der Erfolg von OpenGL lässt sich darauf zurückführen, dass es einen

plattformübergreifenden Standard definiert, um 3D Szenen darzustellen, die außerdem noch

per spezieller Hardware beschleunigt werden können, um noch mehr Leistung zu erzielen.

Heutzutage werden OpenGL Runtime Bibliotheken mit allen Windows, MacOS, Linux und

Unix Systemen ausgeliefert, im Gegensatz zu Direct3D zum Beispiel, welches nur in der

Windows Welt existiert. Dies ist jedoch nur deshalb möglich, weil die Spezifikationen von

OpenGL von einem unabhängigen Konsortium festgelegt werden. Dieses Konsortium wird

Architecture Review Board (ARB) genannt, dem wichtige Industriegrößen angehören.

Ein weiterer wichtiger Aspekt für den Erfolg von OpenGL ist das Lizenzierungsmodell.

Entwickler müssen keine Lizenzgebühren zahlen, wenn sie die OpenGL Bibliotheken

verwenden möchten, was bedeutet, dass jeder OpenGL programmieren darf. In Verbindung

mit der Präsenz dieser Bibliotheken auf allen gängigen Betriebssystemen sind diese

Bibliotheken somit auch für jedermann leicht zugänglich. Lizenzgebühren fallen nur für

Hardwarehersteller an, die OpenGL Treiber mit ihrer Hardware ausliefern möchten. Dies trifft

heutzutage auf praktisch jeden Hersteller von Grafikkarten zu, sowohl im professionellen

Marktsegment, z.B. 3DLabs, als auch im Consumersegment, z.B. nVidia und ATI, da durch

die Verbreitung von Computerspielen, die ihre 3D Engine auf OpenGL aufsetzen, z.B. die

Quake3 Engine als bekanntesten Vertreter hiervon, Hardwareunterstützung von OpenGL

Pflicht geworden ist, möchte man dem dem gelegentlichen Spiel nicht abgeneigten Nutzer

sein Produkt verkaufen.

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Die Entstehung von OpenGL

OpenGL ist eine Entwicklung von Silicon Graphics (SGI). Bevor es OpenGL gab, hatten viele

Grafikhardwarehersteller proprietäre Bibliotheken, um ihre eigene Hardware anzusprechen.

Dadurch war es besonders schwierig für Entwickler, für ihre Programme eine breite

Hardwareunterstützung zu gewährleisten, da sie ihr Programm für jeden Hardwarehersteller

anpassen mussten. SGI erkannte damals, dass ein standardisiertes API nötig ist, um die

Entwicklung im 3D Bereich voranzutreiben. Daher beschloss SGI, das Architecture Review

Board, kurz ARB, im Jahre 1992 ins Leben zu rufen, in dem weite Teile der Industrie

vertreten sein sollten. Dieses ARB wacht über die Entwicklung von OpenGL, es segnet neue

Features und so genannte Extensions von OpenGL ab. Was das ARB nicht absegnet, findet

seinen Weg auch nicht in das offizielle OpenGL. OpenGL selbst basiert weitgehend auf der

SGI® IRIS GL Bibliothek. Zu Beginn war OpenGL nur eine Spezifikation, danach

veröffentlichte SGI Beispielcode, damit Hardwareentwickler passende Treiber für ihre

Hardware schreiben konnten. Die aktuelle Revision von OpenGL ist 1.3.

Das ARB besteht aus Gründungsmitgliedern, ständigen Mitgliedern und Hilfsmitgliedern. Es

tagt alle 3 Monate und die Tagung wird jedes Mal von einem anderen Mitglied organisiert.

Mitglieder, die im jetzigen ARB Stimmrecht haben sind:

• 3Dlabs

• Apple

• ATI

• Compaq

• Dell Computer

• Evans & Sutherland

• Hewlett-Packard

• IBM

• Intel

• Microsoft

• NVIDIA

• SGI

• Sun

Außerdem kann man noch als nicht stimmberechtigter Teilnehmer dem ARB beitreten. Diese

Mitglieder können sich dann für eine Mitgliedschaft bewerben, sollte ein Platz im ARB frei

werden. Beispiele hierfür sind im Moment:

Alt.software, Crytek GmbH, Discreet, Empire Interactive, Ensemble Studios, GLSetup, Id

Software, Imagination Technologies (PowerVR), Intelligraphics, Matrox, Micron, NEC,

Obsession Development, PixelFusion, Quantum3D, RAD Game Tools, Raven Software,

S3/Diamond Multimedia, SiS, Tungesten Graphics, University of Central Florida, Verant

Interactive, Xi Graphics

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Außer dem ARB gibt es noch eine weitere wichtige Organisation, das OpenGL Performance

Characterization Committee, kurz opc

(http://www.specbench.org/gpc/opc.static/overview.htm). Dieses wurde 1993 gegründet, ist

wie das ARB unabhängig und hat die Aufgabe, Benchmarks zu entwickeln, anhand derer die

Leistung von OpenGL Implementierungen auf unterschiedlicher Hardware und

Betriebssystemen getestet werden soll. Das opc trat 1994 der Graphics Performance

Characterization Group, kurz GPC (http://www.specbench.org/gpc/), bei, welche es sich zur

Aufgabe gemacht hat, neue Testmethoden zum Messen von graphischen Leistungen zu

entwickeln. Das GPC selbst wiederum trat Anfang 1996 der Standard Performance Evaluation

Corp., kurz SPEC (http://www.spec.org), bei. SPEC ist eine Organisation, die aus einer

Vielzahl an Gruppen besteht, die Benchmarks entwickeln. Das GPC besteht aus drei Gruppen,

dem schon erwähnten opc, das seit dem Beitreten zur SPEC SPECopc heißt, dann noch

SPECapc, das die Leistung von Applikationen misst, z.B. 3DS Max 3, und zuletzt noch

SPECmedia, das an einem MPEG-2 Benchmark arbeitet. Hierbei können diese Gruppen

jedoch autonom arbeiten. Es gibt zwar Richtlinien der GPC, jedoch können alle ihr

unterstellten Gruppen eigene Richtlinien entwickeln, solange diese nicht im Widerspruch zu

denen der GPC stehen. Finanziert wird die SPECopc durch Mitgliedsbeiträge, sie ist jedoch

eine nicht Profit orientierte Organisation und erwirtschaftet somit keinen Gewinn. Mitglied

kann jeder werden, egal ob Gruppe, Organisation oder Einzelperson, der die Beiträge bezahlt.

Mitglieder der SPECopc sind im Moment:

• 3DLabs

• ATI

• Compaq Computer Corporation

• Dell Computer Corporation

• Evans & Sutherland

• Fujitsu Siemens Computers

• Hewlett-Packard

• IBM

• Intel

• Intergraph

• Matrox Graphics

• NEC Corporation, Japan

• NVIDIA

• S3 Professional Graphics Division

• SGI

• Sun Microsystems

Der Benchmark, den die SPECopc im Moment weiterentwickelt, heißt SPECviewperf® 6.1.2.

(http://www.specbench.org/gpc/downloadindex.html).

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Funktionsweise des OpenGL API

Alles, was OpenGL macht, läuft letztendlich darauf hinaus, dass in den Frame Buffer der

Grafikkarte geschrieben wird bzw. aus ihm gelesen wird. Es bietet keinerlei Möglichkeiten,

Usereingaben in irgendeiner Form zu verwalten. OpenGL hat keine eingebaute Maus oder

Tastaturunterstützung, will man also Usereingaben behandeln, muss man dies anhand des auf

dem System zur Verfügung stehenden Fenstersystems tun.

Generell wird man in einer OpenGL Applikation seine Objekte verwalten und bestimmen, wie

diese zu einander stehen in Form von Raumkoordinaten um dann schließlich die nötigen GL

Befehle abzusetzen, damit die Objekte auf dem Bildschirm gezeichnet werden.

Manipulationen an den Objekten werden mittels Matrizen durchgeführt. Dazu werden alle

Matrizen beim Durchlaufen des Zeichenprozesses aufeinander multipliziert, wodurch sich

verschiedene Manipulationen kombinieren lassen, zum Beispiel das gleichzeitige Rotieren

und Verschieben eines Objektes. Dabei ist es immens wichtig, auf die Reihenfolge zu achten,

schließlich ist es ein Unterschied, ob man ein Objekt zuerst um 3 nach rechts verschiebt und

dann um 90° um den Ursprung dreht, oder umgekehrt. Mit Matrizen kann man allerdings

nicht nur Rotation, Skalierung und Translation bestimmen, sondern auch andere

Eigenschaften der Szene, zum Beispiel Clipping Volumes, Perspektiven etc.

OpenGL arbeitet nach der Client/Server Architektur. Der Client hierbei ist die Applikation,

die OpenGL Kommandos aufruft, während der Server diese empfängt, umsetzt und darstellt.

In einem Netzwerk wie dem X Window System kann somit der Server auf einem anderen

Rechner laufen, als der Client. Da außerdem das Protokoll für die Übertragung der gl Befehle

festgelegt ist, können Client und Server unterschiedlicher Architektur sein und trotzdem

zusammenspielen. Wird OpenGL nur lokal ausgeführt sind Client und Server derselbe

Rechner.

OpenGL ist ein so genannter Zustandsautomat. Es gibt Zustände, die ein und ausgeschaltet

werden können, z.B. die Lichtberechnung der Szene, während bei anderen Zuständen ein

Zustand aus einer vorgegebenen Auswahl gesetzt werden kann, z.B. ob bei der

Polygondarstellung nur Punkte dargestellt werden sollen, die Punkten mit Linien verbunden

werden sollen, oder die spezifizierte Fläche auch gleich gefüllt werden soll. Dabei gibt es

Zustände, die den Server betreffen, welches die meisten sind, und Zustände, die den Client

betreffen. Dies ist auch ein Grund, weshalb Display Lists nur einmal angelegt werden können

und später nicht mehr editierbar sind. Eigentlich arbeitet OpenGL im Immediate Mode, oder

auch Sofortmodus. Das bedeutet, dass sobald eine Primitive spezifiziert wurde, diese auch

automatisch durch die OpenGL Pipeline wandert und bearbeitet wird. Primitive sind die

Grundelemente jeder OpenGL Szene. Als Primitives gelten Punkte, Linien und Polygone, die

durch Vertices beschrieben werden. Werden die drei Eckpunkte eines Dreiecks zum Beispiel

angegeben, wird dieses Dreieck auch sofort gezeichnet, wenn es denn im Viewing Volume

liegt. Das Viewing Volume wird durch das Clipping Volume bestimmt. Normalerweise ist das

Clipping Volume gleich dem Viewing Volume gleich dem Programmfenster. Man kann

jedoch eigene Clipping Volumes definieren. Diese sind Halbräume und es kann beliebig viele

geben. Das Viewing Volume ist dann der Schnitt aus allen Clipping Volumes. So kann man

eine Szene zum Beispiel auf das linke obere Viertel des Bildschirms beschränken.

Die einzige Ausnahme vom Immediate Mode sind so genannte Display Lists. In ihnen kann

man die Geometrie, Normale, aber auch Zustände wie die aktuelle Farbe von der GL schon

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


einmal kompilieren lassen, ohne die Befehle jedoch gleich umzusetzen. So könnte man von

einem Auto das eine Rad vorkompilieren lassen, und wenn man nun das Auto zeichnen

möchte, ruft man einfach 4mal die Displaylist auf und variiert nur jeweils die Position, an der

gezeichnet werden soll. Der Vorteil der Display List im Gegensatz zum 4maligen

spezifizieren des Rades liegt darin, dass die notwendigen Geometrieberechnungen nur einmal

durchgeführt werden müssen und dann nur noch gespeicherte Werte abgefragt werden.

Außerdem wird in einem Netzwerk der Traffic reduziert, da die relevanten Daten schon auf

dem Server liegen. Genauso kann man auch Texturen in einer Displaylist laden. OpenGL

wandelt diese meist in ein eigenes Format um, das es besser verwenden kann. Ist dies einmal

geschehen, können diese Texturen ebenfalls schneller verwendet werden. Werden Display

Lists angefertigt, werden die kompilierten Ergebnisse im Server gespeichert und residieren

nicht mehr auf dem Client. Daher ist auch das nachträgliche ändern von Inhalten der

Displaylist nicht erlaubt und auch nicht möglich. Gibt man zum Beispiel in der Display List

eine Farbe an und lässt einen Parameter als Variable, evaluiert OpenGL den Wert und legt

eine Kopie davon auf dem Server ab, aber keinen Pointer auf die Variable. Wird diese nun

nachträglich geändert, ist das der Display List egal, da sie nicht vom Pointer abhängt. Diese

Evaluation beim Aufruf einer Funktion gilt für alle Aufrufe, OpenGL übernimmt keine

Pointer auf Daten sondern kopiert den aktuellen Wert, auf den der Pointer zeigt, in seinen

eigenen Speicherbereich und arbeitet mit ihm weiter.

Die Kommandos in OpenGL werden sequentiell abgearbeitet. Das bedeutet, dass solange die

Verarbeitung eines Kommandos nicht abgeschlossen ist, kein weiteres Kommando bearbeitet

wird. Dabei kann ein Kommando entweder eine Operation auf dem Frame Buffer sein, zum

Beispiel das zeichnen eines Polygons, oder das Verändern eines Zustandes.

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Hilfsbibliotheken für OpenGL

GLu

Die GLu oder auch GL Utility Library ist eine Bibliothek, die viele nützliche Funktionen

bereitstellt, die einem das Arbeiten mit OpenGL vereinfachen sollen. Hierzu gehört das

äußerst nützliche automatische Mipmapping, das selbständig die nötigen MipMaps generiert,

ohne dass man dazu ein Grafikprogramm bemühen müsste. Außerdem kann man anhand der

glu auch Splines darstellen und sie übernimmt auch das Anlegen einer passenden

Projektionsmatrix für die Szene, die Methode bekommt Blickwinkel (engl. Field of View

bzw. fov), Seitenverhältnis, max z und min z, innerhalb derer gezeichnet wird, übergeben und

errechnet selbständig die nötige Projektionsmatrix. Außerdem kann man noch Kugeln etc. mit

der Bibliothek generieren.

GLX

Die GLX bietet Hilfsfunktionen, um unter Unix/Linux den X Window Manager ansprechen

zu können. Unter Windows wird sie nicht benötigt.

Glut

Glut ist das GL Utility Toolkit. Glut ist sehr hilfreich, wenn man schnell kleinere OpenGL

Programme schreiben möchte, ohne sich damit auseinandersetzen zu wollen, wie man im

entsprechenden Betriebssystem ein GL Fenster zum laufen kriegt. Da dies außerdem auf den

verschiedenen Betriebssystemen sehr unterschiedlich ist, kann man anhand von glut

plattformunabhängig seine Programme schreiben. Glut übernimmt dabei auch die

Eventabfrage von Tasten und der Maus, außerdem hat es eine eigene main loop. Es erspart

einem also eine Menge Zeit und hilft, sich auf OpenGL zu konzentrieren, anstatt Zeit damit zu

verbringen, wie man überhaupt ein OpenGL Fenster aufbekommt.

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Die Pipeline des OpenGL APIs

Vertices werden in der Graphics Rendering Pipeline verarbeitet. Ein Vertex kennzeichnet die

Ecken einer Primitiven, bei Linien sind das Anfangs- und Endpunkt, bei Polygonen die Ecken

des Polygons, bei Punkten der Punkt selber. Mit den Vertices werden Daten assoziiert,

nämlich die Positionskoordinaten im Raum, Farben und die zugehörige Normale, um zu

wissen, wo beim Vertex vorne ist, was für die Lichtberechnung sehr wichtig ist. OpenGL

arbeitet mit einem kartesischen Koordinatensystem, wobei die positive x-Achse nach rechts

verläuft, die positive y-Achse nach oben und die positive z-Achse aus dem Bildschirm heraus

zum Betrachter. Außerdem kann man mit dem Vertex noch Texturkoordinaten assoziieren.

Hat man nun z.B. ein Viereck anhand von 4 Vertices spezifiziert und möchte man eine Textur

nun auf das Viereck „draufkleben“, muss man OpenGL mitteilen, an welchem Vertex z.B. die

linke untere Ecke der Textur liegen soll. Vertices werden unabhängig voneinander und in der

Reihenfolge berechnet, in der sie spezifiziert werden. Einzige Ausnahme hiervon ist, wenn

Vertices ersetzt werden, falls sie außerhalb des Viewing/Clipping Volumes liegen.

Die Pipeline sieht grob wie folgt aus:

Die Pipeline gliedert sich in verschiedene Stufen, wobei nicht alle zwingend durchlaufen

werden. Wenn nicht mit Texturen gearbeitet wird, werden diese natürlich auch nicht im

Rasterizer beachtet. Die Pipeline selbst lässt sich im Grunde in 2 Hauptstufen gliedern, die

selbst wiederum in mehrere Stufen gegliedert sind. Die erste Stufe arbeitet noch mit

Geometriedaten. Hier werden die Koordinatentransformationen, Lichtberechnungen usw.

durchgeführt. Am Ende der Geometriestufe, die auch T&L Stufe (Transform&Lighting)

genannt wird, wandern die Vertices in den Rasterizer. Im Rasterizer werden anhand der

Vertices Fragmente erzeugt. Ab dieser Stufe sind keine Geometriedaten mehr vorhanden,

stattdessen wird die Farbe der Pixel bestimmt, welche zum Schluss auf dem Bildschirm zu

sehen sein sollen.

Die Pipeline kann komplett in Software realisiert werden, Hardware Implementationen

bringen jedoch einen beträchtlichen Geschwindigkeitsvorteil. Vor Allem der Rasterizer sollte

hardwareseitig implementiert sein, da in dieser Stufe rohe Gewalt wichtiger ist als

ausgeklügelte Algorithmen. Auf modernen Grafikkarten sitzen so genannte GPUs, das sind

Graphics Processing Unit, die die Pipeline schon bis zur Geometrieberechnung in Hardware

implementieren und dementsprechend schnell sind. Dieser Sektor entwickelt sich im Moment

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


asend schnell, im selben Zeitraum, in dem sich die Transistoranzahl heutiger CPUs

verdoppelt, verdreifacht sich die Transistoranzahl der GPUs. Die GPU, die auf einer heutigen

nvidia GeForce 4 verbaut ist, besitzt schon mehr Transistoren als ein P4 von intel.

Nachdem die Pipeline im Überblick vorgestellt wurde, widmen wir uns den Stufen im Detail.

Betrachten wir zunächst den ersten Teil der Pipeline, welcher für die Geometrieberechnungen

verantwortlich ist.

Die Geometriepipeline

Diese Stufe der Pipeline ist für die Verarbeitung der Vertices zuständig. Auf der linken Seite

betreten die Geometriedaten die Pipeline, das können Vertices, Normale, Texturkoordinaten

oder Funktionen wie zum Beispiel NURBs sein. Diese können nun zunächst in einer Display

List kompiliert und gespeichert werden, um später durch die Pipeline zu wandern, oder sie

werden direkt durch die Pipeline geschickt. Werden keine expliziten Vertices definiert,

sondern NURBs, werden diese im Evaluator zunächst in einzelne Vertices aufgebrochen und

approximiert. Die so erhaltenen Vertices werden nun in der nächsten Stufe umgewandelt und

beleuchtet (engl. Transform&Lighting, bzw. T&L). Dies bedeutet, dass die Vertices, die

zunächst nur in Objektkoordinaten vorliegen, mit der Model-View Matrix multipliziert

werden. Diese besteht aus vorher definierte Rotationen, Skalierungen, Translationen sowie

selbst bestimmte Matrizen. Als Ergebnis erhält man so genannte Eye Coordinates. Dies wird

deshalb so genannt, weil alle Vertices nun Koordinaten in einem globalen Koordinatensystem

haben, dessen Ursprung die Position des Betrachters ist. Zuvor existierte jedes Objekt in

seinem eigenen Koordinatensystem, daher der Begriff Object Coordinates. Danach werden

Objekte und Betrachter in ein gemeinsames globales Koordinatensystem gesetzt und die

Objekte Transformiert. Zum Schluss setzt man noch den Ursprung dieses Koordinatensystems

auf den Betrachter. Da dies in einem Durchgang geschieht, nennt man auch die entsprechende

Matrix Model-View Matrix. Nun stehen zwar alle Objekte in Bezug zueinander und dem

Betrachter, jedoch sieht der Betrachter nur einen bestimmten Teil der Szenen. Bei paralleler

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Projektion entspricht der sichtbare Bereich des Betrachters einem Kubus beliebiger Tiefe, bei

perspektivischer Projektion jedoch einer Pyramide, deren Spitze abgeschnitten ist. Die Spitze

schneidet man deswegen ab, weil ein gewisser Minimalabstand vom Betrachter vorausgesetzt

wird. Kommt man diesem zu nahe, hauen irgendwann in späteren Berechnungen die

Koordinaten nach unendlich ab und man erhält visuelle Anomalien. Diese geköpfte Pyramide

wird auch Frustum genannt, der sichtbare Bereich entsprechend View Frustum. Als nächstes

werden die Koordinaten mit der Projektionsmatrix multipliziert. Dies hat zur Folge, dass aus

dem Frustum ein so genannter Unit Cube wird, also der Einheitskubus. Diese Umwandlung

ist recht kompliziert, daher bietet einem die GL Utility Library (glu) eine Hilfsfunktion an, die

das übernimmt. Wurde das Frustum in den Kubus umgewandelt, werden die Z-Koordinaten

im Depth Buffer, der ein Teil des Frame Buffers ist, gespeichert. Danach werden sie

weggelassen, sodass vom Kubus nur noch ein Rechteck übrig bleibt. Daher nennt man diesen

Vorgang auch Projektion, obwohl eigentlich nur ein Volumen in ein anderes umgewandelt

wird. Als nächstes steht das so genannte Clipping an. Die spezifizierten Primitiven können

nämlich ganz, zum Teil oder gar nicht im Kubus liegen. Alle Primitive, die ganz außerhalb

des Kubus liegen werden nicht zum Rasterizer geschickt. Primitive, die vollständig im Kubus

liegen werden gleich an den Rasterizer geschickt. Alle Primitive, die nur teilweise im Kubus

liegen werden abgeschnitten. Liegt zum Beispiel die Spitze eines Dreiecks außerhalb des

Kubus, wird dieses Vertex durch 2 Vertices, die genau am Rand des Kubus liegen, ersetzt. So

wird weiter verfahren, bis alle Primitive so umgewandelt wurden, dass sie komplett im Kubus

liegen. Als nächstes folgt dann noch eine Umwandlung der Koordinaten in Window

Coordinates. Schließlich kann die Szene in einem Rechteck dargestellt werden, und nicht

immer nur in einem Quadrat, was zur folge hat, dass die gesamte Szene gestaucht werden

muss und dann skaliert. Wurde auch diese letzte Umwandlung abgeschlossen, werden die

Vertices, Normalen oder Texturkoordinaten an den Rasterizer geschickt.

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Der Rasterizer

Die Aufgabe des Rasterizers ist, anhand der übergebenen Primitiven Fragmente zu erstellen.

Hierzu unterteilt der Rasterizer das zu erstellende Bild oder auch den Frame in ein

Rastergitter dessen Koordinaten den Pixelkoordinaten des Frames entsprechen. Ein Fragment

ist ein Quadrat aus diesem Gitter das außerdem noch als Parameter eine zugewiesen Farbe,

Tiefeninformation aus dem Z-Buffer und Texturkoordinaten enthält. Das Quadrat muss

allerdings nicht unbedingt quadratisch sein, OGL kommt auch mit Rechtecken zurecht, der

Einfachheit halber nehmen wir jedoch Quadrate an.

Der Rasterizer bekommt nun eine Primitive von der T&L Pipeline übergeben. Anhand dieser

Primitiven erstellt er Fragmente. Werden zum Beispiel die 3 Vertices eines Dreiecks

übergeben, muss der Rasterizer alle Fragmente im Gitter finden, die innerhalb oder an den

Kanten dieses Dreiecks liegen. Außerdem muss er noch die Farbwerte dieser Fragmente

bestimmen, indem er die Farben der Vertices beachtet, welche zuvor schon beleuchtet wurden

und dazu die Farben, die man aus der Textur erhält. Texturen sind in aller Regel 2

dimensionale Bilder, die auf Flächen „geklebt“ werden, um diesen ein realistischeres

Aussehen zu verleihen, es gibt allerdings auch 1 und 3 dimensionale Texturen. Ohne Texturen

hätten Polygone nur Farbverläufe und Schattierungen. Für CAD Anwendungen, z.B. dem

Konstruieren von Bauteilen, reicht dies meist auch aus. Soll eine Szene dagegen möglichst

realistisch aussehen, kommt man um Texturen nicht herum, da man nur durch diese

Fotorealismus erreichen kann, indem man zum Beispiel einfach mit einer Kamera ein Foto

einer realen Betonwand mit Strukturen macht, dieses Bild digitalisiert und als Bilddatei

abspeichert. Danach kann man es in seine Szene laden und auf seine eigene Wand kleben, was

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


erheblich realistischer wirkt als ein flaches Grau mit Schattierung. Allerdings sind Texturen

auch weit rechenintensiver als einfarbige Flächen, weshalb sie nicht beliebig viel und groß in

einer Szene vorkommen dürfen, damit man die Szene noch flüssig wahrnimmt. Bei Szenen

ohne Bewegung ist das natürlich egal.

Texturen müssen in OpenGL zunächst quadratisch sein und eine Kantenlänge aufweisen, die

eine 2er Potenz ist, zum Beispiel 256x256 Pixel. Um eine Textur auf ein Polygon zu kleben,

müssen die Eckpunkte der Textur mit Vertices des Polygons verbunden sein. Dieses „Kleben“

nennt man auch mappen, daher kommt der Begriff Texture Mapping.

Nach dem Texturing kann man noch Anti-Aliasing, Atmosphäreneffekte und Ähnliches

durchführen. Hat der Rasterizer Fragmente erstellt, wandern diese in der Pipeline weiter. Ab

hier existieren keine Geometriedaten mehr, es geht jetzt nur noch darum, welche Farbe die

letztendlich darzustellenden Pixel auf dem Bildschirm haben sollen. Es existiert nur noch eine

Tiefeninformation im Depth Buffer, damit ein verdecktes Dreieck, das nach dem

verdeckenden durch die Pipeline wandert, nicht das vordere wieder überschreibt.

Per-Fragment Operationen

Fragmente, die die letzte Stufe der Pipeline komplett durchlaufen, landen zum Schluss im

Frame Buffer. Der Frame Buffer ist ein Speicherbereich, der heutzutage für gewöhnlich im

RAM der Grafikkarte liegt. In ihm werden verschiedene Werte der berechneten Pixel von

OpenGL abgelegt. Der Frame Buffer besteht dabei meist nicht nur aus einem Speicherbereich,

sondern aus mehreren, in welchen entweder Farbwerte, Tiefeninformationen etc. abgelegt

werden. Die Bereiche heißen color, depth, stencil und accumulation buffer, allerdings sind

diese nicht immer zwingend vorhanden. Mit dem accumulation buffer kann man zum Beispiel

Bewegungsunschärfe oder Tiefenunschärfe simulieren, sind diese Effekte allerdings nicht von

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


der Applikation gewünscht, werden diese Buffer auch nicht angelegt. Wurde eine Szene

komplett zu Ende gerendert, wird der Inhalt des Frame Buffers auf dem Monitor ausgegeben,

falls die vertikale Synchronisation aktiviert ist. Bei heutigen Grafikkarten kann man diese

allerdings auch abschalten, was „Reißeffekte“ (auch Tearing genannt) zu Folge haben kann,

wenn nämlich der Frame Buffer ausgegeben wird, während die Engine das Bild noch nicht zu

Ende gezeichnet hatte.

Nicht aus jedem Fragment wird jedoch schließlich ein Pixel, vorher muss es noch einige Tests

bestehen, allen voran den Depth Test, um festzustellen, ob das Fragment nicht von einem

schon im Frame Buffer abgelegten Fragment verdeckt wird und somit nicht sichtbar ist.

Hier zeigt sich auch ein Problem, das sich Overdraw nennt. Die Vertices wandern durch die

Geometriepipeline und werden dort beleuchtet, wandern durch den Rasterizer, Fragmente

werden erstellt und texturiert, Atmosphäreneffekte berechnet, nur um zum Schluss

festzustellen, dass die Fragmente dieser Primitive eigentlich gar nicht sichtbar sind. Heutige

Grafikkarten verbraten viel Rechenzeit wegen dieses Overdraws. Moderne Karten

implementieren deshalb immer häufiger ausgeklügelte Algorithmen in Hardware, um den

Overdraw möglichst zu minimieren und nicht unnötige Berechnungen anzustellen. Dennoch

ist der heutige Stand der Technik so, dass man lieber versucht, dreimal so schnell zu rendern,

anstatt die Hälfte von vorneherein auszuschließen. Die Chips sind auch nicht wirklich zu

langsam für die gestellten Aufgaben, das eigentliche Problem liegt in der benötigten

Bandbreite, um die Daten vom RAM der Grafikkarte zum Chip zu schaufeln. Diese nimmt

außerdem dramatisch zu, je mehr Texturen eine Szene enthält, zumal heutzutage meist nicht

nur eine Textur, sondern gleich mehrere für eine Primitive verwendet werden, ein Beispiel

wäre hier Bump Mapping oder auch Lightmaps. Durch den erhöhten Bedarf an Bandbreite

erklärt sich auch der hohe Preis heutiger Consumerhighendgrafikkarten. Nicht der Chip treibt

die Preise in die Region von knapp 500 Euro, sondern der verwendete Speicher. Im Moment

kommen Hochleistungs-DDR-SDRAMs zu Einsatz mit einer Latenz von ca 3,8 ns. Normales

RAM arbeitet in der Regel bei 7-8 ns. Da dieses schnelle RAM so teuer ist, und die

Grafikkarten auch schon 128 MB an RAM besitzen, erklärt dies den teuren Preis. Allerdings

reicht der Speicher trotzdem nicht aus, um den Chip auszulasten. Bestes Beispiel ist hier die

GeForce2 Ultra, die Schätzungen zufolge ihre GPU im Schnitt nur zu 40% auslastet. Daher

muss man auch differenzieren zwischen der Anzahl an MP (Megapixel) oder auch GP

(Gigapixel), die nun der Chip selbst pro Sekunde verarbeiten kann (das ist meist die hohe

Zahl, die auf der Verpackung und in der Werbung steht) und dem, was die Karte inklusive

Memory Subsystem zu leisten vermag, was vielleicht grade mal ein Viertel oder ein Drittel

dessen ist, was der Chip zu leisten im Stande ist, jedoch entscheidend für die wirkliche

Performance der Karte ist. Schließlich kann man auch einen Ferrari Motor in einen Trabbi

einbauen, man sollte allerdings nicht erwarten, dass dieser dann auch so fährt wie ein Trabbi,

da nicht nur der Motor sondern auch das Fahrwerk und andere Komponenten für die

tatsächliche Leistung berücksichtigt werden müssen.

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Ein kleines Programmbeispiel

Nun folgt ein Beispiel eines kleinen Programms, mit dem man Dreiecke auf dem Bildschirm

ausgeben kann. Dabei werden nur die beiden init() und draw() Methoden vorgestellt, Code,

der das Fenster erstellt, mit einem Rendering Kontext verknüpft, Event Handling und

dergleichen, das plattformspezifisch ist, wird hier weggelassen. Man kann allerdings mit Hilfe

der Glut Bibliothek recht schnell ein OGL Fenster erstellen, da diese einem die meiste Arbeit

abnimmt. Dies hat außerdem den Vorteil der Plattformunabhängigkeit. Ich lasse den Code

trotzdem weg, damit nur OpenGL spezifischer Code übrig bleibt.

Zunächst wird die init() Methode aufgerufen. Dies geschieht in der Regel nur einmal, um

bestimmte Zustände zu setzen, z.B. ob Lichtberechnung stattfinden soll oder nicht.

Alle Kommandos in OpenGL gehorchen folgender Syntax:

rtype Name {E1234} {E b s i f d ub us ui} {E v } ( [args ,] T arg1, …, T argN [, args] );

Hierbei entspricht rtype dem Rückgabtyp der Funktion. Die Zahl nach dem Namen entspricht

der Anzahl an Parametern, die die Funktion erwartet. Als nächstes wird der Datentyp

angegeben, zum Beispiel ob eine Zahl float (f) oder unsigned integer (ui) ist. Danach kann

man angeben, ob die Parameter einzeln übergeben werden, oder ein Vektor (v), der die Werte

enthält. Der Name selbst beginnt mit dem Kürzel der jeweiligen Bibliothek, Kernfunktionen

der OGL API mit glName, andere Funktionen entsprechend gluName, glxName, glutName,

wglName usw.

init(void)

{

glShadeModel( GL_SMOOTH );

glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );

glClearDepth( 1.0f );

glEnable( GL_DEPTH_TEST );

glDepthFunc( GL_LEQUAL );

glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

}

glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient );

glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse );

glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );

glEnable( GL_LIGHT0 );

glEnalbe( GL_LIGHTING );

glMatrixMode( GL_PROJECTION );

glLoadIdentity();

gluPerspective( 90.0f, width / height, 0.1f, 100.0f );

glMatrixMode( GL_MODELVIEW );

glLoadIdentity();

Hier werden nun zunächst einige Einstellungen vorgenommen. Zunächst wird das

Shademodel festgelegt, das bedeutet, ob eine Primitive nur einen Normalenvektor für die

gesamte Fläche und alle Vertices annehmen soll (=Flat Shading), oder ob jedes Vertex einen

eigenen Normalenvektor haben kann und somit Gouraud Shading möglich wird. Eine

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Normale ist ein Vektor, dessen Anzahl an Komponenten gleich der Dimension des Raumes

entspricht, in dem er liegt. Normale werden immer mit Vertices assoziiert, auf denen sie

senkrecht stehen, daher auch der Name Normale, wie er aus der Mathematik bekannt ist.

Normale werden benötigt, um Lichtberechnungen auf den einzelnen Vertices durchzuführen.

Wenn man zum Beispiel einen 6-flächigen Würfel hat, der aus 6 Vierecken besteht, müssen

die Normalen der Vertices des oberen Vierecks nach oben zeigen, die Normalen der Vertices

des unteren Vierecks nach unten, die des vorderen Vierecks zum Betrachter, usw. Würde man

jetzt die Normalen des unteren Vierecks nicht nach unten, sondern noch oben zeigen lassen,

würde die Fläche, die im Würfel liegt, beleuchtet werden, während die andere Seite, die von

außen zu sehen ist, schwarz bleiben würde. Die Normalen sind also wichtig, um die

Geometrie eines Objekts OpenGL mitzuteilen. Falsch gesetzte Normale können

unvorhersehbare Auswirkungen haben. Werden Farben verwendet, ist die Primitive bei Flat

Shading einfarbig, bei smooth shading werden die Farben über die Fragmente der Primitive

interpoliert. Als nächstes wird die Farbe des gesamten Fensters auf schwarz gesetzt.

Farbangaben sind „clamped“, das heißt der Wert liegt zwischen 0 und 1. Da bei der Erstellung

des Fensters RGBA als Farbmodus gewählt wurde, besteht die Angabe aus 4 Werten. Als

nächstes werden noch einige Zustände aktiviert, außerdem werden Informationen zur

Lichtberechnung übergeben. lightAmbient, lightDiffuse und lightPosition sind dabei 3dim.

Arrays, die woanders zunächst erstellt wurden, und schließlich wird das Licht selbst aktiviert.

So kann allerdings noch keine Lichtberechnung stattfinden, diese muss zunächst noch per

glEnable eingeschaltet werden, was in der Zeile darauf geschieht. Man kann dies allerdings

auch zum Beispiel mit einem Tastendruck verbinden, um zur Laufzeit Lichtberechnung ein-

und auszuschalten. Als nächstes wird die Projektionsmatrix festgelegt. glLoadIdentity() lädt

dabei die Identitätsmatrix und löscht dabei den Matrixstack. Die Hilfsfunktion gluPerspective

nimmt einem das Berechnen der Projektionsmatrix ab. Danach wird in den Matrixmodus

MODELVIEW geschaltet. Dies bedeutet, dass alle ab jetzt spezifizierten Matrizen mit der

MV-Matrix multipliziert werden. Würden wir hier nicht umschalten, würde alles auf die

Projektionsmatrix multipliziert werden. Zum Schluss wird die Identität geladen, was einem

Reset der Matrixstacks gleichkommt. Nun sind wir bereit, unsere Primitiven zu zeichnen.

render(void)

{

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glLoadIdentity();

glTranslatef( 0.0f, 0.0f, -10.0f );

glPushMatrix();

glRotatef( angle0, 0.0f, 1.0f, 0.0f );

glColor4f( 0.5f, 0.5f, 0.5f, 0.5f );

glBegin( GL_TRIANGLES );

glNormal3f( 0.0f, 0.0f, 1.0f );

glVertex3f( -1.0f, -1.0f, 0.0f );

glVertex3f( 1.0f, -1.0f, 0.0f );

glVertex3f( 0.0f, 1.0f, 0.0f );

glEnd();

glPopMatrix();

glTranslatef( 0.0f, 3.0f, 0.0f );

glRotatef( angle0, 1.0f, 1.0f, 0.0f );

glBegin( GL_QUADS );

glColor4f( 1.0f, 0.0f, 0.0f, 0.5f );

glNormal3f( 0.0f, 0.0f, 1.0f );

glVertex3f( -1.0f, -1.0f, 1.0f );

glVertex3f( 1.0f, -1.0f, 1.0f );

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


}

glVertex3f( 1.0f, 1.0f, 1.0f );

glVertex3f( -1.0f, 1.0f, 1.0f );

glEnd();

angle0 += 3.0f;

glFinish();

glutSwapBuffers();

Mit dem Befehl glClear werden nun die Bitplanes der verschiedenen Puffer des Frame

Buffers zurückgesetzt. Schließlich wollen wir nicht die angaben des vorhergehenden Frames

beibehalten. Per Translatef geben wir an, um wie viel alle nachfolgenden Objekte verschoben

werden sollen. glPushMatrix() setzt so etwas wie einen Speicherpunkt im Matrixstack. Alle

Matrizen, die von nun an dazumultipliziert werden, können später mit dem Befehl

glPopMatrix() wieder gelöscht werden. Das ist zum Beispiel hilfreich, will man ein Objekt

rotieren lassen, aber die danach folgenden nicht, oder auf einen anderen Winkel. Bisher haben

wir nur Zustände gesetzt, jedoch noch nichts gezeichnet. Dies folgt nun. Alle Primitive

werden mit glBegin() und glEnd() eingeklammert. glBegin bekommt noch mitgeteilt, um was

für eine Primitive es sich handelt, ob Dreick, Viereck, Polygon usw. Davon hängt auch ab,

wie die folgenden Vertices behandelt werden. Zeichnet man Dreiecke, werden 3 Vertices

jeweils zu einem Dreieck zusammengefasst. Sollte zum Schluss ein oder zwei Vertices übrig

bleiben, werden sie ignoriert. Bei einem Polygon hingegen werden alle Vertices beachtet, das

Polygon muss jedoch konvex sein. Ein Vertex kann per 3 Parameter erzeugt werden, diese

Koordinaten liegen in Object Coordinates vor. Alternativ könnte man auch ein Array mit 3

Werten übergeben, dann wäre der Befehl glVertex3fv( array ). Wurden die Vertices erzeugt,

beendet man die Primitive per glEnd(). Je nach Art der Primitive können dabei zwischen

glBegin und glEnd beliebig viele Primitive erzeugt werden. Als nächstes wird eine Rotation

bestimmt. Die 4 Parameter sind der Winkel, um den rotiert wird sowie der Vektor, um den

rotiert wird. Zum Schluss wird mit glFinish() noch angegeben, dass alle abgesetzten Befehle

vollständig abgearbeitet werden soll. Als letztes wird der Pointer des Frame Buffers auf den

neuen Framebuffer gesetzt. Hierzu muss die Hardware double buffering unterstützen, was

heutzutage bei praktisch allen Karten der Fall ist. Dabei schreibt OpenGL nicht immer auf

denselben Speicherbereich, sondern hat 2 Puffer, wobei der eine angezeigt wird, während der

andere geschrieben wird. Ist das Bild vollständig, wird der Pointer auf den Frame Buffer

einfach umgebogen. Würde man dies nicht so machen, würde man entweder auf dem

Bildschirm sehen können, wie die Szene Schritt für Schritt gezeichnet wird, oder man würde

offscreen rendern und müsste dann zum Schluss den Inhalt des neuen Bildes in den Frame

Buffer kopieren, wodurch man Zeit verlieren würde.

Alle OpenGL Szenen werden durch diese Grundbausteine aufgebaut, letzten Endes sind alles

Primitive, aus denen dann eine komplexe Welt aufgebaut werden kann. Komplexere Objekte

werden jedoch nicht von Hand erstellt, in aller Regel benützt man dazu professionelle

Software wie 3D Studio oder Maya und exportiert die Modelle dann in eine Datei. Als

nächstes muss man für seine eigene Applikation einen Loader für diese Dateien schreiben, der

automatisch die Modelle, auch Meshes genannt, erstellt.

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem


Die Zukunft von OpenGL

OpenGL ist der weitverbreitetste Industriestandard zurzeit. Dadurch, dass im ARB die

Industriegrößen vertreten sind, ist auch gewährleistet, dass OpenGL nicht als Akademie API

an den Wünschen der Zeit vorbeigeht. Außerdem ist OpenGL sehr schnell, da im Immediate

Mode Primitive sofort verarbeitet werden, sobald man sie erstellt. Es muss also nicht darauf

gewartet werden, bis formal das gesamte Objekt einmal beschrieben wurde, das Objekt wird

schon gezeichnet, sobald das erste Dreieck erstellt wurde.

Leider hat sich in OpenGL seit der Version 1.3 nicht allzu viel getan, und diese ist nun auch

schon einige Jahre alt. Deswegen entwickelt sich auch das System, das API per Extension zu

erweitern, als Nachteil. Extensions müssen nicht vom ARB abgesegnet sein, jeder Hersteller

darf Extensions spezifizieren. Im Gegenzug müssen jedoch Implementationen anderer

Hersteller diese Extensions auch nicht unterstützen, nur was zum offiziellen OpenGL Kern

gehört, muss von allen unterstützt werden. Mittlerweile ist jedoch die Liste der Extensions

länger als die der eigentlichen OpenGL Funktionen, was damit zu tun hat, dass sich die

Hardware rasend schnell in den letzten Jahren entwickelt hat. Ein API wie D3D hat es da

leichter, Schritt zu halten, da hier nur Microsoft entscheidet, was ins API kommt und was

nicht. Das Ausufern der Extensions verwässert jedoch den Gedanken, dass OpenGL

implementationsunabhängig sein soll. Insbesondere das Aufkommen der Vertex und Pixel

Shader haben dazu geführt, dass diese bei jedem Grafikkartenhersteller über eine andere

Extension unterstützt werden. Diese Shader sind deshalb so wichtig, weil sie die Pipeline

programmierbar machen, diese also nicht mehr starr ist. Daher ist es auch nötig, dass das

Ansprechen der Shader einheitlich ist, und nicht für jeden Kartenhersteller verschieden.

Die Lösung für dieses Problem lautet OpenGL 2.0. Initiator ist hierbei 3DLabs, die auf große

Resonanz im ARB gestoßen sind und das Projekt vorantreiben. OpenGL wird die Shader

beinhalten, außerdem noch viele andere Neuerungen, soll aber trotzdem abwärtskompatibel

bleiben, sodass alte OpenGL Programme trotzdem noch unterstützt werden. OpenGL 2.0

könnte dieses oder nächstes Jahr verabschieden, die White Paper der neuen Version sind auf

der Website von 3DLabs verfügbar

(http://www.3dlabs.com/support/developer/ogl2/index.htm ).

Proseminar Computergrafik

Thema: OpenGL

Autor: Uygar Kalem

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

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!