Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit...

34
Elemente der 3D- Grafikprogrammierung

Transcript of Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit...

Page 1: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

Elemente der 3D-Grafikprogrammierung

Page 2: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

Render - Pipeline• Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende

Grafikdaten, Primitive, in Pixel auf dem Bildschirm transformieren• Prozess aus mehreren Verarbeitungsschritten:• Fixed Function Pipeline:1.) Vorverarbeitung:- Tesselieren: komplexe Geometrieelemente in einfache

Geometrieelemente (Grafikprimitive) zerlegen - Um weitere Operationen zu vereinheitlichen- Z.B. Meshes immer aus Dreiecken2.) Tranformation und Beleuchtung- Geometrische Umrechnung der Eingangsdaten wird durchgeführt- Teilschritte:

- World – Transformation- View-Transformation- Perspektivische Transformation

Page 3: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

3.) Clipping: Abschneiden von Teilen, die außerhalb des Blickfeldes liegen

- Backface Culling: Entfernen von Rückseiten- Beide Prozesse automatisch, aber Programmierer kann

durch Setzen von Render-States eingreifen -> Culling abschalten: auch Rückseiten der Objekte erzeugt 4.) Texturierung- Texturen bzw Bilder werden auf Grafikprimitive aufgebracht- entsprechend Lichtverhältnissen eingefärbt5.) Ergebnisse zusammenführen- Farbwerte der Pixel für Bildschirmausgabe berechnen- Anhand Tiefen-Information (Z-Buffer) wird entschieden,

welche Pixel im Vordergrund liegen- Übereinander liegende Pixel werden verschnitten

Page 4: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Fixed Function Pipeline: geeignet für feste Strukturen • Organische Strukturen wie Gesichter, Pflanzen, Wasser

mit Verformungen oder Farbenspiel -> Berechnung aller geometrischen und farblichen Übergänge im Anwendungsprogramm nötig, dann Übergabe an Grafikkarte -> dazu „programmierbare“ Render-Pipeline:

• Geometrische und farbliche Transformationen nah an der Hardware durchgeführt

• Vertexshader: zur geometrischen Transformation• Pixelshader: zur Texturierung• Shader: kleine Programme, die bei Bedarf in Grafikkarte

geladen werden um Vertex- oder Pixelberechnungen durchzuführen

• Vorrangig dann, wenn spezielle geometrische pder farbliche Effekte erzielt werden sollen

Page 5: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

7.2 Vertices und Vertexbuffer

• Interne Darstellung eines 3D-Modells: Datenstruktur, die performant gerendert werden kann

• maximale Geschwindigkeit in Render – Pipeline: am besten Arrays mit Aneinanderreihung von Geometriedaten, die als Ganzes in Grafikkarte geladen und mit einfachen Algorithmen verarbeitet werden können

• Verzicht auf Kopien -> es darf nur einen Originaldatensatz geben, auf dem dann sowohl Anwendungsprogramm als auch Grafiksystem arbeiten kann

• In DirectX: Vertexbuffer sind auf Verwendung an Schnittstelle zwischen Grafiksystem und Anwendungsprogramm hin optimiert

Page 6: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Vertexbuffer:– reservierter Speicherbereich– Informationen über Knoten (Vertices) eines 3D

Modells sind hier abgelegt– Programm kann mehrere Vertexbuffer anlegen und

unabhängig voneinander verwenden– in Vertexbuffer steht Aneinanderreihung von Vertices

• Vertices:– Eckpunkte oder Knoten eines dreidimensionalen

Mesh– Hat Positionsdaten und ggf. weitere Daten über den

Knoten wie Farbwerte, Texturkoordinaten• Möglichst performant: schlichte, starre Struktur

für Vertex -> einfachste Möglichkeit: immer gleiche Struktur, kann auch enorme Speichervergeudung bedeuten

• Daher flexibles Vertex - Format

Page 7: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

7.2.1 Das Flexible Vertex-Format

• Flexibles Vertex-Format (FVF): zur Speicherung von Vertices in Vertexbuffer verwendetes Datenformat wird festgelegt

• Für jedes Attribut bestimmter Datentyp • Position des Vertex durch Vektor

D3DXVECTOR3 beschrieben, • Farbe durch RGBA-Wert D3DCOLOR• Zusätzlich ist verbindliche Reihenfolge der

Attribute festgelegt -> Gesamtstruktur mit allen Feldern ist festgelegt, nicht verwendete Felder werden gelöscht

Page 8: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Vertexformat mit Positionsangabe, Normale, diffusem Farbwert:# define MEINVERTEXFORMAT (D3DFVF_XYZ I D3DFVF_NORMAL I

D3DFVF_DIFFUSE)struct meinvertex{D3DXVECTOR3 pos;D3DXVECTOR3 normale;D3DCOLOR color;};- Symbolische Konstante MEINVERTEXFORMAT verwendet man später

zur Reservierung von Vertexbuffer- Datenstruktur meinvertex verwendet als Overlay, wenn man von

Vertexbuffer schreiben oder lesen will- Deklaration des Vertexformats -> dieses wird später mit Funktion

SetFVF dem Device bekannt gegeben- Bei Deklaration von MEINVERTEXFORMAT kommt es nicht auf die

Reihenfolge einzelner Flags an- die Reihenfolge der Felder in der Datenstruktur meinvertex muss

sich jedoch streng an Reihenfolge der Attribute in der Tabelle orientieren

-> bei abweichender Reihenfolge erhält man später falsche Werte durch unpassendes Overlay

Page 9: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Umfassendere Methode zur Definition von Vertexformaten:

• Array mit Feldbeschreibungen anlegen D3DVERTEXELEMENT9

• Diesen an Funktion CreateVertexDeclaration übergeben um Vertexdeklaration zu erzeugen

• SetVertexDeclaration setzt Deklaration im Device-> Feldbeschreibungen D3DVERTEXELEMENT9

entsprechen in etwa symbolischen Konstanten -> Aufruf von CreateVertexDeclaration entspricht

Montage der symbolischen Konstanten durch Oder – Verbindung

-> SetVertexDeclaration entspricht Funktion SetFVF-> Vertexdeklaration verwendet man im Zusammenhang

mit Vertex- und Pixelshadern, wenn man selbst definierte Formate in der Renderpipeline verwenden will

Page 10: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

7.2.2 Verwendung von Vertexbuffern

• Vertexbuffern anlegen für ausgewähltes Vertexformat: Position, Normale, Farbe wird für Vertices benötigt

• Vertexbuffer bereitstellen über Memberfunktion CreateVertexBuffer aus Interface des DirectX-Device (IDirect3DDevice9)

HRESULT CreateVertexBuffer (UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9 **ppVertexBuffer, HANDLE pHandle)

-> Länge des Buffers in Bytes, Verwendungsart, flexibles Vertexformat, Memorypool, aus dem Speicher bereitgestellt wird, Pointer für erzeugten Buffer, reservierter Parameter, muss NULL sein

- Als Länge übergibt man Anzahl gewünschter Vertices x Größe der Datenstruktur für einen Vertex, etwa sizeof(meinvertex)

- FVF-Parameter sollte zu Vertexstruktur passende Bitmaske, etwa MEINVERTEXFORMAT enthalten

- im Parameter ppVertexBuffer erhalten wir Funktionsergebnis, d.h. Vertexbuffer

Page 11: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Konkretes Beispiel für Anforderung eines Buffers für 1000 Vertices

LPDIRECT3DVERTEXBUFFER9 vertexbuffer;device->CreateVertexBuffer (1000*sizeof(meinvertex), 0, MEINVERTEXFORMAT, D3DPOOL_MANAGED, &vertexbuffer, NULL);

- Device als Zeiger auf zuvor initialisiertes DirectX-Device- Zugriff auf Vertexbuffer über Interface

(LPDIRECT3DVERTEXBUFFER9)- Buffer kann in anderem Adressraum als dem unseres

Prozesses liegen und damit konkurrierend von anderen Prozessen verwendet werden

- Daher mit Funktion Lock für exklusiven Zugriff ganz oder teilweise sperren ->

Page 12: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

HRESULT Lock (UINT OffsetToLock, UINT SizeToLock, VOID **ppbData, DWORD Flags)

- Offset, ab dem gesperrt wird; Anzahl Bytes, die gesperrt werden; unspezifizierter Zeiger, der nach Aufruf auf den Buffer zeigt; Flags, die Art des gewünschten Locks bestimmen

- Bei erfolgreichem Aufruf erhalten wir in ppbData einen Zeiger auf reservierten Vertexbuffer

- konkret:

meinvertex *pv;vertexbuffer->Lock(0, 0, (void**)&pv, 0);- Wenn SizeToLock auf 0, wird der gesamte

Vertexbuffer gesperrt- Nach Funktionsaufruf finden wir in pv einen Zeiger auf

Vertexbuffer

Page 13: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

- Struktur meinvertex dient dann als Overlay zum Lesen/Schreiben in Vertexbuffer

for (int i=0; i<1000; i++){pv[i].pos = D3DXVECTOR3 (1, 1, 1);pv[i].normale = D3DXVECTOR3 (0, 1, 0);pv[i].color = D3DCOLOR_ARGB (255, 255, 255, 0);

}- Nach Zugriff Freigabe des Vertexbuffer für andere

Prozesse über Funktion Unlock:

HRESULT Unlock (VOID)- Freigabe über Aufruf von Release – Funktion:

vertexbuffer -> Release();

Page 14: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

7.3 Grafikprimitive7.3.1 Grafikprimitive in DirectX

• Grafikprimitive: einfache geometrische Struktur, aus der komplexere Strukturen aufgebaut werden können

• DirectX kennt Punkte, Linien, Dreiecke als Primitive -> alle räumlichen Modelle werden in Dreiecke aufgelöst >>Triangulierung<<

• Vertexbuffer kann Punktliste, Linienliste, Linienzug, Dreiecksliste, Dreiecksstreifen oder Dreiecksfächer enthalten

Page 15: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Punktliste: D3DPT_POINTLIST• Vertexbuffer enthält einzelne Punkte• Linienliste: D3DPT_LINELIST• Zwei aufeinanderfolgende Vertices werden als Anfangs- bzw

Endpunkt einer Linie aufgefasst• Anzahl der Vertices muss größer als 1 und gerade sein• Linienzüge: D3DPT_LINESTRIP• Können ebenfalls im Vertexbuffer modelliert werden• Punkte, Linien, Linienzüge eher selten, wichtiger sind Dreiecke -> flexibelste Form dazu Dreiecksliste D3DPT_TRIANGLELIST• Je drei aufeinanderfolgende Vertices bilden Dreieck• Dreiecke haben Vorder- und Rückseite -> nur Vorderseite wird

gerendert• Vorderseite: Windungsrichtung der im Vertexbuffer

aufeinanderfolgenden Eckpunkte verläuft im Uhrzeigersinn• Ausblenden der Rückseite: Backface - Culling

Page 16: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Culling stellt man mit Funktion SetRenderState umdevice->SetRenderState ( D3DRS_CULLMODE, D3DCULLL_CCW);

- Im obigen Beispiel wird Culling so eingestellt, dass Rückseiten, deren Windungsrichtung gegen Uhrzeigersinn (CCW) verläuft, nicht dargestellt werden

- Anzahl zur Beschreibung geometrischer Strukturen verwendete Vertices verringern:

- Dreiecksstreifen (D3DPT_TRIANGLESTRIP)- Erste drei Vertices bilden Dreick, jeder weitere Vertex bildet

mit seinen zwei Vorgängern das nächste Dreieck- Wenn Backface-Culling aktiviert: erstes Dreieck im

eingestellten Cullingmode gerendert, bei jedem weiteren Dreieck wird Wichtungsrichtung umgekehrt

- Dreiecksfächer (D3DPT_TRIANGLEFAN): drei erste Vertices ein Dreieck, jeder weitere Vertex mit Vorgänger und erstem Vertex

- Culling für alle Dreiecke gleich

Page 17: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

7.3.2 Rendern von Primitiven• Vertex-Format festlegen -> Vertexbuffer allokieren ->

Vertexbuffer mit Primitiven füllen -> rendern• Vertexbuffer als Eingabequelle der Render-Pipeline unseres

Devices festlegen: mit Funktion SetStreamSourceHRESULT SetStreamSource (UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride)

- Nummer des Streams, Vertexbuffer als Quelle, Offset zum Startpunkt im Vertexbuffer, Größe des Datensatzes für einen Vertex in Bytes

- StreamNumber ist logische Nummer -> mehrere Vertexbuffer als Streamsource festlegen, sofern man jedes Mal eine andere Nummer wählt

- Beispiel:device->SetStreamSource (0, vertexbuffer, 0, sizeof(meinvertex));

Page 18: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

- Device mitteilen, welches Vertexformat man im Vertexbuffer verwendet:HRESULT SetFVF (DWORD FVF)-> flexibles Vertex – Format- Als Parameter definiertes Vertexformat übergeben - Beispiel:device-> SetFVF(MEINVERTEXFORMAT);

- Funktion DrawPrimitive rendert VertexbufferHRESULT DrawPrimitive (D3DPRIMITIVETYPE PrimitiveType,

UINT StartVertex, UINT PrimitiveCount)- Art der Primitive, Startindex im Vertexbuffer, Anzahl der zu rendernden

Primitiven

- idR kompletten Vertexbuffer rendern und Startindex auf 0 setzen, aber auch andere Startpunkte sind möglich

- Beispiel: Ab dem 10ten Vertex im Buffer 100 Dreiecke rendern:device->DrawPrimitive (D3DPT_TRIANGLELIST, 10, 100);

Page 19: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

7.3.3 Beispiele mit Dreiecken und Linien

1. Schritt: Festlegen des Vertexformats- Für jeden Vertex Position und Farbwert im Vertexbuffer speichern# define MEINVERTEXFORMAT (D3DFVF_XYZ I

D3DFVF_DIFFUSE)struct meinvertex{D3DXVECTOR3 pos;D3DCOLOR color;};- Liste von Dreiecken mit Umrandung erstellen- Dazu Dreiecksliste und Linienliste rendern- Voraussetzung: Device (LPDIRECT3DDEVICE9) wurde erfolgreich

initialisiert- Funktionalität zum Erstellen und rendern konzipieren wir als eine in

sich geschlossene Klasse (trianglelist), in die von außen nur ein Zeiger auf Device eingeht

Page 20: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

class trianglelist{ private:LPDIRECT3DDEVICE9 device;LPDIRECT3DVERTEXBUFFER9 dreieckbuffer;LPDIRECT3DVERTEXBUFFER9 linienbuffer;public: trianglelist();~trianglelist();void create(LPDIRECT3DDEVICE9 dev);void setup();void render();};- Zwei Vertexbuffer: der erste (dreieckbuffer) soll

Eckpunkte der Dreiecke, der zweite (linienbuffer) Eckpunkte der Umrandung aufnehmen

- Fehlende Arbeitsschritte werden in öffentlichen Methoden create, setup, render abgehandelt

Page 21: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Konstruktor und Destruktor der Klasse:trianglelist::trianglelist(){ dreieckbuffer = 0;linienbuffer = 0;}trianglelist::~trianglelist(){ if (dreieckbuffer)dreieckbuffer -> Release();if (linienbuffer)linienbuffer-> Release();}- Konstruktor initialisiert Bufferzeiger- Destruktor gibt Buffer frei

Page 22: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

2. Schritt: Allokieren des Vertexbuffers- Zwei Vertexbuffer: erste soll 2 Dreiecke = 6 Vertices

aufnehmen, zweite soll 6 Randlinien = 12 Vertices aufnehmen

- Daraus ergibt sich erforderlicher Speicherplatz

void trianglelist::create (LPDIRECT3DDEVICE9 dev)

{ device = dev;device -> CreateVertexBuffer (6*sizeof(meinvertex),0, MEINVERTEXFORMAT, D3DPOOL_MANAGED, &dreieckbuffer, NULL);

device->CreateVertexBuffer (12*sizeof(meinvertex),0, MEINVERTEXFORMAT, D3DPOOL_MANAGED, &linienbuffer, NULL);

}- System legt beide Buffer an, kein direkter Zugriff -> bei

Zugriff auf Inhalt zuvor Funktion Lock aufrufen

Page 23: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

3. Schritt: Befüllen des Vertexbuffers- Zunächst beide Vertexbuffer für Zugriff durch unser Programm

reservieren

void trianglelist::setup(){meinvertex *dv, *lv;int i;dreieckbuffer -> Lock (0, 0, (void**)&dv, 0);linienbuffer ->Lock(0,0, (void**)&lv, 0);/* Zeiger auf jeweilige Bufferinhalte werden in Variablen dv und lv

übertragen */

dv[o].pos = D3DXVECTOR3 (0, 0, 0);dv[1].pos = D3DXVECTOR3 (2, 1, 0);dv[2].pos = D3DXVECTOR3 (2, 0, 0); // … bis dv[5]

/* Koordinatenwerte für sechs Eckpunkte der beiden Dreiecke eintragen dv[0] bis dv[5] in Dreiecks- bzw Linienpuffer */

Page 24: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

dv[0].color = D3DCOLOR_ARGB (255, 80, 80, 80);dv[1].color = D3DCOLOR_ARGB (255, 160, 160, 160);// .. Bis dv[5]/* für Eckpunkte der Dreiecke unterschiedliche Farbwerte */

lv[0].pos = dv[0].pos; // 12 Eckpunkte der 6 Randlinienlv[1].pos = dv[1].pos;lv[2].pos = dv[1].pos;lv[3].pos = dv[2].pos;lv[4].pos = dv[2].pos;lv[5].pos = dv[0].pos;lv[6].pos = dv[3].pos;lv[7].pos = dv[4].pos;lv[8].pos = dv[4].pos;lv[9].pos = dv[5].pos;lv[10].pos = dv[5].pos;lv[11].pos = dv[3].pos;

Page 25: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

for (i = 0; i<12; i++)lv[i].color=D3DCOLOR_ARGB(255, 0, 0, 0);

// Eckpunkte der Randlinien schwarz

dreieckbuffer->Unlock();linienbuffer->Unlock();} // Vertexbuffer freigeben

- Beide Buffer sind jetzt bereit zum rendern

Page 26: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

4. Schritt: Rendern der Primitiven im Vertexbuffer- Rendern besteht aus wenigen Funktionsaufrufen- Zunächst mit Funktion SetFVF richtiges Vertexformat setzen- Danach für jeden Buffer Funktionen SetStreamSource und

DrawPrimitive aufrufenvoid trianglelist::render(){device->SetRenderState (D3DRS_AMBIENT, 0xffffff);// Beleuchtung: Ambient Licht einschaltendevice->SetRenderState (D3DRS_AMBIENTMATERIALSOURCE,

D3DMCS_COLOR1);// Farbwerte aus diffusen Farbkomponente des Vertex verwendendevice ->SetFVF (MEINVERTEXFORMAT);device->SetStreamSource (0, dreieckbuffer, 0

sizeof(meinvertex));device->DrawPrimitive (D3DPT_TRIANGLELIST, 0, 2);devide->SetStreamSource(0, linienbuffer, 0

sizeof(meinvertex));device->DrawPrimitive(D3DPT_LINELIST, 0, 6);}- Aufruf der Methoden create und setup sowie regelmäßiges Rendern ergibt

gewünschtes Bild

Page 27: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Unterschiedliche Farbtöne an den Ecken der Dreiecke führen zu Farbverläufen

• Ecken dv[2] und dv[3] haben gleiche Position, unterscheiden sich aber in Farbe

-> da Vertices zu unterschiedlichen Dreiecken gehören, hätten wir auf keines von beiden verzichten können

- Wenn alle Dreiecke in der gleichen Farbe und ohne Farbverläufe dargestellt werden sollen, wäre Farbinfo für jeden Vertex Speicherplatzvergeudung

- Stattdessen Material in gewünschter Farbe anlegen:

D3DMATERIAL9 material;ZeroMemory (&material, sizeof (material));Material.Ambient = D3DXCOLOR (255, 255, 0, 0);

- Material in render-Funktion auswählen und durch SetRenderState festlegen, dass Material verwendet werden soll:

device->SetMaterial (&material);device->SetRenderState (D3DRS_AMBIENTMATERIALSOURCE,

D3DMCS_MATERIAL);

Page 28: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

7.3.4 Beispiel mit Punktlisten (Partikelsysteme)- Dreiecke oder Linien als am häufigsten genutzte Primitive- Punktlisten zur Realisation von Partikelsystemen = 3-

dimensionale Punktwolken um etwa Rauch oder Schnee zu implementieren

- verwenden gleiches Vertexformat wie zuvor

define MEINVERTEXFORMAT (D3DFVF_XYZ I D3DFVF_DIFFUSE)

struct meinvertex{D3DXVECTOR3 pos;D3DCOLOR color;};

Page 29: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Jeder Punkt /Partikel hat eigene Position, kann eigenständig bewegt werden, hat eigene Farbe

• Beispiel: Kugeloberfläche als Wolke aus einzelnen Punkten zusammensetzen -> größer werden lassen - > zerstäuben

class partikelsystem{private:LPDIRECT3DDEVICE9 device;LPDIRECT3DVERTEXBUFFER9 partikelbuffer;int anzahl;float radius;public: partikelsystem ();~partikelsystem();void create( LPDIRECT3DDEVICE9 dev, int anz);void setup();void blowup();void render ();void lookatme (…}};

Page 30: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Create – Methode:void partikelsystem::create(LPDIRECT3DDEVICE9 dev, int anz)

{device = dev;anzahl = anz;device ->CreateVertexBuffer (anzahl*sizeof(meinvertex), 0, MEINVERTEXFORMAT, D3DPOOL_MANAGED, &partikelbuffer, NULL);

}- Anwender kann wählen, wie viele Partikel er haben will ->entsprechend wird Vertexbuffer bereit gestellt

Page 31: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Setup – Funktion: Anfangspositionen einzelner Partikel in Buffer eingetragenvoid partikelsystem::setup(){int i;meinvertex *pv;srand (123);radius = 0.1f;partikelbuffer->Lock (0, 0, (void**)&pv, 0);for (i=0;i < anzahl; i++){pv[i].pos.x = ((float)rand())/RAND_MAX – 0.5f; // für jedes Partikel durch

Zufalls-pv[i].pos.y = ((float)rand())/RAND_MAX – 0.5f; // Zufallskoordinaten ein// Punkt in Würfelpv[i].pos.z = ((float)rand())/RAND_MAX – 0.5f; // um den Ursprung bestimmtD3DXVec3Normalize (&pv[i].pos, &pv[i].pos); // Normalisierung des Punktespv[i].color = D3DCOLOR_ARGB (255, (int) (128*(pv[i].pos.x +1)),(int) (128*(pv[i].pos.y +1)),(int) (128*(pv[i].pos.z +1))); // Auswahl eines Farbwertes für Partikelpv[i].pos = radius * pv[i].pos; // Sphäre auf Anfangsgröße verkleinern}partikelbuffer -> Unlock();}

Page 32: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Funktion blowup: Aufblasen der Sphäre, bei jedem Aufruf um 10% bis Maximalwert des Radius 10

• Radius 10 erreicht -> Funktion setup setzt Sphäre in Ausgangszustand

void partikelsystem::blowup(){int i;meinvertex *pv;radius *= 1.1f;if (radius <10){partikelbuffer ->Lock (0, 0, (void**)&pv, 0);for (i = 0; i < anzahl; i++)pv[i].pos = 1.1f * pv[i].pos;partikelbuffer->Unlock();}elsesetup ();}

Page 33: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Render – Funktion nimmt Beleuchtungseinstellungen vor und bringt Vertexbuffer zur Darstellung

void partikelsystem::render (){device->SetRenderState (D3DRS_AMBIENT, 0xffffff);

device->SetRenderState (D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);

device->SetFVF (MEINVERTEXFORMAT);device ->SetStreamSource (0, partikelbuffer, 0, sizeof (meinvertex));

device -> DrawPrimitive (D3DPT_POINTLIST, 0, anzahl);

}- Effekt des Zerbröselns: die dem Auge näher liegenden

Partikel größer und weiter entfernt liegende Partikel kleiner -> Pointscaling D3DRS_POINTSCALEENABLE aktivieren

Page 34: Elemente der 3D- Grafikprogrammierung. Render - Pipeline Aufgabe eines Grafikpakets wie DirectX: mit Grafikkarte eingehende Grafikdaten, Primitive, in.

• Skalierung für Partikel einschalten und Konstanten A, B und C setzen:inline DWORD FtoDW (FLOAT f){return *((DWORD*) &f);}void partikelsystem::render (){ device ->SetRenderState (D3DRS_POINTSCALEENABLE, TRUE);device ->SetRenderState (D3DRS_POINTSIZE, FtoDW(0.1f));device->SetRenderState (D3DRS_POINTSCALE_A, FtoDW (0.0f));device->SetRenderState (D3DRS_POINTSCALE_B, FtoDW (0.0f));device ->SetRenderState (D3DRS_POINTSCALE_C, FtoDW (1.00f));device ->SetRenderState (D3DRS_AMBIENT, 0xffffff);device ->SetRenderState (D3DRS_AMBIENTMATERIALSOURCE,

D3DMCS_COLOR1);device ->SetFVF (MEINVERTEXFORMAT);device ->SetStreamSource (0, partikelbuffer, 0, sizeof

(meinvertex)); device -> DrawPrimitive (D3DPT_POINTLIST, 0, anzahl);}- Beim Setzen der Konstanten - Hilfsfunktion FtoDW: Funktion SetRenderState

akzeptiert nur DWORD, aber eine Gleitkommazahl übergeben -> kopiert float in Speicherbereich, der für DWORD vorgesehen ist