DirectX Graphics - Der erste Kontakt - Softwaretechnologie II - Master of Ceremony: Christian Daum

Die Seite wird erstellt Helga Baum
 
WEITER LESEN
DirectX Graphics
 – Der erste Kontakt –

 Softwaretechnologie II
 Master of Ceremony: Christian Daum
          Sidekick: Patrick Gunia
Was ist DirectX?
ƒ   Eine Sammlung von Application Programming Interfaces (APIs) für
    Multimediaprogramme zur schnellen Ansteuerung von Hardware.
     o insbesondere Grafikkarte, Soundkarte, Netzwerk, Speicher.

ƒ   Anwendungen für DirectX werden mit Hilfe des DirectX SDK erstellt.

ƒ   unterstützte Plattformen:
     o Windows-Plattformen seit Windows 95.
     o Spielekonsole Xbox.

ƒ   DirectX ermöglicht direkte Zugriffe auf die Hardware des Systems,
    ohne die Programme von der Hardware abhängig zu machen.
     o Spiele-Entwicklern wird eine Hardware-Abstraktions-Schicht (HAL) für die
       Spieleprogrammierung zur Verfügung gestellt,
          > Mithilfe der HAL können langsame Schnittstellen umgangen werden.
     o Funktionen, die von der Hardware und damit nicht von der HAL bereitgestellt werden
       können, werden in der Hardware-Emulations-Schicht (HEL) emuliert.

ƒ   Die einzelnen DirectX-Komponenten sind COM-Objekte; Vorteile:
     o Abwärtskompatibilität von DirectX (über alle Versionen hinweg).
     o Sprachenunabhängigkeit von DirectX (Freiheit für Entwickler).
DirectX-Komponenten
 1. DirectX Graphics (Unterstützung von 2D- & 3D-Grafik).
 ƒ   ehemals Direct3D & DirectDraw.
 ƒ   ermöglicht schnellen (weil direkten) Zugriff auf die Grafikkarte.
 ƒ   also vorbei an den langsamen Schnittstellen GDI & DDI (Graphics & Display Device Interface).

 2. DirectX Audio (Unterstützung von Soundeffekte & 3D-Raumklang).
 ƒ   ehemals DirectSound & DirectMusic.
 ƒ   Wiedergabe und Aufnahme von Soundeffekten & Hintergrundmusik (MIDI, allerdings kein mp3).
 ƒ   unterstützt Raumklang (d.h. Positionierung der Klänge im 3D-Raum).

 3. DirectInput (Unterstützung von Eingabegeräten zur Spielsteuerung).
 ƒ   wie Tastatur, Maus, Joysticks usw.
 ƒ   Der Zugriff über DirectInput umgeht das Windows Message System
     (d.h. Ereignis-, Melde- & Warteschlagen) & erfolgt direkt auf die Hardware.
 ƒ   Ermöglicht Force-Feedback-Effekte (z.B. vibrierendes Gamepad) & ActionMapping (größere
     Freiheit für Spieler bei Auswahl & Konfiguration von Eingabegeräten).

 4. DirectPlay (Unterstützung von Multiplayer-Netzwerk-/Online-Games).
 ƒ   Protokoll auf Anwendungsschicht.
 ƒ   Vorteil: unabhängig von konkret genutzten Protokollen der Transport- & Übertragungsebene.

 5. DirectShow (Unterstützung von Streaming Media).
 ƒ   Verarbeitung von Video- und Audio-Dateien (mp3. AVI, MPEG).

 6. DirectSetup (Unterstützung bei der DirectX-Installation).
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

              1.   Welttransformation

              ƒ    = Transformation vom Modell- ins
                   3DWeltkoordinatensystem

              ƒ    DirectX Graphics-Funktionsaufruf:
                   SetTransform(D3DTS_WORLD, &Transformationsmatrix);

              ƒ    Is klar: Erst nach Berechnung der Transformationsmatrix
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

              2.   Sichttransformation I - Überblick

              ƒ    = Transformation eines 3D-Objektes in den
                   Kameraraum
                   o   Kameraraum: Bereich, in dem sich alle sichtbaren
                       Objekte einer 3D-Szene befinden
                   a) Berechnung einer Sichtmatrix (View-Matrix)

                   b) Sichttransformation
                      DirectX Graphics-Funktionsaufruf:
                       SetTransform(D3DTS_WORLD, &ViewMatrix);

                       (Funktionsaufruf bei jeder Änderung der View-Matrix
                       notwendig)
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

              2.   Sichttransformation II – Die View-Matrix

              ƒ    Bei jeder Spielerbewegung ändern sich die Kamera- & damit
                   Blickperspektive auf die entsprechenden 3DObjekte
              ƒ    Eine Anpassung der Perspektive erfolgt nun nicht durch
                   Bewegung oder Drehung der Kamera
                   o stattdessen wird die Kamera im Koordinatenursprung
                     fixiert (mit Blickrichtung entlang der positiven z-Achse)
                   o und alle Objekte gemäß der inversen Kamerabewegung
                     transformiert
              ƒ    Statt also die Kamera auf ein Objekt zu zu bewegen/um ein
                   Objekt zu drehen etc. wird stattdessen das Objekt auf die
                   Kamera zu bewegt/um die Kamera gedreht usw.
              ƒ    Damit entspricht die View-Matrix (na klar – wem sonst?) der
                   inversen Kamera-Transformationsmatrix
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

              2.   Sichttransformation III
                   – Berechnung der View-Matrix

              a)   Definition von 4 Vektoren zur Beschreibung der Position
                   & Ausrichtung der Kamera (Pos, Look, Right, Up)
              b)   Berechnung der View-Matrix auf Basis dieser Vektoren:

                   ƒ DirectX-Graphics-Funktionsaufruf:
                     (View-Matrix für ein linkshändiges Weltkoordinatensystem)
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

              2.   Sichttransformation IV – Attentione!
                   (Kameraverschiebung)
              ƒ    Empfehlung: Man sollte aus Performance-Gründen die
                   inverse Verschiebung der Kamera (bereits) während der
                   Welttransformation aller Objekte berücksichtigen – und
                   nicht erst in der View-Matrix
                   o   Grund: Eine Verschiebung der Kamera entspricht in der View-
                       Matrix einer Verschiebung der Objekte
                   o   Würde die Kamera-Verschiebung also erst in der View-Matrix
                       vorgenommen werden, würden sich (z.B. bei einer 3D-Szene mit
                       2000 Fixsternen) die Objekte ungewollt mitverschieben
                   o   Problem: Vor dem eigentlichen Rendern müsste dann eine
                       erneute Welttransformation aller betroffenen Objekte (hier:
                       2000 Sternsken) vorgenommen werden, um diese (ungewollte)
                       Verschiebung wieder rückgängig zu machen
                   o   s.a. Billboardmatrizen für 2D-Grafiken (Rauch. Explosionen
                       etc.): Die Kameraverschiebung sollte auch hier bereits bei der
                       Welttransformation der Matrizen vorgenommen werden
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

             3.   Projektionstransformation I

             ƒ    = Projektion der 3D-Szene auf den 2D-Bildschirm

                  a)   Berechnung einer Projektionsmatrix
                  b)   DirectX Graphics-Funktionsaufruf:

                       SetTransform(D3DTS_Projection, &ProjectionMatrix);

                       o   Dieser Funktionsaufruf bei jeder Änderung der
                           Projektions-Matrix notwendig
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

3.   Projektionstransformation II - Das Viewing Volume (Bildraum)
ƒ    = der vom Betrachter sichtbare Ausschnitt einer 3D-Szene
ƒ    Dabei wird unterschieden nach
     o   Far Clipping Plane    Æ maximale Sichtweite
     o   Near Clipping Plane   Æ minimale Sichtweite
     o   Fiel of View (FOV)    Æ Blickfeld des Betrachters

     Das Viewing Volume                                      Die Projektionsmatrix
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

3.   Projektionstransformation III - Das Viewing Volume (Bildraum)
ƒ    Gepriesen sei der Herr Æ auch hierfür gibt´s eine entsprechende DirectX-Funktion:

     (Funktionsaufruf zur Erzeugung einer Projektionsmatrix für ein linkshändiges Weltkoordinatensystem)

Arbeitsweise der Projektionsmatrix
ƒ    Die Projektionsmatrix bildet jedes Objekt der Szene auf der Projektionsfläche ab
     o     Attentione: Um Projektionsfehler zu vermeiden, muss der Abstand zw.
           Projektionsfläche & Near Clipping Plane >=1.0 sein!
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

3.   Projektionstransformation IV – Umrechnung von Welt- in
     Bildschirmkoordinaten
ƒ    Für die Transformation der Weltkoordinaten eines Objektes (über die
     Viewportkoordinaten) in die entsprechenden Bildschirmkoordinaten ist
     mal wieder eine Matrix zuständig:
     o    ViewProjectionMatrix = matView*matProj;
     o    Diese Matrix muss für jedes Frame berechnet werden
     o    Durch anschließende Matrizenmultiplikation wird der Ortsvektor eines Objektes in die
          entsprechenden Viewportkoordinaten transformiert

ƒ    Zu beachten ist, dass Viewport & Bildschirm zwar denselben Ausschnitt darstellen,
     ihre Koordinatensysteme jedoch divergieren:
          o    Viewportkoordinaten (-1/-1)     linke obere Bildschirmecke
          o    Viewportkoordinaten 1/1         rechte untere Bildschirmecke
          o    Viewportkoordinaten 0/0         Zentrum

ƒ    Während der Ursprung des Viewportkoordinatensystems also bei (-1/-1) liegt, findet
     sich der Ursprung des Bildschirmkoordinatensystem in der linken oberen Ecke
     o    Aus diesem Grund müssen die Viewportkoordinaten noch in die
          Bildschirmkoordinaten umgerechnet werden
Arbeitsweise einer 3D-Engine
    Die Transformations- & Beleuchtungspipeline

3.    Projektionstransformation V
      Umrechnung von Welt- in
      Bildschirmkoordinaten

ƒ     Und so sieht´s als Funktion aus:
      (berechnet unter Verwendung der
      entsprechenden Sicht- & Projektionsmatrizen
      die Bildschirmkoordinaten eines Objektes)
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

4. Clipping
ƒ   Nach der Projektionstransformation werden die Polygone gegen alle Flächen des
    Viewing Volumes geclippt

    o   Clipping: Die nicht sichtbaren Bereiche eines Polygons werden weggeschnitten
    o   Für ein effizienteres Clipping wird der Viewing Raum zuvor in ein Quader
        transformiert

        ƒ     Grund: Das Clipping gegen die Flächen eines Quaders ist erheblich
              einfacher als gegen die Flächen einer spitzwinkligen Pyramide
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline
5. Object-Culling I
ƒ    Um unnötige Durchläufe von (später ohnehin nicht sichtbaren) 3DObjekten
     durch die Transformationspipeline zu sparen, setzt man Objekt-Culling ein:
     o    Ein Verfahren, um später nicht sichtbare Objekte auszusondern, bevor sie
          rechenintensiv durch die Pipeline gejagt würden

1.   Test auf „reales“ Blickfeld von 180° (Einfachste Variante des Object-Culling):
ƒ    Wird sich das Objekt vor oder hinter dem Betrachter befinden?
     (Annahme: Blickfeld des Betrachters beträgt 180°)
ƒ    Vorgehensweise: Bilden des Skalarprodukts aus Ortsvektor & Blickwinkel des Betrachters

                                                            Effekt: frappierende Objektdiskriminierung!
                                                            Æ Durchschnittlich 50 % aller Objekte wird der
                                                            Zutritt zur Pipeline verwehrt

2.   Test auf Blickfeld von 90° (von –45° bis +45°) [= FOV (Field of View)?]
ƒ    Nun wird der Rest der Objekte darauf getestet, ob sie sich jeweils nicht nur „irgendwie
     vor den Ohren“ des Betrachters - sondern auch in dessen direktem Blickfeld befinden
ƒ    Vorgehensweise: Division des Skalarprodukts durch den Betrag des Ortsvektors
     & Check auf Blickwinkel zw. –45° bis +45°:
                                                            Sicher ist sicher: In der Praxis wäre ein
                                                            etwas größerer Blickwinkel realistischer:
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline

5. Object-Culling II – Effizienz

ƒ   Es gibt allerdings noch eine effizientere Methode, um alle beschriebenen
    Schritte des Object Culling durchzuführen

      o Grund: Die Berechnung es Vektorbetrags ist eigentlich überflüssig
      o Stattdessen können der quadrierte Betrag & das quadrierte Skalarprodukt verwendet
        werden, um sich eine Wurzelberechnung zu sparen:
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline
6. Bilderzeugung – Doppelpufferung (Double Buffering)
ƒ   Bilder werden im RAM bzw. VRAM in Form eines linearen Arrays gespeichert
     o Dabei gilt: 1 Arrayelement = 1 Pixel
     o Der Speicherbedarf der Arrayelemente ist abhängig von der Farbtiefe;
       wir erinnern uns:
          > Pseudo:          Bei 256 Farben/Pixel            =     8 Bit / Arrayelement
          > High Color:      Bei 65536 Farben/Pixel          =     16 Bit / Arrayelement
          > True Color:      Bei 16,7 Mio. Farben/Pixel      =     24/32 Bit / Arrayelement

ƒ   Display Surface (auch Primary Surface)
     o = Speicherbereich des VRAM (Videospeicher), auf den bei der Bilderzeugung
       direkt zugegriffen wird
     o Jede Änderung am Display Surface wird umgehend auf dem Bildschirm umgesetzt

ƒ   Problem: Durch schrittweisen Aufbau eines Frames im Display Surface kommt es zu
    Bildschirmflackern & Doppelbildern
     o Gründ: der Schrittweise Aufbau von Frames braucht eine gewisse Zeit; andauernde
       Bildveränderung generell; asynchroner Bildaufbau (Speicher vs. Bildschirm)
ƒ   Solution: Double Buffering with Backbuffer and Surface Flipping (yeah)!!!
     o Der Backbuffer ist ein zweiter Speicherbereich zum Bildaufbau
          > Dort wird das entsprechende Frame quasi vorbereitet

     o Nun gibt es 2 Möglichkeiten, das vorbereitete Frame in den Display Surface zu bekommen
          > Schlichtes Kopieren vom Backbuffer in den Display Surface Æ böse weil langsam
          > Durch Surface-Flipping: Pointer-Austausch Æ toll, weil schnell:
            Der Austausch des Backbuffer-Zeigers mit demjenigen des Display Surface ist erheblich
            schneller -> ergo wird der Backbuffer nun ad hoc zum neuen Display Surface & umgekehrt
Arbeitsweise einer 3D-Engine
Die Transformations- & Beleuchtungspipeline
7. Tiefenpufferung (Depth Buffering).
ƒ   Generell: Verschiedene Verfahren, um zu ermitteln, welche Pixel sich (auf Basis der
    Betrachter-Perspektive und der Tiefe der Bildpunkte) überlagern und damit für den
    Betrachter sichtbar sein sollen oder nicht.
      o Effekt: Ist die Entfernung zweier sich überlagernder Bildpunkte verschieden, wird der weiter
        entfernte aus dem Bildspeicher durch den näher liegenden Punkt überschrieben.
      o Diese Verfahren müssen in DirectX Graphics nicht explizit initialisiert werden.

z-Buffering-Algorithmus.
ƒ Auf Grafikkarten implementiert (entspricht einem Array mit Dimensionen der
   Bildschirmauflösung); Ablauf:
ƒ Zunächst werden alle Elemente des Bildes in den Bildspeicher projiziert.
ƒ Danach werde die Tiefeninformation der Polygone auf Pixelbasis gespeichert.
ƒ Vor dem Rendern wird der maximal mögliche Tiefenwert (des gesamten Bildes)
   ermittelt und auf alle Elemente des z-Buffers übertragen (Der z-Buffer arbeitet dabi
   mit Tiefenwerten von 0 bis 1).
ƒ Beim Rendern eines Polygons erfolgt dann pixelweise eine Tiefenprüfung.
      o Tiefenwert Z-Buffer > Tiefenwert Pixel = Z-Buffer-Tiefenwert wird durch Piexel-Tiefenwert
        überschrieben.
           > Das entsprechende Pixel ist dem Betrachter also näher & damit sichtbar.
      o Tiefenwert Z-Buffer < Tiefenwert Pixel = Z-Buffer-Tiefenwert bleibt bestehen.
           > Das entsprechende Pixel ist ohnehin nicht sichtbar.

w-Buffering-Algorithmus.
ƒ Speichert im Gegensatz zum z-Buffer statt „künstlichen“ Tiefenwerten direkt die
   z-Komponente der einzelnen Vertex-Positionen.
Das Anwendungsgerüst
1. Gliederung des Anwendungsgerüsts      2. Weitere Dateien:

                                      Workshop Gunia
                                      Wenn es Mr. Sidekick genehm wäre, könnte er hier
                                      zur Erläuterung des Anwendungsgerüstes gerne das
                                      1. Programmbeispiel („FirstContact“)
                                      verchecken? (ach ja: nach 19 Charts wär nun
                                      auch ein Kaffee angebracht... Danke.)
Das Anwendungsgerüst
3. Einzubindende Bibliothek-Dateien:
ƒ   Zum Kompilieren des Anwendungsgerüsts sind folgende Bibliotheken
    einzubinden:

4. DirectX-Ersetzungen (Substitutions)
ƒ   Problem: Jedes DirectX-Update bringt versionsspezifische DirectX-Typen
    & -Funktionsaufrufe mit sich -> ergo hoher Anpassungsaufwand bei jedem
    Versionswechsel
ƒ   Lösung: Deshalb Headerdatei DXSubstitutions.h einbinden (also eigene
    Bezeichnungen definieren und durch den Präprozessor ersetzen lassen):
Das Anwendungsgerüst
5. Die zentrale Headerdatei der Anwendung: space3D.h

                                     Standard-Includes
                                     Funktionsspektrum dieser
                                     Header-Dateien:
                                     ƒ   DirectX-Makros & Helper-Funktionen
                                     ƒ   Textausgabe
                                     ƒ   eine lauffähige DirectX-Graphics-Anwendung
                                     ƒ   mathematische Funktionen
                                     ƒ   Funktionen zur Billboard-Ausrichtung
                                     ƒ   Spielsteuerung & Sound
                                     ƒ   vordefinierte Vertex-Formate
                                     ƒ   Klassen für Generierung & Handling von Texturen

                                         Funktionsprototypen
DirectX Graphics – Initialisierungsschritte
Die Game-Initialisierungs-Routine I                       (Modul: GameRoutines.cpp)

ƒ   Wird bei Programmstart aufgerufen und führt die wichtigsten
    Initialisierungsschritte durch:
    o InitRenderOptions();                                                (Modul: GameRoutines.cpp)
        ¾ s. Tag 1: Ruft die Ressource RenderingAndMore.txt auf
          (Art der Vertexverarbeitung? Frame od. Time Based Rendering?)

    o InitSpieleinstellungen();                                           (Modul: Space3D.cpp)
        ¾ Ruft die Ressource Spieleinstellungen.txt auf
          (enthält Grafikeinstellungen – hier: Sichtweite der 3D-Szene)

    o InitD3D();                                                          (Modul: Space3D.cpp)
        ¾ Initialisierung von DirectX-Graphics (Details Folge-Charts)

    o Init_View_and_Projection_Matrix();                                  (Modul: Space3D.cpp)
        ¾ Erzeugung von Sicht- & Projektionsmatrizen & Transformation
DirectX Graphics – Initialisierungsschritte
Die Game-Initialisierungs-Routine II
Initialisierung von DirectX-Graphics mit InitD3D()
1. Erzeugen eines Direct3D-Objekt mit direct3DCreate9();
ƒ       Als Parameter wird die SDK-Version als Konstante übergeben: D3D_SDK_VERSION

2. Ermitteln des aktuellen Display-Modus mit GetAdapterDisplayMode();
ƒ       Rückgabewert wird in einer Variablen vom Typ D3DDISPLAYMODE gespeichert

3. Abfrage von Display- & Backbuffer-Formaten mit CheckDeviceType();
ƒ       Für den Fullscreen-Modus ist die Abfrage der von der Grafikkarte unterstützten
        Display- & Backbuffer-Formate notwendig:
                                                                    ƒ   Displayformat bei einer Farbtiefe von 32 Bit:
                                                                        D3DFMT_X8R8G8B8

                                                                        R8G8B8    -> 8 Bit für die Darstellung von jeweils
                                                                                     256 R-/G-/B-Tönen

                                                                        X8        -> repräsentiert die 8 unbelegten Bits

                                                                        o Formate bei einer Farbtiefe von 16 Bit:
    ƒ   Definition der Farbformate:                                          D3DFMT_R5G6B5 / _X1R5G5B5 / _X4R4G4B4
        Verschiedene Kombinationen möglich; jedoch sind 2 Regeln
        zu beachten: Display- & Backbuffer-Format müssen            ƒ   Backbuffer-Formate bei einer Farbtiefe von
        1. ... die gleiche Farbtiefe haben!                             32 Bit: D3DFMT_X8R8G8B8 & D3DFMT_A8R8G8B8
        2. ... die gleiche Bitanzahl/Farbwert aufweisen!
                                                                        A8        -> 8 Bit für den Alphakanal (definiert
                                                                                     den Transparenzwert eines Pixels)

    ƒ   Unterstützung bei der Suche nach dem korrekten Farbformat
                                                                        o Formate bei einer Farbtiefe von 16 Bit:
                                                                             D3DFMT_R5G6B5/_X1R5G5B5/_X4R4G4B4/
        o Mithilfe der beiden DirectX-Makros SUCCEDED() FAILED()
                                                                             _A1R5G5B5/_A4R4G4B4
        o Der Rückgabewert HRESULT gibt Auskunft über einen
          erfolgreichen oder fehlgeschlagenen Funktionsaufruf
DirectX Graphics – Initialisierungsschritte
Die Game-Initialisierungs-Routine II
Initialisierung von DirectX-Graphics mit InitD3D()
4.   Definition der Präsentationsparameter:
ƒ    Fullscreen oder Window?
ƒ    Wie viel Backbuffer?
ƒ    Backbuffer-Formt & - Auflösung?
ƒ    Tiefenpuffer (z-Buffer) verwenden?
ƒ    Flipping/Swap-Effect: Art des Wechselns zw. Backbuffer & Display-Surface?
5. Initialisierung eines Grafikkarten-Objekt mit CreateDevice():
ƒ Mit dem so erzeugten Objekt (HAL-Gerät) kann auf die Treiber der Grafikkarte
    zugegriffen werden
       o Das HAL-Gerät fungiert hier gleichsam als „Ersatz“ für den direkten Zugriff auf die Hardware
6. Definition der Vertexverarbeitung:
   verschiedene Arten des Transform & Lightning (Beleuchtung) der Vertices:
ƒ Hardware TnL (schnellste Variante, weil von GPU durchgeführt)
       o Spezielle Graphic Processing Unit auf der Grafikkarte
       o Vorteile: CPU-Entlastung & keine überflüssigen Grafikkarten  CPU-Transfers
       o Hier ist ggf. eine Verwendung der Grafikkarte als sog. pure device (reines Gerät) möglich
         Vorteil:        Schnellstmöglicher Gerätetyp;
         Nachteile:      Keine volle Direct3D-Funktionalität (z.B. keine Get*()-Aufrufe;
                         keine Emulation nicht unterstützter Funktionalitäten durch die HEL;
                         instabil bei unerlaubten Aufrufen etc.
ƒ    Mixed TnL (irgendwas dazwischen)
ƒ    Software TnL (langsamste Variante, weil durch CPU durchgeführt)
DirectX Graphics – Initialisierungsschritte
Die Game-Initialisierungs-Routine II
Initialisierung von DirectX-Graphics mit InitD3D()

7. Render States (Renderzustände) definieren mit SetRenderState()
ƒ   States dienen der detaillierten Steuerung des Rendering
      o Beispiel:

     o Texture Stage States definieren mit SetTextureStageState()
         > Steuerung des Texture Mappings (Auswahl der Texturkoordinaten; Erzeugung von
           Texture Blending Effekten)

     o Sampler States definieren mit SetSamplerState()
         > Ebenfalls zur Steuerung des Texture Mappings (Texturfilterung; Textur-
           Adressierungsmodus)
DirectX Graphics – Initialisierungsschritte
Die Game-Initialisierungs-Routine II
Initialisierung von DirectX-Graphics mit InitD3D()

8. CD3DFONT-Schriftklassen definieren mit der Klasse CD3DFont
ƒ   Dienen der Textausgabe einer 3D-Szene

     o Der auszugebende Text wird als Textur auf ein sog. Quad gemappt
         > Quad: viereckiges Polygon, das später gerendert wird

     o Initialisierung & Deklaration in D3DGlobals.h

     o Implementierung der Klasse in d3dfont.cpp
DirectX Graphics – Initialisierungsschritte
Die Game-Initialisierungs-Routine II
9. View- & Projektionsmatrizen erstellen & transformieren mit
   Init_View_and_Projection_Matrix();

ƒ   Ende der Initialisierungsarbeiten
DirectX Graphics
Anzeige des 3D-Szenarios mit Show_3D_Szenario()
                                                                       Step 1: Löschen der vorangegangenen Szene
                                                                       Æ durch Clear():
                                                                       Durch Clear wird
                                                                       ƒ der Backbuffer mit einer Hintergrundfarbe gefärbt
                                                                       ƒ der z-Buffer mit maximalen Tiefenwerten initialisiert
                                                                       ƒ der Stencil-Buffer mit Werten initialisiert

                                                                       ƒ   Funktionsprototyp:

                                                                       Step 2 & 3: Eine neue Szene beginnen & beenden
                                                                       durch BeginScene() & EndScene():
                                                                       ƒ   BeginScene() „informiert“ Direct X Graphics
                                                                           vom Beginn des Szenenaufbaus
                                                                       ƒ   EndScene() Szenenaufbau fertig – Szene bereit
                                                                           zur Anzeige!

                                                                       Step 4: Neue Szene anzeigen durch Present():
Ausgabe von 2D-Text durch DrawtextScaled():                            ƒ Funktionsprototyp später
ƒ   Viewportkoordinaten
    (Vorteil „Vpk“: Textposition bleibt immer identisch - unabhängig
    von d. jew. Resulotion
ƒ   Textskalierung (B & H),
ƒ   bilineare Filterung mit D3DFONT_FILTERED
    (für bessere Textqualität)
DirectX Graphics
Beenden von DirectX Graphics
- Aufräumarbeiten mit CleanUpD3D()

                         ƒ   CleanUpD3D() wird durch die Methode
                             GameCleanUpRoutine() aufgerufen

                             SAFE_DELETE:
                             Æ Zerstören der beiden CD3DFont-Instanzen
                             SAFE_RELEASE:
                             Æ Freigabe der beiden DirectX-Graphics-Objekte
Punkte, Linien & Kreise
ƒ   Aus diesen geometrischen Grundelementen lassen sich beliebige
    Objekte generieren (vergleichbar mit den Grundfarben...)
ƒ   Zudem lassen sie sich besonders fix rendern

Workshop Gunia
Die Klasse C3DScenario:

Es ist mal wieder soweit:
2. Programmbeispiel
(„Punkte, Linien &
Kreise“) bitte!
UND Kaffee.
Punkte, Linien & Kreise - Anwendungsgerüst
Workshop Gunia
Anwendungsgerüst: Einbinden der Datei 3D_ScenarioClasses.h:
Punkte, Linien & Kreise - Initialisierung
Workshop Gunia
Initialisierungsschritte:
Punkte, Linien & Kreise - Aufräumarbeiten
Workshop Gunia
Aufräumarbeiten:
Punkte, Linien & Kreise rendern
Workshop Gunia
Punkte, Linien & Kreise rendern mit Show_3D_Scenario():
Punkte, Linien & Kreise
FVF: Flexible Vertexformate
ƒ   Vertexdaten: Für jeden Eckpunkt (Vertex) eines Objektes müssen
    (je nach Verwendungszweck) verschiedene Daten gespeichert werden
      o Position
      o Normale (für die Lichtberechnung)
      o Farbe (dann aber nicht Lichtberechnung)
      o Texturkoorinaten (Texture Mapping, Multitexturing)

ƒ   Zu diesem Zweck existiert das Modul VertexFormats.h
    mit dem struct POINTVERTEX:

     o Dort werden für jeden Vertex Position & Farbe gespeichert
         > Konstante D3DFVF_XYZ:
           Vertices müssen noch durch DirectX-Graphics transformiert werden
         > Konstante D3DFVF_DIFFUSE:
           Vertices sind bereits beleuchtet
Punkte, Linien & Kreise – Vertexbuffer I

ƒ   Vertexbuffer: Geschützter Speicherbereich der Grafikkarte
    zur effizienten Vertexverarbeitung
     o Vertexverarbeitung: Transformation und Rendering der Vertexdaten

ƒ   Initialisierung eines Vertexbuffers
     o Beispiel:

     o Parameter:
         > 1. Parameter definiert die Größe des Vertexbuffers
           (Übergabe der Anzahl an Punkten & des Speicherbedarfs eines POINTVERTEX)
         > 2. Parameter definiert den Verwendungszweck durch das Flag D3DUSAGE_WRITEONLY
           (Zwar Lesezugriff untersagt aber dafür effizientere Schreib- & Render-Operationen)
         > 3. Parameter definiert das zu verwendende Vertexformat des Buffers
         > 4. Parameter weist DirectX-Graphics an, sich um die Aufräumarbeiten zu kümmern
         > 5. Parameter definiert Adresse des auf den Vertexbuffer verweisenden Zeigers
         > 6. Parameter „soll uns nicht weiter stören“
Punkte, Linien & Kreise – Vertexbuffer II

ƒ   Zugriff auf Vertexbuffer (Zugriffschutz)
     o Der Buffer muss – als geschützter Speicherbereich – vor jedem Zugriff mit
       der Methode Lock() verriegelt werden
     o Nach Durchführung des Schreibvorgangs wird er mit Unlock() wieder
       entriegelt
Punkte, Linien & Kreise – Vertexbuffer III

ƒ   Vertexdaten transformieren.

     o Die Vertexdaten werden durch die Transformations- &
       Beleuchtungspipeline geschickt.

     o Zu diesem Zweck muss mit der Methode SetFVF() ein
       entsprechender Vertex-Shader ausgewählt werden.

         > Bei Pointvertices: g_pd3dDevice->SetFVF(D3DFVF_POINTVERTEX);
         > Bei programmierbaren Vertex-Shadern: SetVertexShader();

     o Danach werden mit SetStreamSource die später zu rendernden
       Vertextdaten ausgewählt.

         > g_pd3dDevice->SetStreamSource(0, PunkteVB, 0, sizeof(POINTVERTEX));
         > Bei programmierbaren Vertex-Shadern können die Vertexdaten auch
           aus mehreren Sources stammen (ein Vertex-Buffer für
           Texturkoordinaten, einer für Normalen, einer für Positionen etc.
Punkte, Linien & Kreise – Vertexbuffer IV
ƒ   Vertexdaten rendern mit DrawPrimitive()
     o   „Primitive“: definiert, auf welche Weise die Vertices in im
         Vertexbuffer miteinander verbunden werden sollen
     o   Mit DrawPrimitive() können bis zu 6 verschiedene
         Grafikprimitiven gerendert werden:

     o Punkte & Linien rendern
         > Point List rendern (Startindex = 0, da alle Vertexdaten gerendert werden sollen):

         > Eine einzelne Linie rendern:
Punkte, Linien & Kreise – Vertexbuffer V
ƒ   Einen Kreis rendern
      o Eigentlich handelt es sich nicht um Kreise – sondern um einen Polyeder
         > Polyeder: regelmäßiges Vieleck
         > Der angestrebte „Kreis“ wirkt umso realistischer, je größer die Anzahl der
           Polyedersegmente ist
     o Berechnung der Vertexkoordinaten
         > s. Tag 3: 2dimensionale Polarkoordinatendarstellung (Kreiskoordinaten)
         > Attentione! Will man beispielsweise einen 8eckigen Polyeder generieren,
           müssen 9 (und nicht 8!) Eckpunkte definiert werden!
         > Grund: Der letzte Eckpunkt muss immer mit dem ersten identisch sein,
           damit der Polyeder überhaupt geschlossen ist!

     o Das Rendern des „Kreises“ erfolgt aufgrund seiner Natur als Polyeder
       dann auch mit einem Line Strip
         > RingSegmente-1 entspricht dabei der Anzahl der zu rendernden Grafikprimitiven
         > Grund: Ein Line Strip besteht zwar aus n Punkten, jedoch nur aus n-1 Linien
Texturen
ƒ   Texturen sind „einfache“ Bitmapgrafiken, welche die Oberflächen
    eines 3D-Körpers definieren und im VRAM gespeichert sind.
     o Durch Texturen wird eine „realistischere“ Darstellung der Objekte erreicht,
       ohne die Anzahl der Polygone erhöhen zu müssen.
     o Ein Pixel der Textur wird als Texel bezeichnet.

ƒ   Texture Mapping meint dabei das Verfahren zur Ausstattung
    dreidimensionaler Objektoberflächen mit zweidimensionalen Texturen.
     o Beim Texture Mapping werden die Polygone eines Objektes (nach dessen
       Transformation) gemäß der in den Vertices gespeicherten
       Texturkoordinaten mit Texturen überzogen.
     o Dabei werden die Texturen in einem rechenintensiven Verfahren Texel für
       Texel auf die entsprechenden Polygone gemappt (aufgetragen).
     o Erschwerender Aspekt beim Texture Mapping:
         > Frei bewegliche & in ihrer Größe variierende 3D-Objekte...
Texturen - Generierung
ƒ    Die Textur-Helperklasse CTexturPool I     (Implementierung: TextureClasses.h)

                                                         CreateTexture();
                                                         ƒ   Erzeugt eine Textur inklusive vollständiger
                                                             Mipmap-Kette mit transparentem Bereich
                                                             o Mipmap-Textur: verkleinerte Version einer
                                                               Textur (wird bei Texturfilterung eingesetzt)
                                                             o Transparenz: Bei aktiviertem Alpha-
                                                               Blending werden schwarze Bereiche
                                                               transparent dargestellt

                                                         CreateNonTransparentTexture();
                                                         ƒ    Erzeugt eine Textur inklusive vollständiger
                                                              Mipmap-Kette ohne transparenten Bereich

ƒ Erzeugung einer Textur in 3 Schritten:
                                                         CreateTexture_WithoutMitmps &
1. Ein Texturklassen-Objekt erzeugen                     CreateNonTransparentTexture_without
    CursorTextur = new CTexturPool                       Mitmaps();
                                                         ƒ    Erzeugen Texturenohne Mitmap-Ketten
2. Speicherpfad der Textur übergeben
    sprintf(CursorTextur->Speicherpfad, „Cursor.bmp“);

3. Textur erzeugen
    CursorTextur->CreateTextur();
Texturen - Generierung
ƒ    Die DirectX-Wunderfunktion D3DXCreateTextureFromFileEx()
      o Funktionsprototyp:                Parameter 3,4,5: Die Konstante D3DX_DEFAULT für
                                          Breite, Höhe & Anzahl der Mipmaps
                                          ƒ Erzeugt eine Textur inklusive kompletter
                                            Mipmap-Kette
                                          ƒ Die Maße der Textur entsprechen dabei denjenigen
                                            der Quelldatei (also Original-Bitmap)

                                          Parameter 6: 0
                                          ƒ Erzeugt eine normale Textur-Surface
                                          ƒ Möglichkeit des Shadowmapping: Textur-Surface
                                            wird als Render Target eingesetzt

                                          Parameter 7: Die Konstante D3DFMT_UNKNOWN
                                          ƒ Übernimmt das Original-Format der
                                            Bitmap-Quelldatei

                                          Parameter 8: Die Konstante D3DPOOL_MANAGED
                                          ƒ DirectX-Graphics übernimmt die Verwaltungsarbeiten

                                          Parameter 9-14: Filter für die Textur- &
                                          Mipmap-Erstellung
      o Beispiel:
                                          ƒ   D3DX_FILTER_TRIANGLE: wird verwendet, wenn
                                              Textur- & Quellbitmap-Maße identisch sein sollen
                                          ƒ   D3DX_FILTER_BOX: wird verwendet, wenn die
                                              Textur-Maße nur die Hälfte der Originalmaße
                                              (Bitmap) betragen sollen

                                          Parameter 15: Die Konstante D3DCOLOR_XRGB
                                          ƒ definiert Farbe (hier schwarz) & Transparenz bei
                                            eingeschaltetem Alpha-Blending

                                          Parameter 18: &pTexture
                                          ƒ übergint Adresse des Zeigers pTexture, der auf die
                                            Textur-Surface zeigt
Texturen - Generierung
ƒ    Die Textur-Helperklasse CTexturPool II   (Implementierung: TextureClasses.h)

                                               Breit schaut die Klasse
                                               einfach besser aus ...
Texturen - Generierung
ƒ    Die Texturklasse CTexturPoolEx I     (Implementierung: TextureClasses.h).

      o Mit Hilfe dieser Klasse lassen sich mehrere Texturen in einem
        Schritt erzeugen.

      o Ausgangssituation: Für ein 3D-Objekt sollen drei verschiedene
        Texturen unterschiedlichen Detailgrads verwendet werden:
          > SternenkreuzerTextur1M1.bmp
          > SternenkreuzerTextur1M3.bmp
          > SternenkreuzerTextur1M3.bmp

      o Um nun alle 3 Texturen in einem Schritt zu erzeugen ...
          > ... muss lediglich der Texturstammname (hier also SternenkreuzerTextur1)
            an ein Objekt der Klasse CTexturPoolEx übergeben ...
          > ... & anschließend mit der so erzeugten Instanz die Methode
            InitTextures() aufgerufen werden:
Texturen - Generierung
ƒ    Die Texturklasse CTexturPoolEx II   (Implementierung: TextureClasses.h)
Texturen - Koordinaten
ƒ    Texturkoordinaten

                             ƒ Als Texturkoordinaten werden die
                               Parameter tu & tv verwendet
                                o Koordinaten 0/0 = linke obere Ecke
                                  des als Textur verwendeten Bitmaps
                                o Koordinaten 1/1 = rechte untere Ecke
                                  des als Textur verwendeten Bitmaps

                             ƒ Um also ein Bitmap vollständig als Textur
                               auf ein Objekt zu mappen, müssen
                               Texturkoordinaten in einem Bereich
                               von 0 bis 1 verwendet werden

                             ƒ Texture Wrapping
                               (mehrfaches mappen von Polygonen):
                                o Analog funktioniert dies bei doppelter
                                  Texturierung eines Objektes – hier müssen
                                  dann Texturkoordinaten >1 (bzw.
Texturen – weitere Vertexformate
ƒ    COLORREDVERTEX: Bereits beleuchtete Vertices mit Texturkoordinaten
      o Wird verwendet, wenn DirectX Graphics das darzustellende Objekt zwar
        transformieren aber nicht beleuchten soll

                                 Parameter tu & tv:
                                 is klar -> Texturkoordinaten
                                 Konstante D3DFVF_TEX1:
                                 Hier soll nur ein einzelner Satz von
                                 Texturkoordinaten verwendet werden

ƒ    SCREENVERTEX: Sowohl bereits transformierte als auch beleuchtete
     Vertices mit Texturkoordinaten
      o Wird verwendet, wenn DirectX Graphics das darzustellende Objekt weder
        transformieren noch beleuchten soll
                                                         Konstante D3DFVF_XYZRHW:
                                                         Die Vertices wurden bereits transformiert
                                                         (was der 4dimensionale Vektor D3DXVECTOR4
                                                         ebenfalls verdeutlicht)
                                                         • XY: enthalten die x- & y-Koordinaten des Vertex
                                                           (da der Vertex bereits transformiert wurde,
                                                           entsprechen diese den Bildschirmkoordinaten)
                                                         • Z: Tiefenwert (s. z-Buffer: Wertebereich von 0 bis 1)
                                                         • RHW-Wert: die „reziproke w-Komponente“ (s. Tag 3!);
                                                           wird für Nebelberechnung & perspektivisch korrektes
                                                           Texture-Mapping verwendet)
Texturen – texturierte Rechtecke (Quads) I
ƒ    Quads werden für die Darstellung von 2D-Objekten verwendet.
      o Wie Partikel, Feuer, Explosionen, Wolken, Cursor, Displayelemente etc.
        .
ƒ    Einen Quad rendern mit DrawPrimitive():
       o Zu diesem Zweck wird ein aus 2 Dreiecken bestehender Triangle
         Strip verwendet.
           > alternativ wäre auch eine Triangle List möglich – jedoch müssten in diesem Fall
             6 statt 4 Vertices definiert werden; Grund: 2 Dreiecke = 6 Vertices.

       o Beim Funktionsaufruf muss die Anzahl der Dreiecke im Triangle
         Strip mit übergeben werden.
           > Attentione: Ein Triangle Strip beinhaltet immer 2 zusätzliche Vertices;
             Grund: 2 Dreiecke = 4 Vertices, 4 Dreiecke = 6 Vertices usw.
Texturen – texturierte Rechtecke (Quads) II
ƒ    Cullmode definieren
      o Der Cullmode legt fest, welche Dreiecke (z.B. bei einem Triangle
        Strip) beim Rendern auszusondern (zu cullen) sind
         > Grund: Bei der Definition von Dreiecken müssen deren Eckpunkte entweder im
           Uhrzeigersinn oder entgegen dem Uhrzeigersinn angegeben werden
         > Beim Triangle Strip gibt man die Eckpunkte entgegen dem Uhrzeigersinn an
         > Dies muss DirectX-Graphics mitgeteilt werden:

         > Hierbei wird zwischen den Cullmodi CW (clockwise) & CCW (counter-clockwise)
           unterschieden
         > Diese Modi definieren jeweils, welche Dreiecke auszusondern sind
           (hier: diejenigen, deren Eckpunkte im Uhrzeigersinn angegeben wurden)

      o Vorteil des Verfahrens: Performancegewinn
         > Beispiel: Wären die vorderen Dreiecksflächen eines Objekte im Uhrzeigersinn
           definiert, würden die die hinteren Dreiecksflächen aus Betrachtersicht entgegen
           dem Uhrzeigersinn definiert erscheinen
         > In diesem Fall würde man den Cullmode CCW wählen
         > Effekt: Alle hinteren Dreiecksflächen würden nicht gerendert werden (auch
           backface culling genannt) Æ Performancegewinn
Texturen – texturierte Rechtecke (Quads) III
ƒ    Vertexdaten für ein beleuchtetes Quad definieren
Texturen – texturierte Rechtecke (Quads) IV
ƒ    Vertexdaten für ein beleuchtetes & transformiertes Quad definieren
Texturen – texturierte Rechtecke (Quads) V
ƒ    Zu verwendende Textur festlegen & Quad rendern
      1. Textur festlegen
         DirectX-Graphics benötigt zur Verwendung einer Textur einen Zeiger auf das
         entsprechende Textur-Objekt. Dies geschieht mit Hilfe der Funktion SetTexture();
      o Beispiel:
      o Erläuterung
           > Cursor-Texture            Instanz der Textur-Helperklasse CTexturPool
           > pTexture                  Zeiger auf das eigentliche Texturobjekt
           > Parameter 0               Texture Stage Number (=Nummer der Verwendeten Textur-Stufe)
                –   DirectX-Graphics kann bis zu acht Texturen gleichzeitig verarbeiten (s. Tag 12: Multitexturing)
                –   0 entspricht also der „nullten Textur-Stufe“ (zur Verwendung von lediglich 1 Textur)

      2. Transformations- & Beleuchtungspipeline mit SetStreamSource()
         Nun werden die Vertexdaten des Quads durch die Transformations- &
         Beleuchtungspipeline gejagt

      3. Vertex-Shader festlegen mit SetFVF()

      4. Rendern mit DrawPrimitive()

      5. Die verwendete Textur wieder aus der Texturstufe entfernen mit SetTexture()
Texturen – Demoprogramm
Workshop Gunia
ƒ Überblick über die einzubindenden Programmmodule, Klassen, Funktionen

ƒ   Einbinden der Module in Space3D.h
                                         BuildIdentityMatrices()
                                         Initialisiert bei Programmstart die global
                                         verwendeten Matrizen als Einheitsmatrizen
                                         (s. Folgechart)

                                           Zusätzlich DirectInput-Bibliothek
                                           fürgegen CursorSpass mit einbinden!
Texturen – Demoprogramm
Workshop Gunia

ƒ   BuildIdentityMatrices():

     o Initialisiert global verwendete Matrizen als Einheitsmatrizen

     o Attentione: Wird von der Game-Initialisierungs-Routine aufgerufen
         > Deshalb: Funktionsprototyp als External in GameRoutines.h einbinden!
Texturen – Demoprogramm
Workshop Gunia
ƒ Die Klasse C3DScenario

                           ƒ Konstruktor: initialisiert alle Elemente des
                             3DSecenarios
                           ƒ Destruktor: na?
                           ƒ New_Scene(): Wird zum Rendern verwendet & muss
                             zur Darstellung der Scene durch Show_3D-Scenario
                             aufgerufen werden
                           ƒ Danach werden nacheinander Sternenfeld, Cursor
                             & Bildschirmschablone gerendert
Texturen – Demoprogramm
Workshop Gunia
ƒ Die Klasse CSchablone
                          ƒ CSchablone definiert ein Screen Quad
                            (Bildschirmschablone)

                          ƒ Im einfachsten Fall:
                            Ein simples beleuchtetes & transformiertes
                            Quad von der Größe der Bildschirmauflösung

                          ƒ Zweck: Einbau von Cockpit- od. anderen
                            Anzeigeelementen
Texturen – Demoprogramm
Workshop Gunia
ƒ Die Klasse CCursor

 Also die Klasse passt hier nur wirklich nicht mehr auf eine Folie – deshalb:
 Siehe SimpleCursorClass.h

 ƒ   CCursor ist für Initialisierung, Darstellung & Zerstörung des
     Cursor-Quads zuständig
      o Cursor-Quad: Ein beleuchtetes Quad, dass für die Cursordarstellung verwendet wird

 ƒ   Attentione: Der Cursor muss immer an der aktuellen Mausposition
     gerendert werden
      o Deshalb muss vor dem Rendern eine Welttransformation durchgeführt werden:
Texturen – Demoprogramm
Workshop Gunia
ƒ Die Klasse CStarfield

   ƒ Erzeugt eine Point List & gibt diese
     auf dem Bildschirm aus:
Simulationen
Workshop Gunia:

ƒ   „Nach eigenem Dafürhalten“
Sie können auch lesen