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

Documentos relacionados