DirectX vs. OpenGL
Transcrição
DirectX vs. OpenGL
Projektarbeit Computergraphik DirectX vs. OpenGL Fachbereich: 12. Informatik Betreut durch Prof. Dr. Xiaolin Zhou von Patrick Schmid, Christian Piwecki 4. Juli 2005 INHALTSVERZEICHNIS Projekt Graphik Inhaltsverzeichnis 1 Grafikengines 2 1.1 Was ist eine Grafikengine ? . . . . . . . . . . . . . . . . . . . 2 1.2 Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Bekannte Grafikengines . . . . . . . . . . . . . . . . . . . . . 3 1.4 Meilensteine von 3D Grafik Engines . . . . . . . . . . . . . . 5 2 Schnittstellen für Grafikengines 7 3 Bekannte Grafikschnittstellen 8 3.1 3.2 OpenGL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.1.1 Geschichte . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.1.2 Was ist OpenGL ? . . . . . . . . . . . . . . . . . . . . 8 3.1.3 Leistungsfähigkeit . . . . . . . . . . . . . . . . . . . . 8 3.1.4 Entwicklung . . . . . . . . . . . . . . . . . . . . . . . . 19 DirectX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.2.1 Geschichte . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.2.2 Was ist DirectX ? . . . . . . . . . . . . . . . . . . . . 20 3.2.3 Leistungsfähigkeit . . . . . . . . . . . . . . . . . . . . 21 3.2.4 Entwicklung . . . . . . . . . . . . . . . . . . . . . . . . 29 4 Unterschiede DirectX und OpenGL 32 5 Projekt-Fazit 34 6 Literaturverzeichnis 35 7 Anhang 36 7.1 Open GL Funktionsliste . . . . . . . . . . . . . . . . . . . . . 36 7.2 Realisierung eines Würfels unter OpenGL . . . . . . . . . . . 38 7.3 Realisierung eines Würfels unter DirectX . . . . . . . . . . . . 46 Abbildungsverzeichnis 1 Flag-Erklärung,Diffuse & Ambient Light . . . . . . . . . . . . 14 2 Eine Primitive mit 3 Vertices . . . . . . . . . . . . . . . . . . 24 3 Die Direct3D-Rendering-Pipeline . . . . . . . . . . . . . . . . 27 1 1. Grafikengines 1 Projekt Graphik Grafikengines 1.1 Was ist eine Grafikengine ? Die Grafikengine ist ein eigenständiger Programmteil. Sie ist zuständig für die Darstellung von Computergrafik. Grafikengines sind für Programmierer eine große Hilfe, da sie oft benötigte Standardfunktionen besitzen um umfangreiche Computergrafiken zu erstellen, ohne diese neu programmieren zu müssen. Sie beinhalten meist allgemein folgende Funktionen: • Geometrische Objektbeschreibung • Oberflächentexturen • Licht und Schatten • Transparenz • Spiegelungen Darüber hinaus können Grafikengines auch weitere Aufgaben erfüllen. Eine Grafikengine zeichnet sich durch extrem aufwendige Optimierungen und Berechnungen aus. Die Grafikengine ist eigentlich Bestandteil der Game Engine - wird aber separat für andere Applikationen verwendet, die 3D - Grafiken darstellen müssen. 1.2 Funktionen Eine Grafik- bzw. 3D - Engine hat die Aufgabe Objekte, die sowohl zweials auch dreidimensional sein können, in einem 3D Raum zu erstellen, anzuzeigen und zu bewegen. Der dreidimensionale, virtuelle Raum ist über ein Koordinatensystem mit x-, y- und z- Achse implementiert. Die x - Koordinaten befinden sich im horizontalen Bereich des Bildschirms, die y Koordinaten im vertikalen und die z - Koordinaten geben an wie tief ein Objekt im Bildschirm liegt. Da für eine umfangreichere dreidimensionale Darstellung viel Rechenarbeit benötigt wird setzt man zusätzliche Hardware in Form von GPUs (Graphics Processing Unit) auf Grafikkarten ein um die CPU zu entlasten. Mit diesem zweiten Prozessor wird es möglich, dass Algorithmen parallelisiert abgearbeitet werden. Die am häufigsten verwendeten Programmbibliotheken, die Grafikkarten ansprechen sind OpenGL und DirectX. Es gibt sicherlich sehr viele unterschiedliche Möglichkeiten eine Grafikengine zu implementieren. Bewährt hat sich aber, die Objekte mit Hilfe von Polygonen aufzubauen, diese nach bestimmtem Schema zu verbinden und die entstehenden Flächen mit einer Textur zu belegen. Polygone sind einfache Punkte im 3D - Raum. Jedes Polygon besitzt eine x -, eine y - sowie eine z - Koordinate. 2 1.3 Bekannte Grafikengines Projekt Graphik Die Texturen können in weiterentwickelten 3D- Engines noch weiter mit Bumpmaps überzogen werden, die der Textur ein plastisches Aussehen verleihen. Darüber hinaus gibt es Partikeleffekte mit denen sich beispielsweise Explosionen, Nebel, Feuer, Schmutz und Wasser realitätsnah darstellen lassen. Ein Partikel ist ein kleines Teilchen - also ein einzelnes Polygon - das mit einer Textur überzogen ist. Sie werden meist von Partikel - Emittern erzeugt, die eine größere Anzahl mit unterschiedlichen Eigenschaften wie Geschwindigkeit, Richtung und Lebensdauer ausstoßen. Die neuste Entwicklung auf diesem Gebiet sind Pixel- und Vertex - Shader. Ein Pixelshader ist ein Assemblerprogramm, das direkt auf der Grafikkarte ausgeführt wird. Sie sind also hardwareabhängig. Mit ihrer Hilfe können Effekte wie Spiegelungen, Schattierungen, Falloff, Lensglow, Lensflares auf Basis von Materialeigenschaft und Textur sehr realitätsnah implementiert werden. Ein Vertexshader berechnet Änderungen von Form und Lichteinfall von/auf ein 3D - Objekt. Texturen und Oberflächen werden jedoch nicht berechnet. Nach dem Vertexshader kommt der Pixelshader zum Einsatz. 1.3 Bekannte Grafikengines Meist tragen Grafikengines den Namen seiner Anwendung. Dennoch werden oft Grafikengines programmiert, die eigene Nämen tragen. Grafikengines werden oft über viele Jahre hinweg zum Einsatz kommen. Mit ihrem Alter sinkt auch der Kaufpreis da auch die Möglichkeiten die man mit Grafikengines hat zeitlich begrenzt sind. Ein kleiner Überblick bekannter Grafikengines und deren Verwendung verdeutlicht diese rasante Entwicklung: • Quake-Engine (1996-1999) Die Quake-Engine wurde erstmals 1996 im Spiel Quake verwendet. Als erste Grafikengine konnte sie 3D Polygonemodelle darstellen anstelle von 2D Sprites. Dynamische Beleuchtungsmethoden wurden erstmals verwendet u.a. Lightmaps, Real-Time-Lightsourcing. Erstmals hatte man die Möglichkeit einen 3D-Grafikkartenbeschleuniger zu verwenden. Sie wurde bis 1999 von ID-Software vertrieben und 1999 als Open Source herausgegeben. Die Quake3 Engine war die meist verkaufteste Grafikengine jemals. Kaufpreis damals ca. 250 000 US Dollar • Unreal-Engine (1998-2007?) Von Epic Software kam 1998 die Unreal Engine. Sie sollte damals der Quake Engine das Wasser reichen können. Noch heute ist diese Engine im Einsatz und wird noch weiterentwickelt. Kaufpreis ca. 350 000 - 500 000 US Dollar 3 1.3 Bekannte Grafikengines Projekt Graphik • CryENGINE (2003) CryTek veröffentlichte 2002 die CryENGINE, welche schon zuvor in kleineren Grafikdemos wie das X-Isle Demo zum Testeinsatz kam. Die CryENGINE ist die erste Grafikengine, welche aus Deutschland kam und im US Markt eine echte Begeisterung auslöste. Als erste Engine hatte diese u.a. die Möglichkeit physikalisch korrekt berechnete Effekte einzusetzen. Über den Kaufpreis gibt es derzeit keine Angaben. • Source Engine (2004) Valve Software veröffentlichte ihre neueste Engine 2004. Sie ist sozusagen wie die CryENGINE State-of-the-Art. Unterstützung aller DirextX Versionen von 6-9, physikalische Effekte usw. Die Engine ist noch im Einsatz und wird sehr oft lizenziert. Kaufpreis ca. 400 000 - 500 000 US Dollar 4 1.4 Meilensteine von 3D Grafik Engines 1.4 Projekt Graphik Meilensteine von 3D Grafik Engines Dank ihrer Grafikengines verdanken viele Meilensteine der PC Spiele Geschichte ihr Dasein. Einige dieser als kurze Auflistung mit Spielname, Firma und Erscheinungsjahr zum Überblick: • Doom (Id Software, 1993) • Doom II (Id Software, 1994) • Quake (Id Software, 1995) Quake II (Id Software, 1996) • Unreal (Epic Games, 1998) • Quake III (Id Software, 1999) • Unreal Tournament 2003 (Epic Games, 2002) • Far Cry (Crytek, 2004) • Doom 3 (Id Software, 2004) • Half-Life 2 (Valve, 2004) Neben den großen und bekannten Grafikengines gibt es auch noch weniger bekannte, aber dennoch auf dem Markt existente. • 3DGM • A6 • Blitz • Cipher • DB / DBPro • Jamagic • Jupiter • Mad F/X 1.0 • PR • Quest • Radish • RF • TV3D • Torque 5 1.4 Meilensteine von 3D Grafik Engines Projekt Graphik Die bisher angegeben Engines sind rein kommerzieller Natur, aber es gibt auf dem Markt auch eine große Anzahl von Open Source Grafikengines. Einige dieser Engines in dieser Auflistung: • Irrlicht Engine • Nebula2 EngineCrystalSpace3DEngine • zFXc Engine • Ogre-Engine C++ • Axiom-Engine C# (.NET Portierung der Ogre-Engine) 6 2. Schnittstellen für Grafikengines 2 Projekt Graphik Schnittstellen für Grafikengines Die Schnittstelle ist ein plattform- und programmiersprachenunabhängiges API (Application Programming Interface). Sie ist nur eine standardisierte Programmbibliothek und somit keine Implementierungen. Die Befehle werden erst vom Betriebsystem übersetzt und an den Grafikkartentreiber übermittelt. Der Treiber gibt die Befehle dann an die Grafikkarte bzw. an die CPU weiter, falls die Grafikkarte für einen bestimmten Befehl nicht qualifiziert ist. Der Grafikkartenhersteller muss also in Form des Treibers die Implementierung gewährleisten. 7 3. Bekannte Grafikschnittstellen 3 Projekt Graphik Bekannte Grafikschnittstellen 3.1 3.1.1 OpenGL Geschichte OpenGL (Open Graphics Library) entwickelte sich aus der sogenannten IrisGL von SGI. Sie wurde entwickelt um Programme mit GL - Unterstützung portierfähiger zu machen da die IirisGL nur auf SGI - Computer lief. Um einen hohen Verbreitungsgrad zu erreichen hatte auch ARB (Architecture Review Board) Einfluss auf das Design der Programmbibliothek. Die ARB ist ein Zusammenschluß von mehreren Soft- sowie Hardwarefirmen darunter 3D Labs, ATI, Apple, Dell, HP, Matrox, nVidia, IBM, Intel, Microsoft (bis März 2003), Silicon Graphics, Digital Equipment (DEC), Evans Sutherland und Intergraph, die sich vier mal im Jahr treffen um über die Zukunft des Standards zu diskutieren. Die ARB entwickelte einen sogenannten Conformance Test. Jede neue Version von OpenGL muss diesen Test positiv durchlaufen um veröffentlicht zu werden und damit gewährleistet werden kann dass die verschiedenen Versionen kompatibel sind und gleiche Ergebnisse liefern. Die Kosten für diese Test sowie für die Verwaltung werden über Lizenzzahlungen finanziert. Eine Lizenz kostet je nach Art zwischen 25000 und 100000 Dollar einmalig und 5 Dollar pro verkaufter Kopie der Bibliothek. Das gilt jedoch nur für Versionen die den Conformance Test durchlaufen haben. Andere OpenGl - Implementationen können ebenfalls veröffentlicht werden, für diese müssen keine Lizenzen bezahlt werden - dürfen sich aber auch nicht OpenGL nennen. 3.1.2 Was ist OpenGL ? OpenGL ist neben DirectX eine der wichtigsten Schnittstellen für Grafikengines. Im Gegensatz zu DirectX, das von Microsoft stammt ist OpenGL ein Open Source Projekt. Das heißt die OpenGL wird laufend weiterentwickelt und steht jedem kostenlos zur Verfügung. 3.1.3 Leistungsfähigkeit OpemGL verfügt über eine große Anzahl von Funktionen mit denen Anwendungen über eine Ansammlung von Bibliotheken komfortabel und einfacher gestaltet werden können. Die wichtigsten sind die Utility Library (GLU), deren Funktionen auf OpenGL aufbauen und das Werkzeug OpenInventor, das Szenenbeschreibungen als Text- oder Binärdatei einlesen bzw. schreiben kann. Das Format mit dem OpenInventor arbeitet ist gleichzeitig grundlage für den Standard VRML (Virtual Reality Modeling Language). VRML wird für Erstellung von 3D - Szenen im Internet verwendet. Weitere wichtige Bestandteile sind: 8 3.1 OpenGL Projekt Graphik • GLX -> Schnittstelle zwischen X - Window - System und OpenGL • WGL -> Schnittstelle zwischen Windows und OpenGL • AGL und CGL -> Schnittstelle zwischen MAC und OpenGL • GLUT -> Bibliothek die auf den Paketen OpenGL, GLU, GLX und je nach Plattform auf GLX, WGL oder AGL aufbaut und darüber hinaus eine plattformunabhängige API für Erstellung von RenderingContexten sowie für Ein- und Ausgabe beinhaltet. • Java3D -> API für Java um 3D Anwendungen für Java 2 Environments zu entwickeln • OpenAL -> Open Audio Library für 3D - Raumklang • GLSL -> OpenGL Shading Language für direktes Programmieren der Grafikhardware • SDL -> Simple DirectMedia Layer: freie Multimedia-Bibliothek Um Unabhängigkeit zu Rechnertyp und Betriebsystem zu erhalten verzichtet OpenGL komplett auf Funktionen, die Fenster verwaltet, Eingaben von Maus/Tastatur verwaltet und Funktionen zur Dateiein- bzw. Ausgabe. All das muss vom Betriebsystem für die jeweilige Plattform zur Verfügung gestellt werden. In OpenGL werden keine Objekte als Ganzes gezeichnet. Stattdessen werden alle Punkte, Polygone und Linien (primitive genannt) sofort gezeichnet, nachdem sie der OpenGL übergeben worden sind. Alle gezeichneten primitives werden sofort “vergessen“. Die Applikation gibt also an welche primitives gezeichnet werden und mit welchen Einstellungen. Neben den primitives (also den Objekten bzw. was gezeichnet wird) gibt eine große Auswahl von Eigenschaften an wie etwas gezeichnet werden soll. Diese Einstellungen können jederzeit geändert werden und wirken sich auf alle nachfolgenden Zeichenoperationen aus. Die aktuellen Einstellungen, die der Nutzer verwendet bilden einen Kontext. Es können mehrere Kontexte erstellt werden und man kann zwischen ihnen umschalten. Der aktuelle Kontext wird auch als State Machine bezeichnet, da er eine Art Statusinformation darstellt. Grundsätzliche Vorgehensweise beim Erstellen eines OpenGL - Programms: Als erstes müssen folgende Pakete includiert werden: gl.h, glu.h und glux.h Dem Linker müssen folgende Bibliotheken bekannt gemacht werden: OpenGL32.lib GLu32.lib und GLaux.lib.Dann muss ein Kontext und ein Fenster erzeugt werden. Diese beiden Objekte werden dann miteinander verbunden. Wird die GLUT Bibliothek verwendet, hat man die Möglichkeit ohne Kenntnisse von WinAPI oder MFC sehr einfach ein Fenster zu erstellen. Hierfür verwendet man folgende Funktionen: • glutInit(&argc, argv); Initialisiert die GLUT Library 9 3.1 OpenGL Projekt Graphik • glutInitWindowSize(int width, int height); Setzt die Größe des Fensters • glutInitWindowPosition(int x, int y); Setzt die Position des Fensters • glutCreateWindow(ẄindowTitle¨ ); Erstellt das Fenster mit dem Parameter als Titel • glutDisplayFunc(display); Deklariert die Funktion die für den Fensterinhalt verantwortlich ist • glutReshapeFunc(reshape); Deklariert die Funktion die aufgerufen wird, wenn das Fenster in der Größe verändert, bewegt oder minimiert/maximiert wird. • glutMainLoop(); Ermöglicht Event-Handling und ruft entsprechende Callback-Funktionen auf. Nun werden immer abwechselt am Kontext Einstellungen vorgenommen und eine Reihe von primitives, die vorher spezifiziert wurden gezeichnet. Am Ende der Applikation muss der Kontext wieder freigegeben werden bevor das Fenster wie gewohnt geschlossen wird. Wie bereits erwähnt gibt es drei Arten von primitives: Punkte, Linien und Polygone. Diese können aber noch in weiteren 10 unterschiedlichen Arten spezifiziert werden. Die am häufigsten benutzte ist sicherlich das Dreieck (Triangle). Um in OpenGL bekannt zu geben, daß eine Reihe von primitives spezifiziert wird, wird die Funktion glBegin() aufgerufen. Die Art, wie die primitives verbunden werden sollen, wird der Funktion als Parameter übergeben: – glBegin(GL TRIANGLES); Gibt an, daß immer 3 Punkte zu einem Dreieck verbunden werden – glBegin(GL QUADS); Gibt an, dass immer 4 Punkte zu einem Viereck verbunden werden – glBegin(GL POLYGON); Definiert einzelne Polygone – glBegin(GL POINTS); Behandelt jeden Vertex als einzelnen Punkt – glBegin(GL LINES); Behandelt immer jeweils 2 Vertexe als Endpunkte einer Linie 10 3.1 OpenGL Projekt Graphik – glBegin(GL LINE STRIP); Zeichnet eine Gruppe von Liniensegmenten zwischen Anfang und Ende aller Vertexen – glBegin(GL LINE LOOP); Zeichnet ebenfalls eine Gruppe von Liniensegmenten zwischen allen Vertexen; Anfang und Ende sind jedoch verbunden. – glBegin(GL TRIANGLE STRIP); Zeichnet eine Gruppe von verbundenen Dreiecken – glBegin(GL TRIANGLE FAN); Zeichnet eine Gruppe von verbundenen Dreiecken, wobei alle einen gemeinsamen Punkt besitzen (eine Art Kegel entsteht) – glBegin(GL QUAD STRIPS); Zeichnet eine Gruppe von verbundenen Rechtecken. Immer 2 Punkte des vorgehenden Rechtecks sind ebenfalls Punkte des folgenden Rechtecks. Innerhalb der Funktion glBegin kann man dann wiederum mit Funktionen jedes einzelne primitive (z.B. jeden einzelnen Punkt) sowie dessen Eigenschaften (z.B. Farbe, Texturkoordinaten, Normalen usw.) ebenfalls über spezielle Funktionen spezifizieren. Eine wichtige Funktion, die Eckpunkte für Dreiecke (Triangles) sowie für Vierecke (Quads) beschreibt ist glVertex(). Diese Funktion gibt es in 24 Ausführungen - jeweils eine für jeden Datentyp (von unsigned byte bis double). 11 3.1 OpenGL Projekt Graphik Die Gebräuchlichsten sind: – glVertex2f(x, y) die 2 Float - Werte als Parameter aufnimmt – glVertex3f(x, y, z) die 3 Float - Werte als Parameter aufnimmt – glVertex2d(x, y) die 2 Double - Werte als Parameter aufnimmt – glVertex3d(x, y, z) die 3 Double - Werte als Parameter aufnimmt. Um einem Eckpunkt eine Eigenschaft zuzuordnen, z.B. eine Farbe lässt man die Applikation bevor das primitive definiert wird, über die Funktion glColor() - von der ebenfalls je nach Datentyp mehrere Versionen verfügbar sind - eine Farbe für den jeweils folgenden Eckpunkt festlegen. Auswahl von glColor() - Versionen: – glColor3b(r, g, b) definiert eine Farbe über 3 Byte - Parameter, die für RGB stehen – glColor3f(r, g, b) definiert eine Farbe über 3 Float - Parameter, die für RGB stehen – glColor4d(r, g, b, a) definiert eine Farbe über 4 Double - Parameter, die für RGB plus einem Alpha - Wert stehen Um der OpenGL mittzuteilen, daß alle primitives beschreiben wurden wird die Funktion glEnd() aufgerufen. Zwischen glBegin() und glEnd() kann nur auf eine begrenzte Auswahl der OpenGL - Funktionen zugegriffen werden. Außerhalb stehen sie uneingeschränkt zur Verfügung. Beispiel: glBegin(GL TRIANGLES); glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(0.0f, 0.0f); glVertex2f(1.0f, 0.0f); glVertex2f(0.0f, 1.0f); glEnd(); Zeichnet ein einfaches zweidimensionales Dreieck. 12 3.1 OpenGL Projekt Graphik Um wirklich etwas sehen zu können muss das Objekt auf der z-Achse nach hinten, also in den Bereich gebracht werden, den der Bildschirm darstellt. Um Objekte zu verschieben - bzw. den Ausgangspunkt festzulegen, von dem aus das Objekt gezeichnet werden soll, verwendet man die Funktion glTranslatef() (z.B.). glTranslatef() werden 3 Float - Werte übergeben von denen der z - Wert negativ sein sollte. Diese Funktion muss vor glBegin() ausgeführt werden ! Es gibt viele Funktionen die vor einem glBegin() ausgeführt werden können. Eine vollständige Liste mit allen Funktionen befindet sich auf der Seite X. Detailierte Informationen über die Funktionen kann man in jeder Referenz nachlesen (z.B. auf http://www.rush3d.com/reference/openglbluebook-1.0/). Besonders hervorzuheben sind aber folgende Allgemeine Funktionen – glClear(red, green, blue, alpha); Leert Buffer, die in der Parameterliste angegeben werden. – glLoadIdentity(x,y,z); Ersetzt aktuelle Matrix durch Identitätsmatrix. D.h. es wird zum Ursprung zurückgesprungen. – glRotatef(angle,x,y,z); Multipliziert die aktuelle Matrix mit einer Rotationsmatrix -> das Objekt dreht sich. Als Parameter sind angle, x, y und z. Angle gibt den Winkel an mit dem gedreht werden soll. x, y und z definieren den Vektor, um den gedreht werden soll. – glShadeModel(GL SMOOTH); Wählt eine Shadingtechnik aus, die angibt, wie ein Objekt gefärbt werden soll. Wählt man den Parameter GL SMOOTH (Standard), wird der Farbverlauf zwischen den einzelnen Punkten (primitives) berechnet. Bei GL FLAT wird das gesamte Objekt in der Farbe des letzten Vertexes gefärbt. – glClearColor(red, green, blue, alpha); Definiert die Löschfarbe Lichtorientierte Funktionen – glLightf(light, pname, param); Diese Funktion setzt Lichtquellen - Eigenschaften. – light GL LIGHTi wobei i für die Nummer der Lichtquelle steht. Es gilt i <= GL MAX LIGHTS. – pname GL SPOT DIRECTION Definiert die Richtung der Hauptachse des Lichtkegels. – GL SPOT POSITION Definiert die Position der Lichtquelle. – GL SPOT EXPONENT Definiert den Wert der Verteilung der Leuchtintensität innerhalb des Lichtkegels. Je höher der Wert, desto gebündelter der Lichtstrahl. 13 3.1 OpenGL Projekt Graphik – GL SPOT CUTOFF Definiert den Winkel zwischen Hauptachse und Rand des Lichtkegels. Werte zwischen 0 und 90 sind möglich. – GL AMBIENT Definiert die RGBA Werte für ambientes Licht – GL DIFFUSE Definiert die RGBA Werte für diffuses Licht – GL SPECULAR Definiert die RGBA Werte des reflektierenden Lichts – GL CONSTANT ATTENUATION Definiert den konstanten Wert zur Berechnung der Lichtdämpfung – GL LINEAR ATTENUATIONDefiniert den linearen Wert zur Berechnung der Lichtdämpfung – GL QUADRATIC ATTENUATION Definiert den quadratischen Wert zur Berechnung der Lichtdämpfung Abbildung 1: Flag-Erklärung,Diffuse & Ambient Light 14 3.1 OpenGL Projekt Graphik Texturorientierte Funktionen – GenTextures(n, &zeigerauftextur[0]); Erstellt einen Texturnamen – glBindTexture(GL TEXTURE 2D, textur[0]); Bindet die Textur an das angegebene Ziel. Mögliche Ziele: GL TEXTURE 1D -> 1 dimensionale Textur GL TEXTURE 2D -> 2 dimensionale Textur GL TEXTURE 3D -> 3 dimensionale Textur – glTexImage2D(target,level,components,width,height, depth,border,format,type,pixels); Legt Einstellungen für die Textur fest wie die Textur gezeichnet werden soll. Alternativ: glTexImage1D() oder glTexImage3D() target GL TEXTURE 1D -> eindimensionale Textur GL TEXTURE 2D -> zweidimensionale Textur GL TEXTURE 3D -> dreidimensionale Textur Level Detailgrad für die Textur level 0 ist das Basisbild. Level n ist die n-te Mipmapreduzierung des Bildes. Mipmap = gleiche Textur mit geringerer Auflösung, also in größerer Entfernung components 1 für R 2 für R und A 3 für RGB 4 für RGBA width Anzahl der Pixel pro Zeile (muss in 2er Potenz angegeben werden) height Anzahl der Zeilen (muss in 2er Potenz angegeben werden) depth Tiefe (muss in 2er Potenz angegeben werden) border Breite des Rahmens 0 oder 1 format Format der Pixeldaten. Folgende Parameter stehen zur Auswahl: GL COLOR INDEX, GL RED, GL GREEN, GL BLUE, GL ALPHA, GL RGB, GL RGBA, GL LUMINANCE, und GL LUMINANCE ALPHA TYPE Type = Pixeltyp des Inhalts von pixels. 15 3.1 OpenGL Projekt Graphik Folgende Typen werden unterstützt: GL UNSIGNED BYTE, GL BYTE, GL UNSIGNED SHORT, GL SHORT, GL UNSIGNED INT, GL INT, GL FLOAT, GL BITMAP pixels Textur-Image Daten oder Array wo die Pixel gespeichert sind – glTexParameter(target, pname, params); Legt Eigenschaften der Textur fest. target -> siehe oben pname – GL TEXTURE MIN FILTER Verkleinerungsfunktion, die eine zu große Textur auf eine kleinere Fläche abbildet. – GL TEXTURE MAG FILTER Vergrößerungsfunktion, die eine zu kleine Textur auf eine größere Fläche abbildet. GL TEXTURE WRAP S Textur geht über Grenzen hinaus - sie umwickelt das Objekt. Es stehen folgende params zur Verfügung: – GL CLAMP: Umwicklung mit begrenzter Reichweite der Texturkoordinate s. – GL REPEAT: Umwicklung mit unbegrenzter Reichweite der Texturkoordinate s. – GL TEXTURE WRAP T Wie GL TEXTURE WRAP S jedoch bezogen auf Texturkoordinate t. – GL TEXTURE BORDER COLOR Setzt die Randfarbe. Der Parameter params enthält vier Werte, die den RGBA-Farbwert für den Texturenrand darstellen. params liefert folgende Funktionen zur Verkleinerung von Texturen: – GL NEAREST Der Wert des Texturelements, welches am nächsten zum Zentrum des zu texturierenden Pixels liegt wird verwendet – GL LINEAR Der Mittelwert der vier Texturenelemente die dem Zentrum des zu texturierenden Pixels am nächsten liegen wird verwendet. – GL NEAREST MIPMAP NEAREST Wählt Mipmap, die der Größe des zu texturierenden Pixels am besten entspricht, und nutzt die Kriterien von GL NEAREST um den Texturenwert zu generieren. – GL LINEAR MIPMAP NEAREST Wählt Mipmap, die der Größe des zu texturierenden Pixels am besten entspricht, und nutzt die Kriterien von GL LINEAR um den Texturenwert zu generieren. 16 3.1 OpenGL Projekt Graphik – GL NEAREST MIPMAP LINEAR Verwendet den gewichteten Mittelwert der zwei Mipmaps, die der Größe des zu texturierenden Pixels am besten entsprechen, und nutzt die Kriterien von GL NEAREST um den Texturenwert zu generieren. – GL LINEAR MIPMAP LINEAR Verwendet den gewichteten Mittelwert der zwei Mipmaps, die der Größe des zu texturierenden Pixels am besten entsprechen, und nutzt die Kriterien von GL LINEAR um den Texturenwert zu generieren. – glTexCoord2f(0.0f, 0.0f ); Setzt die Texturkoordinaten. Sie stehen im Zusammenhang mit den Eckpunkten der Polygone. Alternativ: glTexCoord1f, glTexCoord2d(), glTexCoord3f(), usw. Funktionen zur Konfiguration der OpenGL - Engine – glEnable(FLAG); Mit glEnable() und dem entsprechenden Flag lassen sich verschiedene Einstellungen und Optimierungen vornehmen bzw. aktivieren, die sich direkt auf die Anzeigemethoden auswirken. Einige Flags sind: – GL ALPHA TEST Bei Aktivierung wird Alphatest durchgeführt. – GL BLEND Bei Aktivierung werden RGBA - Farben mit den Farben im Farbpuffer gemischt. – GL COLOR MATERIAL Bei Aktivierung werden Materialparameter durch die aktuelle Farbeinstellung. – GL CULL FACE Bei Aktivierung werden Polygone entsprechend ihrer Laufrichtung ausgeschlossen – GL DEPTH TEST Bei Aktivierung wird der Tiefenpuffer (z-Buffer) aktiviert. – GL DITHER Dithering wird aktiviert. – GL FOG Bei Aktivierung wird die Nebelfarbe in den Farbwert der Textur gemischt. – GL LIGHTi Lichtquelle i wird aktiviert. – GL LIGHTING Bei Aktivierung werden die aktuellen Beleuchtungsparameter verwendet um Vertex-/Indexfarbe zu berechnen. 17 3.1 OpenGL Projekt Graphik – GL LINE SMOOTH Bei Aktivierung wird die Linie als echtes Rechteck gezeichnet, ansonsten als Parallelogramm mit einem Winkel ungleich 90◦ . – GL LINE STIPPLE Bei Aktivierung werden Linien gepünktelt oder gestrichelt dargestellt. – GL NORMALIZE Bei Aktivierung werden Normalenvektoren auf Einheitslänge skaliert. – GL POINT SMOOTH Bei Aktivierung werden Punkte gefiltert gezeichnet. – GL SCISSOR TEST Bei Aktivierung werden Elemente verworfen die außerhalb eines durch glScissor() definierten Bereich liegen. – glDisable(FLAG); glDisable() funktioniert analog zu glEnable(). Es werden die als Parameter angegebenen Flags wieder zurückgesetzt. Die Grafik-Pipeline von OpenGL Nachdem die Koordinaten eines Vertexes über die Funktion glVertex() definiert wurden wird der Vertex durch die Modelview-Matrix transformiert, die unter anderem Informationen über die Kameraeinstellung enthält. Als Ergebnis erhält man einen Punkt im Raum mit sogenannten Augenkoordinaten. Nun werden die Lichteffekte, die auf ihn wirken berechnet und anschließend nochmals von der Projektionsmatrix (entweder Parallelprojektion oder Zentralprojektion) transformiert. Als Ergebnis erhalt man die sogenannten Clipkoordinaten die dann durch die Window-Transformation in Fensterkoordinaten umgerechnet werden. Aus mehreren so erzeugten Punkten bildet OpenGL dann das entsprechend gewählte primitive. Durch Rasterung wird dieses primitive dann in einzelne Fragmente, den Pixeln zerlegt. Jedes Pixel besitzt Informationen wie z.B. Farbe, Entfernung zum Betrachter, Texturkoordinaten, usw. Die durch Rasterung entstandenen Pixel durchlaufen bevor sie endgültig auf dem Bildschirm angezeigt werden noch einen Z-Buffertest und das Dithering. 18 3.1 OpenGL 3.1.4 Projekt Graphik Entwicklung Die zurzeit aktuelle Version der OpenGL ist OpenGL 2.0, die erstmals direkt in den Kern implementierte, programmierbare Shader unterstützt. Neu dafür entwickelt wurde die so genannte OpenGL Shading Language. Darüber hinaus gibt es weitere Varianten wie zum Beispiel die OpenGL ES. Dieser offene API Standard wird zur Erzeugung von 2D/3D - Grafiken für mobile Multimedia Applikationen auf Palms und Smartphones verwendet. Ein weiterer Ableger ist die OpenML, die sich auf Audio-, Video- und Grafikfunktionen spezialisiert. Angesichts der zwölf stimmberechtigten Mitgliedern der OpenGL ARB: 3Dlabs, Apple, ATI, Dell, Evans Sutherland, Hewlett-Packard, IBM, Intel, Matrox Graphics, Nvidia, Sun und Silicon Graphics darüber hinaus Adobe, Discreet, NEC, Quantum 3D, S3 Graphics und id Software, die sich um die Entwicklung von OpenGL kümmern, ist es sehr wahrscheinlich, dass OpenGL auch in Zukunft eine prioritäre Stelle neben DirectX einnehmen wird. 19 3.2 DirectX 3.2 3.2.1 Projekt Graphik DirectX Geschichte Als Windows 3.0 im Jahr 1990 eingeführt wurde, begann der Siegeszug der grafischen Bedienoberflächen. Schnell erkannten Entwickler die Vorteile dieser Entwicklung und programmierten fast alle Anwendungen unter Windows. Lediglich Spiele wurden nach wie vor für DOS programmiert. Windows hatte bis zu diesem Zeitpunkt nicht die Funktionen um die Performance die von den Entwicklern benötigt wurde bereitzustellen. Desweiteren fehlten Möglichkeiten aufwändige Grafikund Soundeffekte darzustellen. Um Spieleprogrammierer dazu zu bewegen ihre Spiele für Windows zu entwickeln begann Microsoft die Multimediafunktionen in Windows, speziell die der Grafik- und Soundausgabe zu verbessern. Microsoft musste auch eine Plattform schaffen um evtl. Hardwareprobleme aus dem Weg zu räumen wie z.B. Probleme mit der Grafik- oder Soundkarte oder dem Joystick. So entstand WinG, welches eine Ansammlung von Funktionen bot und performanter war als die herkömmliche Windows GDI. Leider fand auch dies wenig Beachtung, sodass mit Windows 95 das Game SDK sein Debut feierte. Später wurde das Game SDK in DirectX SDK 1.0 umbenannt. DirectX war geboren ! Bis zu DirectX 3 gab es keine 3D-Unterstützung, welche aber Microsoft bald darauf von der Firma Render Morphics erwarb, weiterentwickelte um sie dann schlußendlich in eine neue Komponente namens Direct3D zu implementieren. 3.2.2 Was ist DirectX ? Unter DirectX versteht man eine Ansammlung von Komponenten und Technologien, die Entwicklern die Erstellung von Multimedia-Applikationen und Spielen unter Windows erleichtert. Weiterhin bietet DirectX eine einheitliche, geräteunabhängige Schnittstelle, um den Zugriff auf Hardware wie Grafikkarte, Soundkarte und Eingabegeräte und deren Funktionalität zu erhalten. Entwickelt wurde es von Microsoft unter dem Gesichtspunkt, dass Entwickler sicher sein können, dass ihr Anwendungen auf jedem Windows-PC ohne Änderungen und ohne Berücksichtigung auf verschiedene Hardwarekonfigurationen lauffähig ist. 20 3.2 DirectX 3.2.3 Projekt Graphik Leistungsfähigkeit DirectX besteht im Wesentlichen aus zwei Schichten: – HAL (Hardware Abstraction Layer) HAL bietet Funktionen an, die direkt von der Hardware unterstützt werden. – HEL (Hardware Emulation Layer) HEL bietet Funktionen an, die keine Unterstützung der Hardware bieten und somit kann HEL diese bis zu einem gewissen Grad emulieren, indem die Funktionen dann z.B. vom GDI (Graphical Device Interface) ausgeführt werden. Wenn nun ein DirectX-Objekt für ein bestimmtes Gerät erzeugt wird, z.B. für die Grafikkarte, dann werden zunächst die Fähigkeiten abgefragt und gespeichert. Wenn dann bestimmte Funktionen durch die Grafikkarte ausgeführt werden sollen, prüft DirectX, ob diese Funktionen von der Hardware (HAL) abgedeckt werden können oder ob die Funktionen durch HEL emuliert werden müssen. Jedoch ist zu bemerken, dass Funktionen die von der HAL ausgeführt werden wesentlich schneller sind als die der HEL, die nur softwareseitig arbeitet. Leider kann aber auch HEL nicht alle Funktionen emulieren, sodass es einige Funktionen in HEL einfach nicht gibt. DirectX besteht aus vielen Komponenten, von denen jede eine bestimmte Aufgabe übernimmt. Die Folgende Auflistung enthält eine kurze Beschreibung der einzelnen Komponenten: – DirectDraw DirectDraw war die erste DirectX-Komponente. Sie erlaubt den direkten Zugriff auf Grafikkarte und Bildspeicher. Die größte Stärke von DirectDraw ist es jedoch, Speicherbereiche schnell zwischen Haupt- und Grafikkartenspeicher schieben zu können. – Direct3D Direct3D ist die größte und auch komplexeste Komponente von DirectX. Sie besteht aus einer Sammlung von Funktionen, mit denen Geometrietransformationen (Bewegung, Skalierung, Rotierung) sowie Beleuchtung und Texturierung ausgeführt werden können. Mit DirectX 8 wurden DirectDraw und Direct3D zu einer Komponente zusammengefasst. DirectX Graphics. Zu DirectX gehören aber ausser Grafikkomponenten auch noch folgende Komponenten, auf die ich aber aufgrund des Grafikprojektes nicht weiter eingehen werde. 21 3.2 DirectX Projekt Graphik – Direct3DX Utility Library Direct3DX Bibliothek, bietet Funktionen, die das Arbeiten mit Direct3D erleichtern. – DirectSound Mit dieser Komponente provitiert man von den Hardwarebeschleunigern beim Mixen von Soundeffekten – DirectMusic Im Gegensatz zu DirectSound kann man hier auch komplette Musikstücke abspielen und komponieren – DirectInput Ist für alle Eingaben zuständig die von Eingabegeräten kommen wie Maus, Joystick... – DirectPlay Unterstützung von Netzwerkverbindungen – DirectShow Mit DirectShow kann man z.B. Multimediadateien abspielen wie Videos oder Sounddateien Grundsätzliche Vorgehensweise zum Erstellen eines DirectX-Programms Bevor man ein DirectX-Programm beginnen kann, benötigt man ein Fenster. Dieses kann man mit MFC oder WinAPI erzeugen. Dem Linker sollten ausserdem die Include-Dateien als auch die Library-Dateien bekannt gemacht werden, was das DirectX SDK im Normalfall selbst erledigt. Sollte es jedoch nicht automatisch passieren, sollte man es von Hand selbst machen. Schritt 1: Direct3D einbinden Um Direct3D nutzen zu können muss man zuerst den Header d3d9.h und die Library d3d9.lib einbinden. Schritt 2: Direct3D Variablen deklarieren Für die ganze Sache sind erstmal zwei Zeiger vom größeren Interesse. Einmal das HauptObjekt von Direct3D. Es ist dafür verantwortlich, dass die richtigen Header eingebunden sind, für die Version, die wir nutzen und es erstellt den Device. Das ist der zweiter Zeiger. Er hat Zugriff zur Hardware kann somit Regisseur in unserer kleinen 3D-Welt spielen. Schritt 3: Direct3D einrichten Mit D3D SDK VERSION, stellt man sicher, dass auch die richtigen Header-Dateien von Direct3D genutzt werden. Es muss aber eine gleichgroße oder größere Version von DirectX installiert sein, weil sonst die Schnittstelle in der DirectX-DLL nicht vorhanden ist, deshalb prüft dieser Aufruf ob dieses der Fall ist. Wenn nicht schlägt sie fehl und es bricht ab. 22 3.2 DirectX Projekt Graphik Es ist für eine Direct3D-Anwendung im Desktopmodus notwendig, dieselben Einstellungen für unser Programm zu nutzen, wie der Desktop. Es ist zum Beispiel nicht möglich eine Anwendung mit 32-Bit Farbtiefe auf 16-Bit Farbtiefe des Desktops laufen zu lassen. Mit der Funktion GetAdapterDisplayMode() kann man sich die Einstellungen des GrafikAdapters holen, denn bevor man in Windows eine Anwendung startet, befindet man sich im Desktopmodus, demzufolge ist die Grafikadaptereinstellung gleich der Desktopeinstellung. Als nächstes legt man die beiden Einstellungen der BackBuffer und FrontBuffer fest. Der FrontBuffer ist das Bild, was man sieht und damit immer das aktuelle Bild, der Backbuffer ist nicht sichtbar und er ist das nachfolgende Bild. Das Bild wird im BackBuffer zusammengeschustert und ersetzt dann das Bild im FrontBuffer. Der Vorteil an dieser Technik ist das störendes Flimmern wegfällt und man ( glücklicherweise ) nicht sieht wie das Bild in seinen Bestandteilen nacheinander aufgebaut wird, sondern es gleich vollständig auf einen Schlag erhält. Entscheidend für die Art des Kopiervorgangs zwischen Backbuffer und Frontbuffer, ist der SwapEffect, also wie die Buffer kopiert werden sollen. Hierfür benutzt man die Funktion D3DSWAPEFFECT DISCARD. Es ist zu empfehlen diesen Flag weiterhin zu verwenden, denn er ist der einzige Modus der FullScene-Antialising unterstützt und ist von der Methode her am schnellsten und saubersten. Als nächstes muss man die Initialisierung vornehmen, und zwar die Einrichtung des Device, der Schnittstelle zwischen uns und der Hardware, der Instanz, der die Grafikkarte beherrscht. Hierfür wird der Flag D3DDEVTYPE HAL benötigt. Er steht dafür, das man hierfür die HAL benutzt. Mit HAL ist es möglich, die Hardwarebeschleunigung als auch Transform & Lighting zu nutzen. Um TL zu nutzen, setzt man den Flag D3DCREATE HARDWARE VERTEXPROCESSING Als letztes müssen die Objekte von Direct3D aus dem Arbeitsspeicher wieder entfernt werden. Grundlegende Funktionen – LPDIRECT3D9 Erstellung eines Direct3D Objekts – LPDIRECT3DDEVICE9 Rendering-Schnittstelle definieren – D3DPRESENT PARAMETERS Um die Rendering-Schnittstelle zu erstellen, muss diese Funktion mit Parametern gefüllt werden – UINT Adapter Gibt an, welche Grafikkarte benutzt wird – D3DDEVTYPE HAL Benutzen der Hardwarebeschleunigung 23 3.2 DirectX Projekt Graphik – D3DDEVTYPE REF Benutzen des Referenz Software-Rasterizer – DrawPrimitive Diese Funktion zeichnet das über Vertices angegebene geometrische Objekt Um die Funktion DrawPrimitive korrekt anzuwenden sollte man wissen, dass Direct3D Vektordaten in einem Vertex Buffer speichert und dann zum Rendern für primitive Formen verwendet. Man hat die Auswahl von 6 verschiedenen Primitivarten: – Punktlisten Jeder Punkt wird einzeln ausgegeben – Linienlisten Je zwei Punkte werden durch eine Linie verbunden – Linienstreifen alle Punkte werden der Reihe nach durch eine Linie verbunden – Dreieckslisten Je drei Punkte werden zusammen als Dreieck dargestellt – Dreiecksstreifen alle Punkte werden der Reihe nach als breiter Streifen aus Dreiecken dargestellt – Dreiecksfächer alle Punkte spannen mit dem ersten einen Fächer aus Dreiecken auf Abbildung 2: Eine Primitive mit 3 Vertices Da einzelnen Vektoren auch Farb-oder Texturwerte zugewiesen werden können, werden bei den Primitiven die dazwischen liegenden Werte interpoliert. 24 3.2 DirectX Projekt Graphik Folgender Quellcode-Ausschnitt würde z.B. ein Dreieck zeichnen D3DVERTEX g pvTriangleVertices[3]; D3DVEKTOR p1{0.0f,3.0f,0.0f}; D3DVEKTOR p2{3.0f,-3.0f,0.0f}; D3DVEKTOR p3{-3.0f,-3.0f,0.0f}; g pvTriangleVertices[0]=D3DVERTEX(p1, vNormal,0,0); g pvTriangleVertices[1]=D3DVERTEX(p2, vNormal,0,0); g pvTriangleVertices[2]=D3DVERTEX(p3, vNormal,0,0); pd3dDevice->DrawPrimitive(D3DPT TRIANGLELIST,D3DFVF VERTEX ,g pvTriangleVertices,3,NULL); Die Eckpunkte des Dreiecks sind mit D3DVEKTOR gegeben. Das Flexible Vertex Format (FVF) Über das FVF hat man die Möglichkeit, eine eigene Datenstruktur für Vertices auszudenken und dieses dann Direct3D mitzuteilen. Man muss angeben, welche Information man einem Vertex bereitstellen will und wie man diese dann verarbeiten möchte. Programmtechnisch ist das FVF ein DWORD, das sich aus der OR-Verknüpfung von Flags ergibt. Denkbar wären u.a. folgende Flags: – D3DFVF DIFFUSE Das Vertex beinhaltet einen diffusen Farbwert, welcher in den Koordinaten angegeben werden muss – D3DFVF XYZ Vertex Koordinate ist noch untransformiert – D3DFVF NORMAL Es wird ein Normalvektor verwendet Direct3D stellt eine Vielzahl von Funktionen bereit mit denen man u.a. Licht-und Texturen darstellen kann. Hier eine Auflistung der Texturorientierten Funktionen – LPDIRECT3DTEXTURE9 Texturschnittstelle definieren – D3DXCreateTextureFromFile Lädt Textur aus einer angegebenen Datei 25 3.2 DirectX Projekt Graphik – D3DXCreateTextureFromFileEx Ähnlich wie ...FromFile aber möchte man Techniken wie MipMapping, Color-Keying oder ähnliches anwenden benötigt man diese Funktion In Zusammenhang mit den oben genannten Funktionen stehen u.a. auch noch folgende Paramter zur Auswahl die man definieren kann. – Filter Gibt an, wie die Pixel der Bilddatei gefiltert werden sollen. Besonders interessant wenn die Textur skaliert werden soll – Mip-Levels Gibt an wieviel Mip-Map Levels generiert werden sollen – MipFilter Gibt an, wie die Texturen beim Generieren von Mip-Maps behandelt werden sollen Wenn man in Direct3D Licht verwenden möchte, muss die Vektorstruktur um Oberflächennormalen erweitert werden, um die Lichtstärke über dem Einfallswinkel bestimmen zu können. struct Customvertex { D3DXVECTOR position; D3DXVECTOR normal; }; Danach kann das Licht erstellt werden und einige Werte können festgelegt werden wie die Farbe, die Art und evlt. Position und Richtung. D3DLIGHT9 light light.type = D3DLIGHT DIRECTIONAL; light.Diffuse.r=1.0f; light.Diffuse.g=1.0f; light.Diffuse.b=1.0f; light.Direction=D3DXVECTOR3 (1.0f,1.0f,1.0f ); light.Range=1000.0f; Jetzt kann das Licht an das Gerät übergeben und aktiviert werden. Materialien haben Einfluss darauf, wie Licht von der Oberfläche des Objekts reflektiert werden und somit beinflussen sie auch die Texturen. 26 3.2 DirectX Projekt Graphik Die Rendering-Pipeline Direct3D bedient sich dem Pipelining-Prinzip zur Verarbeitung der Geometriedaten. Die Rohdaten gelangen sozusagen in die erste Stufe, in der sie bearbeitet und anschließend an die nächsthöhere Stufe weitergegeben werden. Nachdem die Geometriedaten die Direct3DPipeline vollständig durchlaufen haben, erhalten Sie eine fertig gerenderte Szene. Abbildung 11 zeigt eine schematische Darstellung der Pipeline. Abbildung 3: Die Direct3D-Rendering-Pipeline Tesselation Zwar nimmt die Leistungsfähigkeit der Computer stetig zu, dennoch sind im 3D-Bereich viele Grenzen gesetzt. Rundungen werden durch eine Vielzahl von Dreiecken realisiert. Desto mehr Dreiecke verwendet werden, desto ansehnlicher sind die Ergebnisse. Zum einen erhöht sich der Zeitaufwand zum Rendern der vielen Dreiecke und zum anderen - was viel entscheidender ist - müssen Sie mehr Daten über den Bus schicken. Seit DirectX 8.0 besteht die Möglichkeit, so genannte Curved Surfaces bzw. High Order Surfaces darzustellen, indem ein Dreieck während der Laufzeit unterteilt wird. Moderne Grafikkarten führen diesen Prozess, der im Fachjargon Tesselation genannt wird, im Grafikchip durch. Daraus resultiert eine Reduzierung der Bus-Belastung. Natürlich bleibt der erhöhte Aufwand zum Rendern der Primitive nicht aus. Nach dem vierten Tag wissen Sie die Tesselation zu nutzen, um den Detailgrad eines 3D-Objekts zu erhöhen. Transformation & Lighting Direct3D stellt im Rahmen der so genannten Fixed-Function-Pipeline die Funktionalitäten zur Transformation und zur Beleuchtung der Primitive zur Verfügung. Diverse Methoden und Eigenschaften eröffnen dem Programmierer, wie die Vertex-Daten zu verarbeiten sind. Die Fixed-Function-Pipeline bietet keine Möglichkeit zur Erweiterung des gegebenen Funktionsumfangs. Als Alternative, nicht etwa als zusätzliche Option, gelten die Vertex Shader. Shader sind kleine Programme, die vom Grafikprozessor ausgeführt werden (insofern die Hardware Vertex Shader unterstützt). Wählt der Programmierer diesen Weg, kann oder besser muss er die Transformationen und die Beleuchtung der Vertices vornehmen. Ein klarer Vorteil zeichnet sich in der hohen Flexibilität ab. Vertex Shader zählen zu der Programmable Pipeline. 27 3.2 DirectX Projekt Graphik Clipping, Culling und Rasterization Zwischen einer dreidimensionalen virtuellen Welt und deren Darstellung auf dem Monitor besteht ein Konflikt, denn die Koordinaten lassen sich nicht direkt übertragen. Wie bereits besprochen, durchläuft die Geometrie deshalb mehrere Transformationen, bis die Koordinaten nach der Projection-Transformation in 2D-Koordinaten vorliegen. Natürlich ist nicht sichergestellt, dass sich alle in die Pipeline gejagten Primitive voll im sichtbaren Bereich befinden. Schließlich ist die Fläche zum Anzeigen der Szene begrenzt und wird durch den Viewport beschrieben. Als Viewport gilt in diesem Fall ein Rechteck, welches die Größe des Sichtbereichs absteckt. Primitive, die sich außerhalb des angegebenen Bereichs befinden, werden geclippt. Direct3D unterstützt außerdem von Haus aus das Back Face Culling. Jene Option sorgt im aktiven Zustand dafür, dass wahlweise die Primitive mit im oder gegen den Uhrzeigersinn angeordneten Vertices entfernt werden. Dadurch soll Direct3D verhindern, dass vom Betrachter abgewandte Primitive auf dem Monitor erscheinen. Wenn die Sichtbarkeit der Dreiecksrückseiten erwünschst ist, muss lediglich das Back Face Culling deaktiviert werden. Nun können die Daten im Rasterisations-Prozess (engl. rasterization) in entsprechende Farbwerte übertragen werden, sprich Direct3D berechnet die Pixel an den jeweiligen Flächen und speichert die Werte in einem so genannten Surface. Ein Surface ist lediglich ein sequenziell aufgebauter Speicherbereich, vergleichbar mit einem Bitmap. Multitexturing-Einheit vs. Pixel Shader Die Einheit zur Transformation und Beleuchtung der Vertices ist nur ein Bestandteil der Fixed-Function-Pipeline gewesen. Jene Einheit zum Hinzufügen von Texturen bildet den zweiten Bestandteil. Analog zur gesamten Architektur von Direct3D ist die Multitexturing-Einheit aufgebaut, d.h. sie besitzt ebenfalls mehrere Bearbeitungsstufen. Mehrere Bearbeitungsstufen sind deshalb von Belang, damit der Programmierer die Möglichkeit zur Kombination unterschiedlicher Texturen erhält. Wie Sie später kennen lernen werden, sind solche Bitmaps selbst zur Beleuchtung anderer Texturen zu gebrauchen. Das Pendant zur Multitexturing-Einheit stellt der Pixel Shader dar. Wie beim Vertex Shader obliegt es dem Programmierer, die Funktionalitäten der Fixed-Function-Pipeline zu implementieren (insofern dies erwünscht bzw. erfordert ist). Vorteile sind wieder in der Flexibilität erkennbar. So ermöglichen Pixel-Shader die dynamische Beleuchtung während des Texturierungs-Prozess. 28 3.2 DirectX Projekt Graphik Tiefen- und Alpha-Test Bevor der aktuelle Pixel auf das Ziel-Surface übertragen wird, muss dieser sich dem Tiefen- und dem Alpha-Test unterziehen. Letzterer bewirkt den Verfall solcher Pixel, deren Farbwert in den als transparent definierten Farbbereich fällt. Der Tiefentest verhindert, dass jene Pixel in das Surface geschrieben werden, die eigentlich durch andere verdeckt werden. Wir nehmen uns des Tiefenproblems später an und demonstrieren den Unterschied zwischen aktiviertem und deaktiviertem Tiefentest. Fog Blending In Abhängigkeit von der Distanz zwischen einem Objekt und der Position der Kamera oder allein durch die Stelle des Objekts auf der Z-Achse werden dessen Pixel zu guter Letzt mit dem Farbwert des Nebels kombiniert. Körper außerhalb eines definierten Bereichs sind bei aktiviertem Fog Blending gänzlich unsichtbar und werden vom Nebel überdeckt. In diesem Fall wird der Farbwert des Nebels in das Surface geschrieben. 3.2.4 Entwicklung Windows Graphics Foundation (WGF) - Der DirectX9 Nachfolger WGF - Einführung WGF wird der Nachfolger von Microsoft’s aktueller Grafik API DirectX9. Aus gutem Grund entschied Microsoft das neue Grafik API nicht DirectX10 zu nennen, sondern Windows Graphics Foundation (WGF), was auf tiefgreifende Änderungen im bisherigen Konzept von DirectX schliessen lässt. WGF wurde von Grund auf neu durchdacht mit den Zielen einer optimalen Betriebssystem-Integration und einer ausreichenden Flexibilität für zukünftige 3D-Applikationen mit der entsprechenden Stabilität und Leistung. Microsoft möchte hier einen Grundstein für ein Next-Generation-API legen, was sowohl Performance technisch als auch in Sachen Flexibilität einiges verspricht. WGF ist das erste API unter Windows, das Direct3D (3D-Graphik) mit DirectDraw (2D-Graphik) vereint, die beide bislang über getrennte Schnittstellen anzusteuern waren. Mit der Vereinigung dieser beiden Schnittstellen will Microsoft eine klar definierte Grafikkomponente schaffen und vereinfacht somit auch das Entwickeln und Warten von 3D-Applikationen und Grafik-Treibern sowie die Behandlung grafikhardware-basierter Fehler im Betriebssystem. Für die Desktop-Präsentation hält sich Microsoft offen, zudem die 2D-Schnittstelle um einige noch nicht genannte Besonderheiten und Effekte zu erweitern. 29 3.2 DirectX Projekt Graphik Die neue WGF Grafik-Pipeline Eines der wichtigsten Neuerungen in WGF ist die Grafik-Pipeline, die im wesentlichen durch den Common Shader Core ansprechbar ist. Das Prinzip des Common Shader Core ist es Vertex- und PixelShader zu vereinen, um Flexibilität in der Programmierung der Pipeline zu erlauben. Als Beispiel sind hier gridbasierte physikalische Simulationen zu nennen, die Geschwindigkeitswerte im Pixel-Shader erzeugen, und gleich dem Vertex-Shader als Input dienen, d.h. Pixelbuffer, die als Vertexbuffer genutzt werden und erneut den Weg durch die Pipeline machen. In Sachen Flexibilität wartet WGF zusätzlich mit einem neuen Feature auf, nämlich den sogenannten Geometry- oder Primitive-Shadern, die in der Lage sind innerhalb der Grafik-Pipeline Primitive, wie Lines, Triangles, Quads, etc zu generieren, womit Algorithmen die ohnehin auf einer Generierung von zusätzlicher Geometry angewiesen waren, wesentlich effizienter ablaufen können. Bisher war es nicht möglich zusätzliche Geometry-Daten innerhalb der Pipeline zu erzeugen, d.h. es konnte nur ein Vertex die Vertex-Pipeline verlassen, wenn ein Vertex hinunter gesendet wurde. Mit Sicherheit wird es hierfür weitreichende neue Anwendung geben, die PrimitiveShader nutzen werden. Aktuelle Algorithmen, die sich hierfür eignen, wären beispielsweise GPU Shadow und Light Volumes, Triangulierung parametrischer Flächen, Billboard-Rendering oder dynamisch erzeugte Geometrie-Stücke von explodierenden Fässern oder ähnlichem. WGF wird das Shader Model 4.0 unterstützen, und Technologien wie, Normal-Map Komprimierung, verbessertes Zustandsmanagement oder High Dynamic Range Rendering Formate integrieren. Vertex-Lighting, Fog, Alpha-Test, Triangle-Fans und Point-Sprites werden als Altlasten aus der Fixed-Function Pipeline herausgenommen, wobei diese Funktionalität stattdessen über programmierbare Shader unterstützt wird. Dies unterstützt den Trend, dass Grafikhardware immer mehr auf programmierbare Shader Pipelines optimiert wird, und die FixedFunction Pipeline langsam ihren Rückzug bestreitet. WGF und Longhorn WGF soll hervorragend in Longhorn integriert sein. So wird beispielsweise mittels der Longhorn Avalon Technologie das komplette Desktop-Rendering in Longhorn mittels 3D-Hardware Beschleunigung durchgeführt. Longhorn Avalon ist der Codename für das neue Grafik Subsystem, welches das Entwickeln von Grafikapplikationen erleichtern soll. Im Gegensatz zu herkömmlichen Grafik-Konzepten ist Avalon vektorbasiert, und nicht auf Pixelbasis. Unterstützt wird dies zusätzlich durch das neue Programmiermodell XAML, das vor allem für den Entwurf von User-Interfaces geschaffen wurde. Dass WGF tief im Betriebsystem verankert ist, zeigt auch das Management von WGF-Applikationen, welches in der Lage sein wird mehrere 3DApplikationen nach Batches und Kontexten zu sortieren, um ein optimales Scheduling zu garantieren. Hier soll auch ein sogenanntes Preemptive Context Scheduling zum Einsatz kommen, welches auf 30 3.2 DirectX Projekt Graphik der Idee des bekannten preemptiven Multitaskings basiert. Ein weiteres wichtiges Feature ist die Virtualisierung von GPU-Speicher. D.h. in WGF gibt es intern prinzipiell nur virtuellen GPU-Speicher, von dem sowohl Teile auf der Grafikkarte als auch Teile im System-Speicher residieren können, jedoch als zusammenhängender Block adressiert werden. Die Speicherverwaltung konzentriert sich im Wesentlichen auf das Laden in Form von Preloading und On-Demand-Loading von GrafikSpeicherblöcken, wofür entsprechende Caching-Mechanismen bereitstehen sollen. In diesem Zusammenhang spielt auch das kommende Longhorn Display Driver Model (LDDM) eine große Rolle, dessen Hauptziel es ist, Abstürze, die vom Grafik-Treiber ausgelöst werden, vollständig abzufangen und möglichen resultierenden Datenverlust zu vermeiden. WGF - Release Termin? Eine genauer Release Termin ist wohl noch nicht in Sicht. Für Hardwarehersteller ist jedoch bereits die WGFSpezifikation in der Version 0.99 erhältlich, wobei im Moment an der WGF-Spezifikation 1.0 gearbeitet wird. Somit sind die Hersteller in der Lage rechtzeitig ihre Grafikkarten auf die neue WGF-Architektur und deren Möglichkeiten anzupassen und erste Tests zu fahren. WGF wird voraussichtlich im nächsten Jahr (2006) für Entwickler benutzbar sein, jedoch spätestens mit dem Erscheinen des Longhorn-Betriebssystems im selben Jahr, und dann auch fest im Longhorn Betriebssystem integriert. 31 4. Unterschiede DirectX und OpenGL 4 Projekt Graphik Unterschiede DirectX und OpenGL Grundlegende Unterschiede von DirectX und OpenGL OpenGL – Nutzt die Hardware optimal aus, durch spez. Anpassungen – Läuft auf unterschiedlichen Plattformen – Läuft nicht sofort auf den meisten 3D-Chips mit fast allen 3D Features, ohne spez. Anpassungen – Läuft auf verteilten Systemen mit Client-Server-Architektur – Open Source Referenzimplementierung – Meist bessere Treiber für professionelle Grafikhardware DirectX – nutzt die Hardware nicht optimal aus, durch spez. Anpassungen, da an DirectX Funktionsset gebunden – Läuft nicht auf unterschiedlichen Plattformen, nur auf Windows – läuft sofort auf den meisten 3D-Chips mit fast allen 3D Features, ohne spez. Anpassungen – läuft nicht auf verteilten Systemen – programmiersprachenunabhängig (unmanaged DirectX, COM) – arbeitet mit World und View-Matrix, Objekt daher unabhängig vom Betrachter verschiebbar durch Änderung der World-Matrix – nicht nötig, eigene Routinen zum Laden von Texturen zu schreiben – Alpha-Operationen beim Blending unabhängig definieren von den Color-Operationen – zusätzliches Ambient-Lighting – DirectX bzw. D3DX-Bibliothek bietet die Möglichkeit, Mesh-Dateien zu laden und darzustellen 32 4. Unterschiede DirectX und OpenGL Feature Projekt Graphik OpenGL 1.2 Core Direct3D 8 System Mechanik OS Support API Definition Control API Specification API Mechanism Software Emulation Extension Mechanism Source Implementation FixedFunction Vertex Blending Programm. Vertex Blending Parametric Curves Primitives Parametric Surface Primitives Hierarchical Display Lists Windows,MacOS,BeOS,others OpenGL ARB OGL Specification includes und libraries Ja Ja Ja Nein Nein Ja Ja Ja Windows Microsoft SDK Documentation COM Nein Ja Nein Ja Ja Ja Ja Nein Rendering 2-Seiten Belichtung Point Size Rendering Attribute Line Width Rendering Attribute Programmable Pixel Shading Triadic Texture Blending Cube Environment Mapping Volume Textures Multitexture Cascade Texture Temp. Result Register Mirror Texture Addressing Texture Wrapping Range-Based Fog Bump Mapping Modulate 2X Texture Blend Modulate 4X Texture Blend Add Signed Texture Blend Ja Ja Ja Nein Nein Nein Ja Nein Nein Nein Nein Nein Nein Nein Nein Nein Nein Ja Nein Ja Ja Ja Ja Ja Ja Ja Ja Ja Ja Ja Ja Ja Frame Buffer HW Independent Z Buffer Access Full-Screen Antialiasing Motion Blur Accumulation Buffers 33 Ja Ja Ja Ja Nein Ja Ja Nein 5. Projekt-Fazit 5 Projekt Graphik Projekt-Fazit Ob man sich nun für DirectX oder für OpenGL entscheidet, jedes System hat seine Vor- und Nachteile. Für Anfänger ist jedoch unserer Meinung nach OpenGL wesentlich einfacher zum Einstieg geeignet als DirectX, da es viele Funktionen vereinfacht. Was die Performance angeht, sticht keines der beiden heraus. Es kommt jedoch auf den Hersteller des Anwendungsprogramms an, wie weit er seinen Code auf das jeweilige System optimiert. So könnte es durchaus sein, dass einmal DirectX, ein anderes Mal OpenGL die Nase vorn hat. Die Vorteile von OpenGL liegen vor allem in der Plattforumunabhängigkeit und der Open-Source-Referenzimplementierung. Jedoch dauert ein neuer Standard sehr lange und man könnte in ein Extension Chaos geraten. Bei DirectX ist der Vorteil, dass sehr schnelle Standards verfügbar sind und dieser dann meist weiter ist als die Hardware-Entwicklung. Der größte Nachteil wird wohl in der plattformabhängigkeit liegen und den oft starken Veränderungen bei neuen Versionen. Gruppeninternes Fazit Mit diesem Projekt lernten wir vor allem eines: Einarbeiten! Kein anderes Projekt verlangte in so kurzer Zeit soviel Materie zu verstehen. Aber im Gegensatz dazu machte es uns eine Menge Spaß, vor allem als gegen Ende unser Programmierbeispiel endlich funktionierte. Es kam zwischendurch beim DirectX Beispiel zu Komplikationen, welche aber nach einigen Stunden intensiven Recherchierens bewältigt wurden. Auch das Erstellen von Windows Fenstern dauerte eine Zeit, wurde aber dank Internet Tutorials und Büchern auch gemeistert. So haben wir nun auch einen Einblick in WinAPI bekommen. In der Gesamtbetrachtung haben wir bei diesem Projekt bis jetzt von allen Projekten am meisten gelernt und wir sind froh es genommen zu haben, denn so haben wir nun einen kleinen Einblick sowohl in OpenGL als auch in DirectX erhalten und wollen nun darauf aufbauen. Zeitlich schafften wir alles in geplanter Zeit, unserer selbst gesetzen Deadline, sodass wir noch genug Zeiten hatten für den Fall das was schief laufen würde oder wir noch etwas ändern wollten. 34 6. Literaturverzeichnis 6 Projekt Graphik Literaturverzeichnis Jetzt lerne ich DirectX und Visual C++ Christian Rousselle, Markt & Technik DirectX GE-PACKT Joachim Rohde, mitp Verlag Unterschiede zwischen DirectX 7 und DirectX 8 http://www.hardtecs4u.com/reviews/2001/directx7 vs 8 Erklärungen über Grafik-Engines http://www.computerbase.de/lexikon/Grafik-Engine Infos aus 1.Hand von Microsoft besonderer Dank an Gesa Ehmsen(Community Management) und Dirk Primbs(DirectX Technologieberater) http://www.msdn.microsoft.com/directx Computerspiele Peter Dobrovka, mitp Verlag OpenGL Tutorials und Erklärungen http://www.lighthouse3d.com OpenGL Informationen und Tutorials http://www.open-gl.de OpenGL Hauptseite http://www.opengl.org Viele Informationen über OpenGL http://nehe.gamedev.net GLUT 3.0 Specification The OpenGL Bluebook The OpenGL Redbook 35 7. Anhang 7 7.1 Projekt Graphik Anhang Open GL Funktionsliste OpenGl-Funktionen im Überblick GLX commands glXCopyContext glXChooseVisual glXCreateGLXPixmap glXCreateContext glXDestroyGLXPixmap glXDestroyContext glXGetCurrentContext glXGetConfig glXIntro glXGetCurrentDrawable glXMakeCurrent glXIsDirect glXQueryVersion glXQueryExtension glXUseXFont glXSwapBuffers glXWaitX glXWaitGL GL commands glAlphaFunc glAccum glBitmap glBegin glCallList glBlendFunc glClear glCallLists glClearColor glClearAccum glClearIndex glClearDepth glClipPlane glClearStencil glColorMask glColor glCopyPixels glColorMaterial glDeleteLists glCullFace glDepthMask glDepthFunc glDisable glDepthRange glDrawPixels glDrawBuffer glEnable glEdgeFlag glEndList glEnd glEvalMesh glEvalCoord glFeedbackBuffer glEvalPoint glFlush glFinish glFrontFace glFog glGenLists glFrustum glGetClipPlane glGet glGetLight glGetError glGetMaterial glGetMap glGetPolygonStipple glGetPixelMap glGetTexEnv glGetString glGetTexImage glGetTexGen glGetTexParameter glGetTexLevelParameter glIndex glHint glInitNames glIndexMask glIsList glIsEnabled glLightModel glLight glLineWidth glLineStipple glLoadIdentity glListBase glLoadName glLoadMatrix glMap1 glLogicOp glMapGrid glMap2 glMatrixMode glMaterial glNewList glMultMatrix glOrtho glNormal glPixelMap glPassThrough glPixelTransfer glPixelStore glPointSize glPixelZoom glPolygonStipple glPolygonMode glPopMatrix glPopAttrib glPushAttrib glPopName glPushName glPushMatrix glReadBuffer glRasterPos glRect glReadPixels glRotate glRenderMode glScissor glScale glShadeModel glSelectBuffer glStencilMask glStencilFunc glTexCoord glStencilOp glTexGen glTexEnv glTexImage2D glTexImage1D glTranslate glTexParameter glViewport glVertex 36 7.1 Open GL Funktionsliste Projekt Graphik GLU commands gluBeginPolygon gluBeginCurve gluBeginTrim gluBeginSurface gluBuild2Dmipmaps gluBuild1DMipmaps gluDeleteNurbsRenderer gluCylinder gluDeleteTess gluDeleteQuadric gluEndCurve gluDisk gluEndSurface gluEndPolygon gluErrorString gluEndTrim gluLoadSamplingMatrices gluGetNurbsProperty gluNewNurbsRenderer gluLookAt gluNewTess gluNewQuadric gluNurbsCallback gluNextContour gluNurbsProperty gluNurbsCurve gluOrtho2D gluNurbsSurface gluPerspective gluPartialDisk gluProject gluPickMatrix gluQuadricCallback gluPwlCurve gluQuadricNormals gluQuadricDrawStyle gluQuadricTexture gluQuadricOrientation gluSphere gluScaleImage gluTessVertex gluTessCallback gluUnProject 37 7.2 Realisierung eines Würfels unter OpenGL 7.2 Projekt Graphik Realisierung eines Würfels unter OpenGL #include <stdlib.h> #include <windows.h> #include <stdio.h> // Header File für Standard Input/Output #include <gl\gl.h> // Header File für die OpenGL32 Library #include <gl\glu.h> // Header File für die GLu32 Library #include <gl\glaux.h> // Header File für die Glaux Library HDC hDC=NULL; // Private GDI Device Context HGLRC hRC=NULL; // Permanent Rendering Context HWND hWnd=NULL; // Window Handle HINSTANCE hInstance; // Instanz der Applikation bool keys[256]; // Key-Array bool active = TRUE; // Window Active Flag Set To TRUE By Default bool fullscreen = TRUE; // fullscreen flag bool light; // light flag bool lp; // L gedrüclt? bool fp; // F gedrückt? bool zp; // Z gedrückt? bool zbuffer = FALSE; // Z - Buffer GLfloat xrot; // X Rotation GLfloat yrot; // Y Rotation GLfloat xspeed; // X Rotation Speed GLfloat yspeed; // Y Rotation Speed GLfloat z=-5.0f; // Anzeige nach hinten legen GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f }; GLuint filter; texture[3]; // aktuell benutzter Filter GLuint // Speicher für 3 Texturen LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); Declaration For WndProc // ////////////////////////////////////////////////////////////////////////////////////// // // // BMP aus Datei laden ... // // // ////////////////////////////////////////////////////////////////////////////////////// AUX_RGBImageRec *LoadBMP(char *Filename) ein Bitmap { FILE *File=NULL; // Lädt // Zeiger auf File if (!Filename) { return NULL; } // Falls Datei nicht existiert File = fopen(Filename,"r"); if (File) { fclose(File); return auxDIBImageLoad(Filename); } // Falls Datei existiert return NULL; // -> falls Fehler auftrat // File Handle schließen // Lädt das Bitmap und übergibt einen Zeiger } ////////////////////////////////////////////////////////////////////////////////////// // // // Konvertiert das geladene Bitmap in eine Textur // // // ////////////////////////////////////////////////////////////////////////////////////// int LoadGLTextures() { int Status=FALSE; AUX_RGBImageRec *TextureImage[1]; // Speicherplatz für Textur reservieren memset(TextureImage,0,sizeof(void *)*1); if (TextureImage[0]=LoadBMP("Data/kiste.bmp")) { Status=TRUE; glGenTextures(3, &texture[0]); // Erstellt 3 Texturen, die mit "f" durchsprungen werden können // Filter 1: Nearest Filtered Texture glBindTexture(GL_TEXTURE_2D, texture[0]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 38 7.2 Realisierung eines Würfels unter OpenGL Projekt Graphik glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); // Filter 2: Linear Filtered Texture glBindTexture(GL_TEXTURE_2D, texture[1]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); // Filter 3: MipMapped Texture glBindTexture(GL_TEXTURE_2D, texture[2]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); } if (TextureImage[0]) { if (TextureImage[0]->data) { free(TextureImage[0]->data); } // löscht von Textur belegter Speicher free(TextureImage[0]); // löscht Image Struktur } return Status; // Erfolg ? } ////////////////////////////////////////////////////////////////////////////////////// // // // Initialisiert und Resized das Fenster // // // ////////////////////////////////////////////////////////////////////////////////////// GLvoid ReSizeGLScene(GLsizei width, GLsizei height) { if (height==0) { height=1; } glViewport(0,0,width,height); // Reset The Current Viewport glMatrixMode(GL_PROJECTION); glLoadIdentity(); // wählt die Projektionsmatrix // Resetet die Matrix gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // wählt ModelMatrix } ////////////////////////////////////////////////////////////////////////////////////// // // // OpenGL SetUp // // // ////////////////////////////////////////////////////////////////////////////////////// int InitGL(GLvoid) { if (!LoadGLTextures()) { return FALSE; } // Textur - Routine wird gestartet glEnable(GL_TEXTURE_2D); glShadeModel(GL_SMOOTH); glClearColor(0.1f, 0.5f, 0.8f, 0.5f); glClearDepth(1.0f); // // // // if(!zbuffer) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); Enable Texture Mapping Enable Smooth Shading Hintergrund- bzw. Löschfarbe Depth Buffer Setup // z - Buffer aktivieren // z - Buffer deaktivieren //glEnable(GL_LINE_SMOOTH); glEnable(GL_POLYGON_SMOOTH); //glEnable(GL_CULL_FACE); glEnable(GL_DITHER); glEnable(GL_STENCIL_TEST); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Depth Testing // Perspective Berechnungen glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); glEnable(GL_LIGHT1); return TRUE; // // // // } 39 Einstellungen für Ambient Light Einstellungen für Diffuse Light Position des Lichts Enable Licht1 7.2 Realisierung eines Würfels unter OpenGL Projekt Graphik ////////////////////////////////////////////////////////////////////////////////////// // // // Eigentliche Zeichenoperation // // // ////////////////////////////////////////////////////////////////////////////////////// int DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Leert Farb- und Tiefenpuffer glLoadIdentity(); // View zurücksetzten glTranslatef(0.0f,0.0f,z); // Ausgangspunkt um z nach hinten verschieben glRotatef(xrot,1.0f,0.0f,0.0f); glRotatef(yrot,0.0f,1.0f,0.0f); // Rotation um X-Achse // Rotation um Y-Achse glBindTexture(GL_TEXTURE_2D, texture[filter]); glBegin(GL_QUADS); // vorne glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, // hinten glNormal3f( 0.0f, 0.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, // oben glNormal3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, // unten glNormal3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, // rechts glNormal3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, // links glNormal3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, glEnd(); // Punkte werden zu Vierecken verbunden // Normalenvektor der Textur -1.0f, 1.0f); // Texturkoordinate und dazugehöriger Vertex -1.0f, 1.0f); 1.0f, 1.0f); 1.0f, 1.0f); -1.0f, 1.0f, 1.0f, -1.0f, -1.0f); -1.0f); -1.0f); -1.0f); 1.0f, -1.0f); 1.0f, 1.0f); 1.0f, 1.0f); 1.0f, -1.0f); -1.0f, -1.0f); -1.0f, -1.0f); -1.0f, 1.0f); -1.0f, 1.0f); -1.0f, -1.0f); 1.0f, -1.0f); 1.0f, 1.0f); -1.0f, 1.0f); -1.0f, -1.0f); -1.0f, 1.0f); 1.0f, 1.0f); 1.0f, -1.0f); xrot+=xspeed; yrot+=yspeed; return TRUE; } ////////////////////////////////////////////////////////////////////////////////////// // // // Funktion, die aufgerufen wird wenn man das Fenster beendet // // // ////////////////////////////////////////////////////////////////////////////////////// GLvoid KillGLWindow(GLvoid) { if (fullscreen) { ChangeDisplaySettings(NULL,0); ShowCursor(TRUE); } // Falls im Vollbildmodus - switch zu Desktop // zeigt Maus Cursor wieder an // Kontexte wieder freigeben: if (hRC) // Falls Rendering Context vorhanden... { if (!wglMakeCurrent(NULL,NULL)) // Falls DC und RC nicht freigegeben werden können { MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); } if (!wglDeleteContext(hRC)) { MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); } 40 7.2 Realisierung eines Würfels unter OpenGL Projekt Graphik hRC=NULL; } if (hDC && !ReleaseDC(hWnd,hDC)) { MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); hDC=NULL; } if (hWnd && !DestroyWindow(hWnd)) { MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); hWnd=NULL; } if (!UnregisterClass("OpenGL",hInstance)) { MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); hInstance=NULL; } } /* * * * * * * This Code Creates Our OpenGL Window. title width height bits fullscreenflag - Parameters Are: Title To Appear At The Top Of The Window Width Of The GL Window Or Fullscreen Mode Height Of The GL Window Or Fullscreen Mode Number Of Bits To Use For Color (8/16/24/32) Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE) * * * * */ BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) { GLuint PixelFormat; // Holds The Results After Searching For A Match WNDCLASS wc; // Windows Class Structure DWORD dwExStyle; // Window Extended Style DWORD dwStyle; // Window Style RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values WindowRect.left=(long)0; // Set Left Value To 0 WindowRect.right=(long)width; // Set Right Value To Requested Width WindowRect.top=(long)0; // Set Top Value To 0 WindowRect.bottom=(long)height; // Set Bottom Value To Requested Height fullscreen=fullscreenflag; hInstance wc.style wc.lpfnWndProc wc.cbClsExtra wc.cbWndExtra wc.hInstance wc.hIcon wc.hCursor wc.hbrBackground wc.lpszMenuName wc.lpszClassName = = = = = = = = = = = // Set The Global Fullscreen Flag GetModuleHandle(NULL); CS_HREDRAW | CS_VREDRAW | CS_OWNDC; (WNDPROC) WndProc; 0; 0; hInstance; LoadIcon(NULL, IDI_WINLOGO); LoadCursor(NULL, IDC_ARROW); NULL; NULL; "OpenGL"; // // // // // // // // // // // Grab An Instance For Our Window Redraw On Size, And Own DC For Window. WndProc Handles Messages No Extra Window Data No Extra Window Data Set The Instance Load The Default Icon Load The Arrow Pointer No Background Required For GL We Don’t Want A Menu Set The Class Name if (!RegisterClass(&wc)) // Attempt To Register The Window Class { MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } if (fullscreen) // Attempt Fullscreen Mode? { DEVMODE dmScreenSettings; // Device Mode memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory’s Cleared dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure dmScreenSettings.dmPelsWidth = width; // Selected Screen Width dmScreenSettings.dmPelsHeight = height; // Selected Screen Height dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) { // If The Mode Fails, Offer Two Options. Quit Or Use Windowed Mode. if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YES { fullscreen=FALSE; // Windowed Mode Selected. Fullscreen = FALSE } else { // Pop Up A Message Box Letting User Know The Program Is Closing. MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP); return FALSE; // Return FALSE } } } if (fullscreen) // Are We Still In Fullscreen Mode? 41 7.2 Realisierung eines Würfels unter OpenGL Projekt Graphik { dwExStyle=WS_EX_APPWINDOW; dwStyle=WS_POPUP; ShowCursor(FALSE); // Window Extended Style // Windows Style // Hide Mouse Pointer } else { dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwStyle=WS_OVERLAPPEDWINDOW; } // Window Extended Style // Windows Style AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size // Create The Window if (!(hWnd=CreateWindowEx( dwExStyle, "OpenGL", title, dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, NULL, NULL, hInstance, NULL))) // // // // // // // // // // // // // Extended Style For The Window Class Name Window Title Defined Window Style Required Window Style Required Window Style Window Position Calculate Window Width Calculate Window Height No Parent Window No Menu Instance Dont Pass Anything To WM_CREATE { KillGLWindow(); // Reset The Display MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } static PIXELFORMATDESCRIPTOR pfd= { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, bits, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; // pfd Tells Windows How We Want Things To Be // // // // // // // // // // // // // // // // // // Size Of This Pixel Format Descriptor Version Number Format Must Support Window Format Must Support OpenGL Must Support Double Buffering Request An RGBA Format Select Our Color Depth Color Bits Ignored No Alpha Buffer Shift Bit Ignored No Accumulation Buffer Accumulation Bits Ignored 16Bit Z-Buffer (Depth Buffer) No Stencil Buffer No Auxiliary Buffer Main Drawing Layer Reserved Layer Masks Ignored if (!(hDC=GetDC(hWnd))) // Did We Get A Device Context? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can’t Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Did Windows Find A Matching Pixel Format? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can’t Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } if(!SetPixelFormat(hDC,PixelFormat,&pfd)) // Are We Able To Set The Pixel Format? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can’t Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } if (!(hRC=wglCreateContext(hDC))) // Are We Able To Get A Rendering Context? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can’t Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } if(!wglMakeCurrent(hDC,hRC)) // Try To Activate The Rendering Context { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can’t Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } 42 7.2 Realisierung eines Würfels unter OpenGL ShowWindow(hWnd,SW_SHOW); SetForegroundWindow(hWnd); SetFocus(hWnd); ReSizeGLScene(width, height); // // // // Projekt Graphik Show The Window Slightly Higher Priority Sets Keyboard Focus To The Window Set Up Our Perspective GL Screen if (!InitGL()) // Initialize Our Newly Created GL Window { KillGLWindow(); // Reset The Display MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } return TRUE; // Success } LRESULT CALLBACK WndProc( This Window HWND hWnd, // Handle For UINT WPARAM LPARAM uMsg, wParam, lParam) // Message For This Window // Additional Message Information // Additional Message Information { switch (uMsg) { case WM_ACTIVATE: { if (!HIWORD(wParam)) { active=TRUE; } else { active=FALSE; } // Check For Windows Messages // Watch For Window Activate Message // Check Minimization State // Program Is Active // Program Is No Longer Active return 0; // Return To The Message Loop } case WM_SYSCOMMAND: { switch (wParam) { case SC_SCREENSAVE: case SC_MONITORPOWER: return 0; } break; } // Intercept System Commands // Check System Calls // Screensaver Trying To Start? // Monitor Trying To Enter Powersave? // Prevent From Happening // Exit case WM_CLOSE: { PostQuitMessage(0); return 0; } // Did We Receive A Close Message? // Send A Quit Message // Jump Back case WM_KEYDOWN: { keys[wParam] = TRUE; return 0; } // Is A Key Being Held Down? // If So, Mark It As TRUE // Jump Back case WM_KEYUP: { keys[wParam] = FALSE; return 0; } // Has A Key Been Released? // If So, Mark It As FALSE // Jump Back case WM_SIZE: // Resize The OpenGL Window { ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // LoWord=Width, HiWord=Height return 0; // Jump Back } } // Pass All Unhandled Messages To DefWindowProc return DefWindowProc(hWnd,uMsg,wParam,lParam); } int WINAPI WinMain( HINSTANCE HINSTANCE LPSTR int { MSG msg; BOOL done=FALSE; hInstance, hPrevInstance, lpCmdLine, nCmdShow) // // // // Instance Previous Instance Command Line Parameters Window Show State // Windows Message Structure // Bool Variable To Exit Loop MessageBox(NULL,"Pfeiltasten für Bewegung\n l - Licht\n f - Filter\n z - Buffer", "Tastaturbelegung", MB_OK); // Ask The User Which Screen Mode They Prefer if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO) { 43 7.2 Realisierung eines Würfels unter OpenGL fullscreen=FALSE; Projekt Graphik // Windowed Mode } // Create Our OpenGL Window if (!CreateGLWindow("PiCube3D",640,480,16,fullscreen)) { return 0; // Quit If Window Was Not Created } while(!done) // Loop That Runs While done=FALSE { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting? { if (msg.message==WM_QUIT) // Have We Received A Quit Message? { done=TRUE; // If So done=TRUE } else // If Not, Deal With Window Messages { TranslateMessage(&msg); // Translate The Message DispatchMessage(&msg); // Dispatch The Message } } else // If There Are No Messages { // Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene() if ((active && !DrawGLScene()) || keys[VK_ESCAPE]) // Active? Was There A Quit Received? { done=TRUE; // ESC or DrawGLScene Signalled A Quit } else // Not Time To Quit, Update Screen { SwapBuffers(hDC); // Swap Buffers (Double Buffering) if (keys[’L’] && !lp) { lp=TRUE; light=!light; if (!light) { glDisable(GL_LIGHTING); } else { glEnable(GL_LIGHTING); } } if (!keys[’L’]) { lp=FALSE; } if (keys[’F’] && !fp) { fp=TRUE; filter+=1; if (filter>2) { filter=0; } } if (!keys[’F’]) { fp=FALSE; } if (keys[’Z’] && !lp) { zp=TRUE; zbuffer=!zbuffer; if (!zbuffer) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } if (!keys[’Z’]) { zp=FALSE; } if (!keys[’F’]) { fp=FALSE; } if (keys[VK_PRIOR]) { 44 7.2 Realisierung eines Würfels unter OpenGL Projekt Graphik z-=0.02f; } if (keys[VK_NEXT]) { z+=0.02f; } if (keys[VK_UP]) { xspeed-=0.001f; } if (keys[VK_DOWN]) { xspeed+=0.001f; } if (keys[VK_RIGHT]) { yspeed+=0.001f; } if (keys[VK_LEFT]) { yspeed-=0.001f; } if (keys[VK_F1]) // Is F1 Being Pressed? { keys[VK_F1]=FALSE; // If So Make Key FALSE KillGLWindow(); // Kill Our Current Window fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode // Recreate Our OpenGL Window if (!CreateGLWindow("PiCube3D",640,480,16,fullscreen)) { return 0; // Quit If Window Was Not Created } } } } } // Shutdown KillGLWindow(); return (msg.wParam); // Kill The Window // Exit The Program } \end{document} 45 7.3 Realisierung eines Würfels unter DirectX 7.3 Projekt Graphik Realisierung eines Würfels unter DirectX Der folgende Quellcode generiert einen in Direct3D9 erzeugten, rotierenden Würfel #include <windows.h> #include <d3dx9.h> #include <d3d9.h> //Definition vom Vertex Koord.i.Modelspace Texturkoord. #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) // Private GDI Schnittstelle HDC hDC = NULL; HWND hWnd = NULL; // Haltet die Instanz der Applikation HINSTANCE hInstance; // DirectX 3D Version 9 Objekt LPDIRECT3D9 pD3D = NULL; // DirectX 3D Render Schnittstelle LPDIRECT3DDEVICE9 pD3DDevice = NULL; // DirectX Textur Schnittstelle LPDIRECT3DTEXTURE9 pTexture = NULL; bool keys[256]; active=TRUE; fullscreen=TRUE; // Array für Keyboard Routine bool // Window Active Flag Set TRUE By Default bool // Fullscreen Flag Set To Fullscreen Mode // Vertex Buffer IDirect3DVertexBuffer9 *pVertexBuffer = NULL; struct my_vertex{ FLOAT x, y, z; // untransformierte Position vom Vertex. DWORD Diffuse; // Diffuse Komponent FLOAT tu, tv; // Texturkoordinaten }; //* Würfelkoordinaten * my_vertex g_vertices[] ={ // // Würfelkoordinaten | Texturkoordinaten X Y Z Diffuse Wert X { -1.0f, -1.0f, -1.0f,0, 0.0f, 1.0f { -1.0f, 1.0f, -1.0f,0, 0.0f, 0.0f { 1.0f, 1.0f, -1.0f,0, 1.0f, 0.0f { 1.0f, 1.0f, -1.0f,0, 1.0f, 0.0f { 1.0f, -1.0f, -1.0f,0, 1.0f, 1.0f { -1.0f, -1.0f, -1.0f,0, 0.0f, 1.0f Y }, }, }, }, }, }, { 1.0f, -1.0f, { 1.0f, 1.0f, { -1.0f, 1.0f, { -1.0f, 1.0f, { -1.0f, -1.0f, { 1.0f, -1.0f, }, }, }, }, }, }, { -1.0f, { -1.0f, { 1.0f, { 1.0f, { 1.0f, { -1.0f, 1.0f,0, 1.0f,0, 1.0f,0, 1.0f,0, 1.0f,0, 1.0f,0, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f,0, 0.0f, 1.0f }, 1.0f, 1.0f,0, 0.0f, 0.0f }, 1.0f, 1.0f,0, 1.0f, 0.0f }, 1.0f, 1.0f,0, 1.0f, 0.0f }, 1.0f, -1.0f,0, 1.0f, 1.0f }, 1.0f, -1.0f,0, 0.0f, 1.0f }, { 1.0f, -1.0f, -1.0f,0, 0.0f, { 1.0f, -1.0f, 1.0f,0, 0.0f, { -1.0f, -1.0f, 1.0f,0, 1.0f, { -1.0f, -1.0f, 1.0f,0, 1.0f, { -1.0f, -1.0f, -1.0f,0, 1.0f, { 1.0f, -1.0f, -1.0f,0, 0.0f, { { { { { 1.0f 0.0f 0.0f 0.0f 1.0f 1.0f //Front face //Back face //Top face 1.0f 0.0f 0.0f 0.0f 1.0f 1.0f }, }, }, }, }, }, //Bottom face -1.0f, -1.0f, 1.0f,0, 0.0f, 1.0f -1.0f, 1.0f, 1.0f,0, 0.0f, 0.0f -1.0f, 1.0f, -1.0f,0, 1.0f, 0.0f -1.0f, 1.0f, -1.0f,0, 1.0f, 0.0f -1.0f, -1.0f, -1.0f,0, 1.0f, 1.0f }, }, }, }, }, //Left face 46 7.3 Realisierung eines Würfels unter DirectX { -1.0f, -1.0f, { { { { { { Projekt Graphik 1.0f,0, 0.0f, 1.0f }, 1.0f, -1.0f, -1.0f,0, 0.0f, 1.0f }, 1.0f, 1.0f, -1.0f,0, 0.0f, 0.0f }, 1.0f, 1.0f, 1.0f,0, 1.0f, 0.0f }, 1.0f, 1.0f, 1.0f,0, 1.0f, 0.0f }, 1.0f, -1.0f, 1.0f,0, 1.0f, 1.0f }, 1.0f, -1.0f, -1.0f,0, 0.0f, 1.0f }, //Right face }; #define NUM_VERTICES (sizeof(g_vertices)/sizeof(my_vertex)) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); Deklaration für WndProc void ReSizeD3DScene(int width, int height) und Initialisierung vom D3D Fenster { if (height==0) { height=1; } // // Resize // Vorbeugen Nulldivision // Height 1 setzen D3DXMATRIX projection_matrix; D3DXMatrixPerspectiveFovLH(&projection_matrix, 45.0f,(float)width/(float) height, 0.1f, 100.0f ); pD3DDevice->SetTransform( D3DTS_PROJECTION, &(D3DMATRIX)projection_matrix ); D3DXMatrixIdentity(&projection_matrix); } int InitD3D() Für D3D { // Setup pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE ); // ZBUFFER pD3DDevice->SetRenderState(D3DRS_CULLMODE, FALSE); // Backface Culling pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); // Licht pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); pD3DDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); pD3DDevice->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); pD3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); pD3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); pD3DDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ANISOTROPIC); D3DXCreateTextureFromFile( pD3DDevice, "stein.jpg",&pTexture); pD3DDevice->CreateVertexBuffer( 36*sizeof(my_vertex),0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVertexBuffer, NULL ); unsigned char *pVertices = NULL; pVertexBuffer->Lock( 0, sizeof(g_vertices), (void**)&pVertices, 0 ); memcpy( pVertices, g_vertices, sizeof(g_vertices) ); pVertexBuffer->Unlock(); return TRUE; //Initialisierung OK } int DrawD3DScene() // Zeichnen { pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, // Clear Screen D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,0.0f), 1.0f, 0 ); static float rotqube = 0.0f; //Rotationsgeschwindigkeit rotqube += 0.4f; D3DXMATRIX D3DXMATRIX D3DXMATRIX D3DXMATRIX D3DXMATRIX D3DXMATRIX matWorld; matTranslation; matRotX; matRotY; matRotZ; matRotXYZ; // // // // // // World Matrix Translation Matrix X Achse Rotations Matrix Y Achse Rotations Matrix Z Achse Rotations Matrix XYZ Rotations Matrix 47 7.3 Realisierung eines Würfels unter DirectX Projekt Graphik D3DXMatrixTranslation( &matTranslation, 0.0f, 0.0f, 5.0f ); D3DXMatrixRotationY(&matRotY, D3DXMatrixRotationX(&matRotX, D3DXMatrixRotationY(&matRotY, D3DXMatrixRotationZ(&matRotZ, D3DXToRadian(rotqube)); D3DXToRadian(rotqube)); D3DXToRadian(rotqube)); D3DXToRadian(rotqube)); // Rotation in Y Richtung // Rotation in X Richtung // Rotate In Z Richtung D3DXMatrixRotationYawPitchRoll( &matRotX, D3DXToRadian(rotqube), D3DXToRadian(rotqube), D3DXToRadian(rotqube) ); matWorld = (matRotY * matRotX * matRotZ) * matTranslation; pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld ); // Setup Transformation pD3DDevice->BeginScene(); // Begin der Direct3D Szene pD3DDevice->SetStreamSource( 0, pVertexBuffer, 0, sizeof(my_vertex) ); pD3DDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,NUM_VERTICES/3); //Würfel zeichnen pD3DDevice->EndScene(); // Ende der Direct3D Szene pD3DDevice->Present( NULL, NULL, NULL, NULL );// Ergebnis anzeigen pD3DDevice->SetTexture( 0, pTexture ); return TRUE; } void KillD3DScene() { if( pVertexBuffer != NULL ) { pVertexBuffer->Release(); pVertexBuffer = NULL; pTexture->Release(); pTexture=NULL; // Vertex Buffer freimachen } } void KillD3DWindow() schliessen { if (pD3DDevice != NULL) pD3DDevice->Release(); // Fenster // D3D Schnittstelle freimachen if (pD3D != NULL) pD3D->Release(); // D3D Schnittstelle freimachen if (fullscreen) { ChangeDisplaySettings(NULL,0); ShowCursor(TRUE); } // Vollbildabfrage // Wenn ja, zurück zum Desktop // Mauszeiger anzeigen if (hDC && !ReleaseDC(hWnd,hDC)) // Kann DC freigemacht werden { MessageBox(NULL,"Release Device Context Fehlgeschlagen.","SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); hDC=NULL; // DC NULL setzen } if (hWnd && !DestroyWindow(hWnd)) // Kann man Fenster schliessen { MessageBox(NULL,"Fenster konnte nicht entfernt werden -> hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); hWnd=NULL; // hWnd NULL setzen } if (!UnregisterClass("Direct3D",hInstance)) // Kann man Klasse unregistrieren { MessageBox(NULL,"Programm konnte nicht korrekt abgemeldet werden.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); hInstance=NULL; // hInstance NULL setzen } } //============================================================================================ // Fenstergenerierung //=========================================================================================== BOOL CreateD3DWindow(char* title, int width, int height, bool 48 7.3 Realisierung eines Würfels unter DirectX fullscreenflag) { WNDCLASS wc; DWORD dwExStyle; DWORD dwStyle; RECT WindowRect; WindowRect.left=(long)0; WindowRect.right=(long)width; WindowRect.top=(long)0; WindowRect.bottom=(long)height; fullscreen=fullscreenflag; hInstance wc.style wc.lpfnWndProc wc.cbClsExtra wc.cbWndExtra wc.hInstance wc.hIcon wc.hCursor wc.hbrBackground wc.lpszMenuName wc.lpszClassName = = = = = = = = = = = // // // // // // // Projekt Graphik Fenster Extended Style Fenster aussehen Werte Dreieck oben links / unten rechts Linkswert 0 Rechtswert auf angeforderte Breite Wert oben 0 Wert oben auf angeforderte Höhe // Globaler Fullscreen Flag GetModuleHandle(NULL); CS_HREDRAW | CS_VREDRAW | CS_OWNDC; (WNDPROC) WndProc; 0; 0; hInstance; LoadIcon(NULL, IDI_WINLOGO); LoadCursor(NULL, IDC_CROSS); NULL; NULL; "Direct3D"; // // // // // Icon Mauszeiger Hintergrund D3D aber 0 Menü, aber 0 Klasse if (!RegisterClass(&wc)) // Fenster registrieren { MessageBox(NULL,"Registrieren der Window Klasse fehlgeschlagen.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; } if (fullscreen) { dwExStyle=WS_EX_APPWINDOW; dwStyle=WS_POPUP; ShowCursor(FALSE); } else { dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwStyle=WS_OVERLAPPEDWINDOW; } // Vollbild? // Mauszeiger verstecken AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Fenster einstellen auf angeforderte Größe // Create The Window if (!(hWnd=CreateWindowEx( dwExStyle, "Direct3D", title, dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, NULL, NULL, hInstance, NULL))) // // // // // // // // // // Klassenname Fenstername Definierter Fenster Style Benötigter Fenster Style Benötigter Fenster Style Fenster Position Fenster Breite anpassen Fenster Höhe anpassen Kein parent Window Kein Menü { KillD3DWindow(); // Reset Anzeige MessageBox(NULL,"Fenstererzeugungsfehler.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; } if (!(hDC=GetDC(hWnd))) // Schnittstellen Context ? { KillD3DWindow(); MessageBox(NULL,"Kann keinen Schnittstellen Contex erzeugen.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } pD3D = Direct3DCreate9(D3D_SDK_VERSION); // Abfrage DX Version if ( pD3D == NULL ) { KillD3DWindow(); MessageBox(NULL,"Kann DirectX SDK Version 9.x nicht finden","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; } D3DPRESENT_PARAMETERS d3dpp= { width, height, D3DFMT_R5G6B5, // d3dpp übergibt Paramter Windows // Back Buffer Breite // Back Buffer Höhe // Back Buffer Format (Farbtiefe) 49 7.3 Realisierung eines Würfels unter DirectX 1, D3DMULTISAMPLE_NONE, 0, D3DSWAPEFFECT_DISCARD, hWnd, !fullscreen, TRUE, D3DFMT_D16, 0, D3DPRESENT_RATE_DEFAULT, D3DPRESENT_INTERVAL_DEFAULT Projekt Graphik // Back Buffer Zählen (Double Buffer) // Fenster oder Vollbild // 16Bit Z-Buffer (Depth Buffer) // Refresh Rate auf default }; // Surface Format überprüfen if ( FAILED( pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, d3dpp.AutoDepthStencilFormat ) ) ) { KillD3DWindow(); // Reset The Display MessageBox(NULL,"Surface Format nicht gefunden.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } // DirectX 3D Schnittstelle überprüfen if(FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pD3DDevice ) ) ) { KillD3DWindow(); MessageBox(NULL,"Kann DirectX 3D Schnittstelle nicht erzeugen.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; } ShowWindow(hWnd,SW_SHOW); SetForegroundWindow(hWnd); SetFocus(hWnd); ReSizeD3DScene(width, height); // Fenster anzeigen // Focus setzen // Perspektive setzen if (!InitD3D()) // D3D Fenster initialisieren { KillD3DWindow(); MessageBox(NULL,"Initialisierung fehlgeschlagen.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; } return TRUE; } LRESULT CALLBACK WndProc( HWND UINT WPARAM LPARAM hWnd, uMsg, wParam, lParam ) // MESSAGEHANDLER { switch( uMsg ) { case WM_ACTIVATE: { if (!HIWORD(wParam)) { active=TRUE; } else { active=FALSE; } // Aktive Nachricht ? // Minimiert ? // Programm aktiv // Programm inaktiv return 0; } case WM_SYSCOMMAND: { switch (wParam) { case SC_SCREENSAVE: case SC_MONITORPOWER: return 0; } break; } // Screensaver start ? // Energiemodus aktiv ? case WM_CLOSE: { // Close Nachricht erhalten? 50 7.3 Realisierung eines Würfels unter DirectX PostQuitMessage(0); return 0; Projekt Graphik // Quit Message senden } case WM_KEYDOWN: { keys[wParam] = TRUE; return 0; } // Taste gedrückt? // Falls ja TRUE case WM_KEYUP: { keys[wParam] = FALSE; return 0; } // Falls ja FALSE // Taste nicht gedrückt? case WM_SIZE: // Direct3D Fenster neue Größe { if(!fullscreen) ReSizeD3DScene(LOWORD(lParam), HIWORD(lParam)); // LoWord=Breite, HiWord=Höhe return 0; } } // Alle unbehandelten Nachrichten an DefWindowProc senden return DefWindowProc(hWnd,uMsg,wParam,lParam); } int WINAPI WinMain( HINSTANCE HINSTANCE LPSTR int ) { MSG BOOL hInstance, hPrevInstance, lpCmdLine, nCmdShow msg; done=FALSE; // Bool Variable um aus Schleife zu kommen // Welcher Bildschirmmodus ? if (MessageBox(NULL,"F1 - Vollbildmodus \nF2 - ZBUFFER aus\nF3 - ZBUFFER an\nF4 - Wireframe\nESC - Programm beenden", "Funktionstasten",MB_OK { fullscreen=FALSE; // Fenstermodus } // Create Our DirectX 3D Window if (!CreateD3DWindow("Projekt Graphik (C) 2005 by Christian Piwecki",1024,768,fullscreen)) { return 0; // Quit wenn Fenster nicht erzeugt } while(!done) // Schleife done=FALSE { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Wartet Nachricht ? { if (msg.message==WM_QUIT) // Quit Nachricht ? { done=TRUE; // If So done=TRUE } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else // Wenn keine Nachrichten vorhanden { // Zeichnen der Szene. Abfragen von ESC Key und DrawD3DScene() if ((active && !DrawD3DScene()) || keys[VK_ESCAPE]) // Active? { done=TRUE; // ESC DrawD3DScene } Quit erhalten? // Vollbild F1 if (keys[VK_F1]) // F1 gedrückt ? { keys[VK_F1]=FALSE; // Wenn ja key = false KillD3DWindow(); fullscreen=!fullscreen; // Vollbild / Fenstermodus // D3D Fenster neu machen if (!CreateD3DWindow("Projekt Graphik (C) 2005 by Christian Piwecki",1024,768,fullscreen)) { return 0; // Quit wenn kein Fenster erzeugt wurde } } 51 7.3 Realisierung eines Würfels unter DirectX Projekt Graphik // ZBUFFER aus F2 if (keys[VK_F2]) { pD3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE ); // ZBUFFER AUS pD3DDevice->SetRenderState(D3DRS_CULLMODE, FALSE); // Backface Culling aus pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); // Licht an pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); pD3DDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); pD3DDevice->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); D3DXCreateTextureFromFile( pD3DDevice, "stein.jpg",&pTexture); pD3DDevice->CreateVertexBuffer( 36*sizeof(my_vertex),0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVertexBuffer, NULL ); unsigned char *pVertices = NULL; pVertexBuffer->Lock( 0, sizeof(g_vertices), (void**)&pVertices, 0 ); memcpy( pVertices, g_vertices, sizeof(g_vertices) ); pVertexBuffer->Unlock(); } // ZBUFFER mit F3 einschalten if (keys[VK_F3]) { pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE ); // ZBUFFER AN pD3DDevice->SetRenderState(D3DRS_CULLMODE, FALSE); // Backface Culling aus pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); // Licht an pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); pD3DDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); pD3DDevice->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); D3DXCreateTextureFromFile( pD3DDevice, "stein.jpg",&pTexture); pD3DDevice->CreateVertexBuffer( 36*sizeof(my_vertex),0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVertexBuffer, NULL ); unsigned char *pVertices = NULL; pVertexBuffer->Lock( 0, sizeof(g_vertices), (void**)&pVertices, 0 ); memcpy( pVertices, g_vertices, sizeof(g_vertices) ); pVertexBuffer->Unlock(); } // Wireframe aktivieren if (keys[VK_F4]) { pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE ); // ZBUFFER AN pD3DDevice->SetRenderState(D3DRS_CULLMODE, FALSE); // Backface Culling aus pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); // Licht an pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); pD3DDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); pD3DDevice->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); // Wireframes AN D3DXCreateTextureFromFile( pD3DDevice, "stein.jpg",&pTexture); pD3DDevice->CreateVertexBuffer( 36*sizeof(my_vertex),0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVertexBuffer, NULL ); unsigned char *pVertices = NULL; pVertexBuffer->Lock( 0, sizeof(g_vertices), (void**)&pVertices, 0 ); memcpy( pVertices, g_vertices, sizeof(g_vertices) ); pVertexBuffer->Unlock(); } } } // Shutdown KillD3DWindow(); return (msg.wParam); // Exit } 52 7.3 Realisierung eines Würfels unter DirectX \end{document} 53 Projekt Graphik