Direct3D 8

Transcription

Direct3D 8
Direct3D 8
Ein kurzer Überblick
Seminararbeit von
Michael Sonnenfroh
Mai 2001
Seite 1 von 13
Mircosoft™ Direct3D
Direct3D ist eine Grafikschnittstelle, die einen Geräte unabhängigen Zugriff auf moderne 3D
Grafikhardware bietet. Direct3D ist eine Low-Level API, die die Kommunikation mit der Hardware
auf einer sehr tiefen Ebene bietet. Dennoch wird der Programmierer durch einen
HardwareAbstractionLayer weit genug von der eigentlichen Hardware abgekoppelt, um sich keine
Gedanken um den spezifischen Grafikchip machen zu müssen.
Kapitel 1:
Grundlagen
Transformation
Einer der wichtigsten Punkte in der 3D -Programmierung ist das Positionieren von Objekten im
Raum. In Direct3D geschieht das mit Hilfe von 4x4 Matrizen. Diese enthalten zum einen eine 3x3
Matrix für die Transformation des Objekts (Drehung), als auch einen 4D Vektor mit der Position im
Raum.
Direct3D unterscheidet zwischen drei verschiedenen Matrizen:
1.WorldMatrix
Dies Matrix konvertiert ein Modell von seinem
lokalen Koordinatensystem in das
Koordinatensystem der 3D-Szene (Welt).
2.ViewMatrix
Die ViewMatrix positioniert die Kamera in der Welt
und bestimmt deren Ausrichtung. Im Kamera -Raum
befindet sich der Betrachter im Ursprung und schaut
in Richtung der positiven Z-Achse.
3.ProjectionMatrix
Die Projektions-Matrix beschreibt den internen Zustand der Kamera in Analogie zu einer
Linse. Die Projektions-Matrix sorgt typischerweise für eine perspektivische Korrektur.
Primitives und Punkte(Vertices)
Als ein Primitive bezeichnet man in Direct3D eine Sammlung von Punkten, die ein elementares 3DObjekt ergeben. Direct3D kennt sechs solcher elementaren Objekte; PointList, LineList, LineStrip,
Seite 2 von 13
TriangeList, TriangleStrip und TriangleFan. Alle größeren 3D
-Objekte wie Raumschiffe oder
Gebäude bestehen a us diesen elementaren Objekten. Oftmals wird für Primitives auch das Wort
Polygone gebraucht. (z.B. in OpenGL)
Jeder einzelne Punkt(Vertex) kann in Direct3D eine Vielzahl von Informationen enthalten. Dazu
zählen Texturkoordinaten, Farbwerte, Punktgröße und die eigentliche Position des Punktes. Bis auf
die Position sind alle weiteren Daten optional in Direct3D. Ein Punkt könnte folgende Form haben:
RECORD
x,y,z : Single
<-- Position
Color
: LongWord <-- Farbe
u,v
: Single
<-- Texturkoordinaten
END
Zu beachten ist, dass die Reihenfolge in der die einzelnen Teile des Punktes angegeben werden
entscheidend ist! Über Konstanten teilt man Direct3D mit, welche Informationen ein Vertex enthält.
Linke Hand Kartesisches Koordinatensystem
Microsoft verwendet in Direct3D standardmäßig das Linke Hand Kartesische
Koordinatensystem,d.h
die Punkte, die ein Dreieck definieren, müssen im Uhrzeigersinn angegeben werden. Falls diese
gegen den Uhrzeigersinn angegeben werden , wird das Dreieck nicht gezeic hnet. Dieses Verhalten
wird auch als Backface-Culling bezeichnet.
Licht und Materialien
In Direct3D können bis zu 8 unterschiedliche Lichtquellen definiert werden, die die Szene
beleuchten. Im Gegensatz zur Natur, wo einfallendes Licht von der Oberfläche reflektiert wird und
wieder andere Flächen beleuchtet und so kontinuierlich seine Farbe verändert bis es das Auge des
Betrachters erreicht, wird in Direct3D aus Rechenzeit Gründen ein vereinfachtes Modell
angewendet. Das Licht in D3D besteht aus den drei G rundfarben rot,grün und blau. In Direct3D
wird zwischen zwei grundsätzlichen Lichtarten unterschieden:
1.Ambient Light
Das ist diffuses Licht der Umgebung ohne eine bestimmte Richtung und ohne eine
spezielle Lichtquelle. Indirekte Beleuchtung eines Fotograp
hen ist ein Beispiel für
Ambient Light.
2.Direct Light
Das ist das Licht, das eine Lichtquelle in eine bestimmte Richtung abstrahlt. Es fügt kein
Licht zur Umgebungshelligkeit hinzu.
Direct Lights werden nun in weitere Untergruppen aufgeteilt:
2.1.Point Lights
Punktförmige Lichtquellen strahlen Licht in alle Richtungen aus und werden wie
Seite 3 von 13
Objekte im Raum positioniert. Vergleichbar mit einer Glühbirne.
2.2.Spotlights
Spotlights haben die Eigenschaft, dass sie Licht in genau eine Richtung
emittieren und einen Lic htkegel bilden, der in der Mitte die maximale Helligkeit
aufweist und zu den Rändern hin schwächer wird. Vergleichbar mit einem
Suchscheinwerfer.
2.3.Directional Lights.
Dies sind Lichtquellen ohne wirkliche Position. Sie strahlen ihr Licht parallel aus,
was bedeutet, dass das Licht alle Objekte in der Szene aus der gleichen Richtung
trifft. Vergleichbar ist dies mit dem Licht, das von der Sonne auf die Erde trifft.
Materialien bestimmen, wie 3D -Objekte Licht in einer Szene reflektieren oder emittieren. Es kann
genau angegeben werden, wie stark und in welchem Farbton sie Umgebungs - oder diffuses Licht
reflektieren. Materialien können Licht auch emittieren, um so den Anschein zu erwecken, dass das
Objekte leuchtet. Das emittierte Licht beeinflusst die Beleuchtung anderer 3D-Objekte nicht!
Texturen
Texturen sind aus der heutigen Grafikprogrammierung nicht mehr wegzudenken. Sie ermöglichen
es Objekten ein realistische Aussehen zu geben, ohne das die Polygonanzahl erhöht werden muss.
Im Grunde sind Texturen nur Bitmaps, die auf Polygone gemappt werden.
Texturkoordinaten
Texturen können auf jede Primitive -Art gemappt werden, die Direct3D bietet. Um eine Textur nun
auf ein Dreieck zu legen, muss jedem Punkt eine Texturkoordinate zugeordnet werden. Direct3D
verwendet uniforme Texturkoordinaten, die normaler weise von (0,0) bis (1,1) innerhalb der Textur
reichen (bei 2 -D Texturen). Die Position (0,0) bezieht sich immer auf die linke obere Ecke der
Textur, die Position (1,1) auf die rechte untere Ecke.
Texture Address Modes
Texturkoordinaten, die größer als 1 sind, werden von Direct3D speziell behandelt. Dazu werden die
sogenannten „Texture Adress Modes“ gesetzt:
1.Wrap Texture
Die Textur wird auf das Primitive gekachelt.
2.Mirror Texture
Die Textur wird immer gespiegelt gekachelt.
3.Clamp Texture
Die Textur wird einmal gezeichnet und die Farben der Kanten nach außen verschmiert.
4.Border Color
Direct3D benutzt eine fest vorgegebene Farbe für alle Texturkoordinaten außerhalb 0,1.
Texture Filtering
Wenn eine Textur auf ein Primitive gemappt wird, muss sie meisten verzerrt werden, um an die
Seite 4 von 13
Form und Größe des Primitive's angepasst zu werden. Damit diese Operationen keine zu starken
optischen Artefakte hinterlassen, kann eine Textur gefiltert werden. Folgende Varianten gibt es in
D3D:
1.Nearest Point Sample
Dies ist die Standardmethode von D3D. Es wird einfach der nächst beste Pixel in der
Textur als Farbwert gewählt.
2.Linear Texture Filtering
Bei dieser Methode bildet D3D einen Mittelwert über die umgebenden Texturpixel, um d ie
Farbe des zu setzend Pixel zu ermitteln.
3.Anisotropic Filtering
4.Mipmaps
Kapitel 2: Die Direct3D-Schnittstelle
In diesem Kapitel möchte ich einen Überblick über den Umgang mit der Direct3D
geben und an Hand eines Beispiels die Grundlegenden Funktionen erläutern.
-Schnittstelle
COM-Objekte
DirectX basiert seit den ersten Versionen auf den COM-Objekten von Microsoft. Die COM-Objekte
fungieren als „Black Box“ und stellen nach außen nur ein Interface zur Verfügung. Direct3D kennt
elf verschiedene Interfaces, von denen ich hier nur die Wichtigsten vorstellen möchte.
Initialisierung
Als erstes muss Direct3D initialisiert werden. Im Gegensatz zum Erstellen normaler COM -Objekt
ist bei D3D kein CoInitialize nötig, vielmehr wird die Funktion Direct3DCreate8 benutzt um ein
IDirect3D8 Objekt zu erstellen (wenn von Objekten die Rede ist, sind immer COM
-Objekte
gemeint).
Mit Hilfe dieses Objekts kann ein IDirect3DDevice8 Objekt (kurz device) erzeugt werden, welches
die Direct3D Abstraktion des Grafikadapters darstellt. Der IDirect3D8.CreateDevice-Aufruf erhält
eine Reihe von Parametern, die genau spezifizieren, welcher Grafikadapter , welche Auflösung,
Bildwiederholrate, Farbtiefe,TnL-Support,etc. verwendet werden soll.
VertexBuffer
Wie wir in Kapitel 1 gesehen haben, besteht jedes 3D-Objekt aus einer Vielzahl von Vertices. Diese
Vertices werden in D3D in sogenannten VertexBuffer gespeichert. Ein VertexBuffer ist ein
Speicherbereich, der für den Anwender transparent, sowohl im RAM des Grafikadapters, im AGP Speicher als auch im normalen System
-RAM liegen kann. VertexBuffer sind in modernen
Grafikadapter direkt in Hardware implementiert und werden von Direct3D nur „durchgereicht“. Der
Anwender kann in D3D nicht spezifizieren wo der VertexBuffer liegen soll, er kann
nur durch
Parameter gewisse Einschränkungen bestimmen, die es D3D ermöglichen den bestmöglichen
Speicherplatz zu finden. Über das
device kann ein VertexBuffer erstellt werden. Gelingt die
Seite 5 von 13
Ausführung, erhält man ein COM
-Objekt vom Typ
IDirect3DVertexBuffer8, das die D3D
Abstraktion eines VertexBuffers(kurz VB) darstellt. Um nun unsere Punkte in den VB zu
transferieren müssen wir diesen „locken“.Das bedeutet, wir müssen D3D mitteilen, dass wir Zugriff
auf den Speicherbereich des VB wollen. Gelingt der Zugriff , erhält man einen Zeiger auf einen
Zeiger, der auf den Speicherbereich des VB's zeigt. Das korrekte Dereferenzieren der Zeiger ist
wichtig, da der erste Zeiger in den Kernel verweist und das Schreiben der Punktdaten in denselben
zu äußerst unerwünschten Effekten führt.
Die Punktdaten können nun per memcopy direkt in den VertexBuffer geschrieben werden.
Nach erfolgreichem Kopieren, muss der Zugriff auf den VB durch die Funktion Unlock des VB
Objekts wieder freigegeben werden.
Zu beachten ist, das das Locke n eines VertexBuffers zu einem Stall des System führen kann, wenn
sowohl Grafikchip als auch D3D versuchen gleichzeitig auf den Puffer zuzugreifen. Es führt zwar
nicht zu einem Absturz, beeinträchtigt aber die Performance enorm.
IndexBuffer
Analog zu Ver texBuffer gibt es in Direct3D zusätzlich IndexBuffer ( IDirect3DIndexBuffer8) mit
denen der indexierte Zugriff auf die einzelnen Punkte innerhalb eines VertexBuffer's ermöglicht
wird. Das Erstellen und Verwalten geschieht analog zu den VB's, einziger Unters chied ist die Art
der Daten. Statt kompletter Punkte werden hier nur Indexnummern angegeben (16bit bzw. 32bit).
FlexibleVertexFormat
Nachdem wir nun unsere Punkte in einen VertexBuffer gespeichert haben, müssen wir Direct3D
sagen, welches Format ein Punkt hat, d.h. welche Komponenten der Punkt außer seiner Position
noch enthält. Dies ist wichtig, damit Direct3D die Punkte richtig interpretieren kann. Die
Komposition der Punkte wird Direct3D durch OR Verknüpfte-Konstante erläutert.
Unser Punkt aus Kapitel 1 würde so zusammengesetzt:
FVF = D3DFVF_XYZ OR D3DFVF_DIFFUSE OR D3DFVF_TEX1
Position
OR Farbwert
OR Texturkoordinaten
Mit der Funktion SetVertexShader des device kann man D3D das Punktformat mitteilen.
Streams
Nun müssen wir Direct3D noch angeben,
welche Daten es zum Zeichen verwenden
soll. Diese Daten werden als Streams
bezeichnet. Ein Stream ist entweder ein
VertexBuffer oder ein IndexBuffer. Es
können auch mehrere Streams kombiniert
werden. Dadu rch besteht die Möglichkeit
in einem Stream die Position des Punktes
zu haben und in einen anderen Stream
seine Texturkoordinaten. Mit der Funktion
SetStreamSource des device können die
Streams gesetzt werden.
Seite 6 von 13
Device States
Direct3D ist eine Zustandsmasc hine, d.h. Anwendungen setzen Zustände für Licht, Material und
Transformation.Auf alle dann zum Rendern übergebenen Daten werden diese Zustände
angewendet. Zustandsänderungen beeinflussen Direct3D nie rückwirkend, d.h. Änderungen werden
erst beim Rendern der nächsten Primitives wirksam.
die
Render States
Die Render States kontrollieren den Renderer des Direct3D devices. Dies umfasst Parameter
für Beleuchtung, Clipping, Culling sowie die Transformation. Render States werden mit
der
Funktion SetRenderState des device gesetzt. Für die Transformation Matrizen gibt es
spezielle Funktion SetTransform.
Texture Stage States
Analog zu den Render States setzen
Texture Stage States das Verhalten der Texturen
beim Mappen auf
Primitives. In Direct3D können
bis zu 8 Texturen
zusammengemischt werden. Für jeden Einzelnen dieser „Stages“ können umfangreiche
Einstellungen vorgenommen werden. Jedes dieser acht „
Stages“ wird mit den vorher
berechneten „ Stages“ zusammengemischt. Dies ermöglicht Multitexturing -Effekte wie
Lightmaps oder Bump-Maping.
Rendern
Nachdem die Vertexdaten angelegt wurden und die entsprechenden Renderstates gesetzt wurden, ist
es nun an der Zeit die übergebenen Daten zu rendern. Dies geschieht in Direct3D mit Hilfe der
Funktion DrawPrimitive. Als Parameter erwartet die Funktion die Primitive Art, die Anzahl an zu
Seite 7 von 13
zeichnenden Primitives und die Anzahl verwendeter Punkte. Das Rendern geschieht asynchron, d.h.
das Programm wartet nicht bis der Grafikadapter das Zeichnen beendet hat, sondern ist sofort bereit
die nächsten Befehle anzunehmen. Der Grafiktreiber sorgt hier für die korrekte Zwischenpufferung.
Lost Devices
Ein Direct3D device kann entweder in einem betriebsbereiten Zustand oder in einem verlorenen
Zustand sein. Verlor en bedeutet hier, dass dem Programm die Kontrolle über den Grafikadapter
entzogen wurde. Alle Aufrufe von Direct3D werden korrekt beendet, nur haben sie keine direkten
Auswirkungen mehr. Der Zustand wird zum Beispiel durch einen Taskwechsel in einer Vollbi ldApplikation ausgelöst. Der Programmierer muss nun das Direct3D device neu initialisieren, um den
Betrieb wieder aufnehmen zu können. Dafür ist es aber von Nöten, sämtliche Resourcen auf der
Grafikkarte wie VertexBuffer und Texturen freizugeben und nach dem Reset neu zu laden.
Kapitel 3: Direct3D Architektur
In diesem Kapitel möchte ich einen genaueren Überblick über die Architektur von Direct3D geben
und dabei besonders auf die neuen Komponenten VertexShader und PixelShader eingehen. Mit
DirectX8 is t Microsoft im 3D -Bereich eine Kooperation mit dem Grafikchip Hersteller Nvidia
eingegangen, um die 3D
-Schnittstelle besser auf die Bedürfnisse moderner Grafikchips
abzustimmen.
Rendering Pipeline
Das folgende Diagramm verdeutlicht, wie die einzelnen Pun
kte Direct3D und/oder den
Grafikadapter durchlaufen, bis sie im Framebuffer als fertige Pixel abgelegt werden.
Seite 8 von 13
Vertex Daten werden zuerst von der TnL -Engine des Grafikadapters, der Softwarefunktionen von
Direct3D oder den Vertex Shadern verarbeitet. Dies e Daten werden dann von Direct3D in Software
durch den Sichtbereich des Viewports vorsortiert, wobei gegebenenfalls nicht sichtbare Objekte
eliminier werdent. Im nächsten Schritt werden die einzelnen Primitive's mit Texturen versehen.
Dies geschieht entwe der durch Direct3D -Funktionen in Software/Hardware oder durch spezielle
Pixel Shader. Als letztes folgt Nebelberechnung, Stencil-, Alpha- und Tiefentest, bevor ein Pixel im
Framebuffer abgelegt werden kann. Aber was sind nun die Vertex bzw. Pixel Shader?
Vertex Shader
Vertex Shader sind kleine Programme die das Laden und Verarbeiten von Vertices kontrollieren.
Vertex Shader enthalten Definitionen über das Format der Eingangsdaten, die Anzahl an
verwendeten Streams und eine Funktion, die auf die Punkte ange
wendet wird. Vertex Shader
erzeugen weder neue Punkte, noch löschen sie vorhanden. Der Begriff Vertex Shader bezieht sich
meistens auf die programmierbaren Varianten, obwohl die selbe Technik auch bei den
Standardfunktionen von Direct3D angewendet wird. Als Programmiersprache für die Vertex Shader
dient ein spezieller Assembler, der von Direct3D vorkompiliert wird. Ein Programm kann maximal
128 Instruktionen enthalten, es besteht zum einen aus dem Source -Code und zum anderen aus einer
Datendefinition, die f ür das richtige Mapping der Eingangsdaten sorgt. Bis auf die Geforce3 Karte
von NVidia gibt es bisher noch keine Grafikkarte, die Vertex Shader in Hardware unterstützt. Die
nächste Abbildung zeigt die Umgebung, die ein Vertex Shader Programm sieht, den Pse
udoProzessor.
Seite 9 von 13
Wie die Grafik zeigt, besitzt der Vertex Shader 16 Input Register in denen die Daten aus den
verschiedenen Streams pro Vertex zur Verfügung stehen. Die Input Register sind „weakly typed“,
d.h. wie die Daten interpretiert werden liegt am Vertex Shader, nicht an Typkonventionen. So ist es
zum Beispiel möglich, ganze Transformation Matrizen als Eingabe zu benutzten. Der Constant
Memory ist ein Datenbereich, der für die Aufnahme von Transformationsmatrizen, Farbwerten und
anderen konstanten D aten gedacht ist. Die Einträge in diesem Speicher können während der
Ausführung des Vertex Shaders nicht verändert werden. Um die Berechnungen zu erleichtern,
stehen noch 12 allgemeine Register zur Verfügung. Nach jeder Berechnung müssen die
entsprechenden Ausgaberegister mit gültigen Werten gefüllt werden. Ausgabregister gibt es für die
Position des Punktes, Farbwerte für diffuses Licht und Glanzpunkte,bis zu vier Texturkoordinaten,
Werte für Vertexfog und die Punktgröße. Vertex Shader können in Direct3D
in Form von Text Dateien geladen werden. D3D übernimmt dann die Komplilierung und das Laden des Shaders. Das
folgende kleine Beispielprogramm soll die Arbeitsweise eines Vertex Shaders verdeutlichen:
vs.1.0
mov r0,v0
dp4 oPos.x,r0,v3
dp4 oPos.y,r0,v4
dp4 oPos.z,r0,v5
dp4 oPos.w,r0,v6
mov oD0,v1
mov oT0,v2
;Version des Shaders
;Eingangsvertex v0 in Register r0
;Skalarprodukt mit Vector in r0 und v3
;Skalarprodukt mit Vector in r0 und v4
;Skalarprodukt mit Vector in r0 und v5
;Skalarprodukt mit Vector in r0 und v6
;Farbwert des Vertex ins Ausgaberegister oD0
;Texturkoordinaten des Vertex ins Ausgaberegister oT0
Dieser Shader transformiert den Vertex mit einer Matrix, die er mit seinem Input
-Daten erhält.
Normalerweise steckt die Transformations -Matrix als Konstante im Konstantenbereich, wurde aber
hier von mir durch diese dynamische Variante ersetzt, um die Flexibilität der Vertex Shader zu
demonstrieren.
Seite 10 von 13
Vertex Shader ermöglichen damit dem Grafikprogrammierer, die TnL Hardware direkt zu
programmieren, um so Effekte wie Fischauge, Membran Beleuchtung oder andere aufwendige
Effekte direkt auf der Grafikhardware berechnen zu lassen.
Pixel Shader
Wie wir oben gesehen haben, ermöglichen es Vertex Shader eigene Vertexoperationen zu
definieren und die Vertexdaten individuell durch eigene Funktionen zu bearbeiten. Pixel Shader
ermöglichen es nun eigene Textur - und Blendingoperationen zu implementieren, die Effekte wie
Bump-Mapping oder realistische Per -Pixel Beleuchtung ermöglichen. Im Gegensatz zu Vert ex
Shadern gibt es für Pixel Shader keine Softwareunterstützung, d.h. Pixel Shader sind nur verfügbar,
falls der Grafikadapter dies in Hardware explizit unterstützt.
Die obige Grafik zeigt den logischen Datenfluss durch den Pixel Shader. Die Texturkoord
inaten
und Farbwerte werden für jeden einzelnen Pixel berechnet. Ein Dreieck aus dem Vertex Shader
würde in seine Pixel zerlegt und diese dann jeweils als Eingabe v0 für den Pixel Shader benutzt.
Der Programmierer hat damit die Möglichkeit, direkt auf der
Pixelebene des Framebuffers zu
arbeiten. Wie beim Vertex Shader gilt auch hier, dass weder neuen Punkte erzeugt, noch alte
gelöscht werden können. Pixel Shader Programme werden sind ähnlich geartet wie Vertex Shader
Programme und unterscheiden sich hauptsächlich in ihren Instruktionen voneinander.
Fazit
Direct3D ist eine sehr moderne und durchdachte 3D Schnittstelle, die es dem Programmierer
ermöglicht abstrakt und gleichzeitig sehr dicht an der Hardware zu programmieren. Vorallem die
Vertex- und Pixel Shader zeigen wie aktuell Direct3D8 ist und welches Potential in dieser
Schnittstelle steckt. Die Kooperation mit Nvidia, die Microsoft eingegangen ist, hat dazu sicherlich
einiges beigetragen. Die Entwicklung auf dem Grafiksektor schreitet rasant voran u nd es scheint
beinahe so als wären die Hersteller von Grafikchips den Programmieren von 3D
-Software und
Seite 11 von 13
Spielen immer ein Stück voraus. So bin ich der Meinung, dass es noch ein bis zwei Jahre dauern
wird, bis Spiele das volle Potential, das in Direct3D8 steckt, ausnutzten werden können.
Seite 12 von 13
Quellenverzeichnis
[1]
DirectX 8.0 Programmer's Reference
Microsoft Corporation 2000
[2]
Introduction to Vertex Shader
Richard Huddy Nvidia 2000
Seite 13 von 13