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