3D-Grafik mit der TriBase-Engine

Download Report

Transcript 3D-Grafik mit der TriBase-Engine

3D-Grafik mit der
TriBase-Engine
Universität zu Köln
Softwaretechnologie II WS 11/12
Dozent: Prof. Dr. M. Thaller
Referentin: Nadya Steinert

Automatische Initialisierung von Direct3D

Statusänderungen minimieren

Texturverwaltung

Vertex- und Indexbuffer einfacher erstellen

D3DX-Effekte leichter verwalten
Die Klasse tbDirect3D

Dies ist eine Singleton-Klasse, von der nur eine Instanz erzeugt werden kann

Sie verkörpert die vorher benannten Funktionen

Die Funktion tbConfigDialog sammelt Informationen über die Direct3DEinstellungen:
Adapter, Videomodi, Oberflächenformate usw.
Die Methode tbDirect3D:: Init initialisiert Direct3D und erstellt das Fenster; ihr
werden die tbConfig-Struktur und Fenstertitel und -icon übergeben
Die Exit- Methode setzt alle Texturen zurück und löscht alle Direct3DSchnittstellen
Klassendeklaration- Variablen

m_bInitialized (BOOL) – am Anfang und nach Herunterfahren FALSE;








Variable verhindert mehrfaches Aufrufen der Init-Funktion
Zwei Zeiger für die Schnittstellen IDirect3D9 und IDirect3DDevice9
Die D3DCAPS9-Struktur des verwendeten Gerätes speichern
Eine HWND-Variable für das Fenster
m_bOwnWindow (BOOL) falls der Benutzer eigenes Fenster verwendet
Für Kapselung der Methoden SetRenderState, GetRenderState,
SetTextureStageState usw. braucht man Tabellen; DWOR- und float-Version
Ein Array vom Typ PDIRECT3DBASETEXTURE9 mit 8 Elementen
speichert die eingesetzten Texturen
m_vScreenSize (tbVector2) speichert die Größe des Bildpuffers in Pixeln
Klassendeklaration- Methoden




Init-Methode erwartet zuerst einen Zeiger auf tbConfig , erstellt ein Fenster
und initialisiert die IDirect3DDevice9-Schnittstelle; dann ein Fenstername, ein
HWND-Parameter für Benutzerfenster, ein HICON-Parameter
Kapselungsmethoden für die verschiedenen States die mit den DWORD –
und float- Tabellen arbeiten
Verschiedene Hilfsmethoden: IsInitialized, GetWindow, GetDirect3D usw.
Capture-Methode fragt den aktuellen Status der Geräteschnittstelle ab
Die Funktion tbDuConfigDialog


sie ruft den Konfigurationsdialog auf
Füllt die tbConfig-Struktur aus, die die gesamte Konfiguration
von TriBase-Engine beinhaltet
Die Init-Methode







Erzeugt das Anwendungsfenster
Eine IDirect3D9-Schnittstelle
Ruft CreateDevice auf, um eine IDirect3DDevice9-Schnittstelle
zu erhalten
Fragt die Gerätefähigkeiten( D3DCAPS9) ab
Speichert den aktuellen Status der Tabellen durch die CaptureMethode
Setzt Standard-Render und Sampler-States
Setzt m_bInitialized auf true



Speichern des aktuellen Status mit Capture()
Diese Methode geht alle Render-States, Sampler-States
usw. durch, deren Werte in Tabellen gespeichert sind,
fragt sie ab und speichert sie
Doppelte Statusänderungen werden verhindert indem
die Set-Methoden prüfen, ob der Status schon gesetzt
ist und wenn dass der Fall ist, wird sofort unterbrochen

// Wenn das Render-State schon gesetzt ist, direkt abbrechen

if(m_RS.adwRS[RS] == dwValue) return TB_OK;





Die Exit-Methode setzt alle Texturen, Index- und
Vertex-Buffer zurück, gibt die zwei Schnittstellen
frei(D3D und D3DDevice)
Methoden wie SetTextue() erhöhen den Zähler der ihr
übergebenen Schnittstelle und müssen unbedingt
zurückgesetzt werden, damit keine Speicherlecks
entstehn
Um auf die IDirect3DDevice9 zugreifen zu können, wird der
‚->‘-Operator überladen
PDIRECT3DDEVICE9 operetor ->{return m_pD3DDevice;}
D3D->DrawPrimitive() //direkt Methoden von IDirect3DDevice9 aufrufen
tbTextureManager





Sorgt dafür , dass keine Textur zwei Mal geladen wird
Alle geladenen Texturen werden in einer Liste mit
deren Dateinamen festgehalten
Wenn eine bereits geladene Textur wieder gefragt ist,
wird der Referenzzähler der Texturschnittstelle erhöht
Wenn der Referenzzähler null erreicht , wird die Textur
aus der Liste gelöscht
Texturen können aus verschiedenen Quellen geladen
werden: aus Speicher, einer Ressource oder aus
ZIP_Archiv
Klassendefinition von tbTextureManager


















Es gibt eine Liste, wo alle Texturen eingetragen werden
jeder Textureintrag wird in die Struktur tbTextureListEntry gespeichert
struct TRIBASE_API tbTextureListEntry
{
BOOLbExists;// Existiert diese Textur?
PDIRECT3DBASETEXTURE9pTexture;// Die Texturschnittstelle
characSourceFilename[256];// Quelldateiname
intiWidth;// Breite der Textur
intiDepth;// Tiefe der Textur
intiHeight;// Höhe der Textur
intiNumMIPLevels;// Anzahl der MIP-Mapping-Ebenen
D3DFORMATFormat;// Oberflächenformat der Textur
DWORDdwUsage;// Verwendungszweck
D3DPOOLPool;// Speicherklasse
DWORDdwFilter;// Bildfilter (beim Laden)
DWORDdwMIPFilter;// MIP-Map-Filter (beim Laden)
D3DCOLORColorKey;// Color-Key (beim Laden)
};
Klassendefinition -Variablen



Für die Texturen wird eine nicht verkette Liste
benutzt; der Zeiger m_pTextureList zeigt auf
eine tbTextureListEntry-Struktur; Speicher wird
dynamischreserviert
m_iListSize speichert die aktuelle Größe der
Texturliste
m_iNumTexture- Anzahl der geladene Texturen
Klassendefinition- Methoden






Init-Methode erwartet als Parameter die Ausgangsgröße der Texturliste und
reserviert genug Speisher
SetListSize verändert die Listengröße, wenn z.B. kein Platz für eine neue
Textur da ist
GetTextureIndex erwartet als Perameter eine Texturschnitstelle, sucht sie in der
Liste und liefert den Texturindex zurück
GetNewIndex liefert den nächsten freien Index in der Liste zurück, wenn kein
Platz -1; es wird nach dem ersten Listeneintrag gesucht bei dem m_bExist
FALSE ist
ReleaseTexture erwartet auch eine Texturschnittstelle, sucht die Textur und ruft
Release auf; wenn Referenzzähler null, Textur wird gelöscht
DeleteAllTexture geht die gesamte Liste durch und ruft für jede Textur so lange
Release auf bis Referenzzähler null
Klassendefinition -Methoden



AddTextureToList fügt eine Textur zur Liste hinzu, und erweitert diese, wenn
kein Platz mehr da ist
Load-Methoden für Standard-, Würfel- und Volumentexturen; Für jeden Typ
vier verschiedene Versionen, die erwarten Dateiname,
Speicheradresse,Ressourcenangabe, oder virtuelle Datei; Die ersten drei
Methoden erzeugen eine virtuelle Datei aus der Quelle und rufen die Vierte
Version auf; sie haben den gleichen Namen und verschiedene
Parameter(immer zuerst die Quellangabe)
Get-Methoden bekommen die Parameter einer Textur und durchsuchen die
Liste nach einer Übereinstimmung, passende Textur wird
zurückgeliefert(Referenzzähler wird erhöht); wenn Textur nicht vorhanden,
wird die entsprächende Load-Methode aufgerufen
tbVertexBuffer und tbIndexBuffer




Informationen zum Art des Puffers
Verwendungszweck: 0 ist Standard;
D3DUSAGE_DYNAMIC(dynamischer
Puffer);D3DUSAGE_WRITEONLY(kein Lesezugriff;
Speicherklasse: die vier Flags
D3DPOOL_DEFAULT,D3DPOOL_MANAGED,D3DPOOL
_SYSTEMMEM und D3DPOOL_SCRATCHstehen zur
Auswahl
Sperrmethode: 0, D3DLOCK_NOSYSLOCK,
D3DLOCK_DISCARD, D3DLOCK_NOOVERWRITE und
D3DLOCK_READONLY
Funktionsweise von den Buffern





Beim Initialisieren der Klasse gibt der Benutzer den
Verwendungszweck und die Speicherklasse an
Die Größe des Index- und Vertex-Buffer kann eventuell
angepasst werden
Beide Klassen fertigen sich intern eine Kopie des gesamten
Puffers an; mit SetVertex und SetIndex kann der Benutzer sie
verändern, wenn die Veränderung durchgeführt werden soll,
wird Update() aufgerufen
Der veränderte Speicherbereich wird gesperrt und die Daten aus
der internen Kopie werden in den Puffer kopiert
Bei D3DUSAGE_WRITEONLY wird nur aus der Kopie im
Systemspeicher gelesen und im Puffer nur geschrieben;
GetVertex() fragt Vertizes von der internen Kopie ab
Klassendefinition- Variablen(VertexBuffer)








m_pVertexBuffer vom Typ PDIRECT3SVERTEXBUFFER9
m_pBuffer der auf die interne Kopie zeigt, vom Typ void
DWORD m_dwSize speichert die Größe des Puffers in Bytes
DWORD m_dwVertexSize- die Größe eines einzelnen Vertex
DWORD m_dwMaxVertices – Anzahl der Vertizes im Puffer
DWORD dwFVF : der Vertexformat, beim Indexbuffer
m_IndexFormat (D3DFMT_INDEX16 oder D3DFMT_INDEX32)
DWORD m_dwUsage : Verwendungszweck des Puffers,
D3DUSAGE_WRIETEONLY ist immer gesetzt
D3DPOOL m_Pool: die Speicherklasse, in der sich der Vertex-Buffer
befindet
Klassendefinition- Variablen(VertexBuffer)


DWORD dwFirstVertex, dwLastVertex speichern die Nummern
des ersten und des letzten veränderten Vertex; SetVertex() setzt
die Variablen, um später den zu sperrenden Bereich zu ermitteln;
nach dem Sperren hat dwFirstVertex den höchst möglichen Wert
und dwLastVertex 0
DWORD m_dwCursor speichert die Nummer des nächsten
Vertex, der mit AddVertex() gesetzt wird
Klassendeklaration- Methoden




Init() generiert die IDirect3DVertexBuffer9-Schnittstelle und die interne
Kopie; die erste Version der Methode erwartet die Größe des Vertex-Buffers,
die Vertexgröße, den FVF-Bezeichner, Vervwendungszweck und
Speicherklasse
Die zweite Version erwartet einen bereits existierenden VertexBuffer(PDirect3DVertexBuffer9) und die Größe eines Vertex; aus diesem
wird die tbVertexBuffer- Instanz initialisiert; GetDesc() fragt die
Beschreibung des Vertex-Buffers ab; erste Funktion baut auf die zweite auf
Exit() gibt die Schnittstelle und die interne Speicherkopie frei; wird einmal
vom Destruktor und einmal am Anfang von Init() aufgerufen
SetVertex() erwartet die Nummer des zu setzenden Vertex(0 ist der erste) und
den Vertex selbst; der angegebene Vertex wird in die Speicherkopie
geschrieben und m_dwFirstVertex und m_dwLastVertex werden aktualisiert
Klassendeklaration- Methoden






SetVertices() setzt mehrere Vertizes; erster Parameter: Index des ersten zu
setzenden Vertex; dann Anzahl der Vertizes und schließlich Zeiger auf die
Vertizes
AddVertex() fügte dem Vertex-Buffer einen neuen Vertex hinzu und liefert
seinen Index zurück; die Nummer des nächsten Vertex ist im m_dwCursor
AddVertices() fügt gleich mehrere Vertizes hinzu, die im zweiten Parameter
angegeben sind; Erster Parameter- die Anzahl
SetCursor() setzt den Vertexcursor auf den durch den Parameter angegebenen
Wert; wenn Vertex-Buffer voll Cursor wird per Hand zurückgesetzt
GetVertex() liefert den durch den Index angegebenen Vertex
GetVertices() : erste Parameter gibt den Index des ersten abzufragenden Vertex
an; 2. Parameter: Anzahl der abzufragenden Vertizes; dritter: Zeiger auf den
Speicher Bereich, wo es hinkopiert werden soll
Klassendeklaration- Methoden


Update() schreibt die veränderte Vertizes in den Vertex-Buffer;
biem dynamischen Puffer Sperflag D3DLOCK_DISCARD;
m_dwFirstVertex und m_dwLastVertex werden zurückgesetzt
Verschiedene Inline- Methoden
tbEffect



Optionen zum zeichnen eines Objekts oder eins Materials werden in eine
Effekt-Datei gespeichert werden
Der Benutzer kann selbst festlegen Welche Techniken benutzt werden oder
überlässt das der Klasse
Ein globales Effekt-Pool ermöglicht es , das verschiedene Effekte ihre
Parameter teilen; wird in Init() erstellt
Klassendeklaration- Variablen




LPD3DXEFFECT m_pEffect : die Effekt-Schnittstelle
D3DXEFFECT_DESC m_Desc :die Effektbeschreibung
BOOL m_bStateSaved: TRUE , wenn beim Aufruf von Begin()
angegeben wurde, dass dewr aktuelle Status gespeichert werden
soll
BOOL m_bCaptureOnFinish: TRUE; WENN BEIM Beenden
des Effekts automatisch Capture() aufgerufen werden soll
Klassendeklaration - Methoden







5 Init-Methoden: Initialisierung aus einem String , der den gesamten Code enthält; aus
einer virtuellen Datei; einer echten Datei, einem Speicherbereich oder einer Ressource
Exit() löscht die Schnoittstellen und verringert die Referenzzähler der Texturen
SetTechnique: setzt eine Technik , die durch ihre Nummer angegeben wird; gibt man -1
an, sucht die Methode die erste gültige Technik aus
Begin() : erster BOOL-Parameter bestimmt, ob die Änderungen später rückgängig
gemacht werden sollen; der zweite BOOL-Parametergibt an, ob die internen Tabellen
der Render-States, Texturschicht-State usw. in der tbDirect3D-Klasse aktualisiert
werden sollen
Die beide Parameter werden in m_bStateSaved bzw. in m_bCaptureOnFinish
gespeichert;Rückgabewert von Begin() ist die Anzahl der benötigten Durchgänge für
den Effekt
End() beendet den Effekt
Pass() aktiviert den durch seine Nummer angegebenen durchgang
Ein Beispiel
















Die Wasseroberfläche wird in eine Gitter eingeteilt
Die Höhe jedes Vertex wird einmal pro Frame aktualisiert und hängt von der
abgelaufene Zeit und von x- un z-position ab
Wellen lassen sich durch Sinus-Funktionen simulieren
Globale Variablen und Strukturen: zwei Strukturen, eine für die Wasser-Vertizes und
eine für die SkyBox-Vertizes
// Globale Variablen
tbConfigg_Config;// Konfigurationsstruktur
PDIRECT3DTEXTURE9g_pWaterTexture = NULL;// Wassertextur
PDIRECT3DCUBETEXTURE9g_pEnvMap = NULL;// Umgebungstextur
tbEffect*g_pWaterEffect = NULL;// Wassereffekt
tbEffect*g_pSkyBoxEffect = NULL;// Sky-Box-Effekt
tbVertexBuffer*g_pWaterVB = NULL;// Wasser-Vertex-Buffer
tbIndexBuffer*g_pWaterIB = NULL;// Wasser-Index-Buffer
tbVertexBuffer*g_pSkyBoxVB = NULL;// Sky-Box-Vertex-Buffer
tbIndexBuffer*g_pSkyBoxIB = NULL;// Sky-Box-Index-Buffer
const intg_iResolution = 64;// Die Auflösung der Wasseroberfläche
floatg_fTime = 0.0f;// Globaler Zeitzähler
Programminitialisierung






Konfigurationsdialog wird aufgerufen und das Ergebnis wird in g_Config
gespeichert
Danach wird die tbDitrect3-Klasse initialisiert
Ein Texturemanagerobjekt wird erstellt um die beiden Texturen zu laden
InitWater() und InitSkyBox() werden als nächstes aufgerufen
Gitterprinzip: es wird ein Statischer IndexBuffer erstellt, der mir den zu dritt
gruppierten Indizes gefüllt wird; Die Methode GetVertexIndex(DWORD x,
DWORD y) findet den Index jedes Vertex indem sie die Reihe mit der Anzahl
Vertizes pro Reihe multipliziert und die Spalte dazu addiert
InitWater(): Vertex- und Index-Buffer werden erstellt; IndexBuffer wird gefüllt;
Texturen und Effekte werden aufgerufen
Die Animation



Einmal pro Frame geht das Programm alle Vertizes durch und
generiert sie neu, abhängig von position und Zeit; drei
Funktionen erwarten eine Positionsangabe und mit hilfe des
Zeitzählers liefern die Vertexposition(besonders Höhe),
Normalenvektor und Texturkoordinaten: PositionProc(tbVector3
v), NormalProc() und TextureProc()
UpdateWater() ruft diese Funktionen auf und füllt den
VertexBuffer
Die Render-Funktion: der Z-Buffer wird ausgeschaltet
Modelldateien








Sie sollen flexibel und offen für die Zukunft sein
Flexibilität durch Chunks: jeder Chunk hat ein Header(Beschreibung), gefolgt
von den Daten , die Nach Chunktyp interpretiert werden; die Größe der
Daten ist im Header angegeben, was erlaubt das unrelevante Chunks einfach
übersprungen werden
Struktur für ChunkHeader:
struct TRIBASE_API tbModelChunkHeader
{
tbModelChunkTypeChunkType;// Typ des Chunks
DWORDdwDataSize;// Größe der Daten des Chunks
ChunkType ist vom Typ enum; alle ChunkTypen beginnen mit TB_CT_

Vertexdaten-Chunk: TB_CT_MODEL_VERTICES

struct TRIBASE_API tbModelVerticesChunkHeader
{
DWORDdwFVF;// Vertexformat
DWORDdwVertexSize;// Größe eines einzelnen Vertex
DWORDdwNumVertices;// Anzahl der Vertizes
floatfBoundingSphereRadius;// Radius der umgebenden Kugel
tbVector3vBoundingBoxMin;// Minimumpunkt des umgebenden Quaders
tbVector3vBoundingBoxMax;// Maximumpunkt des umgebenden Quaders
Indexdaten-Chunk TB_CT_MODEL_INDICES













struct TRIBASE_API tbModelIndicesChunkHeader
{
D3DFORMATIndexFormat;// D3DFMT_INDEX16 oder D3DFMT_INDEX32
DWORDdwIndexSize;// Größe eines Index
DWORDdwNumIndices;// Anzahl der Indizes

Effekt-Chunk TB_CT_MODEL_EFFECTS
struct TRIBASE_API tbModelEffectHeader
{
characName[256];// Name des Effekts
BOOLbAlphaBlended;// Mit Alpha-Blending rendern?
D3DPRIMITIVETYPEPrimitiveType;// Typ der Primitiven
DWORDdwStartIndex;// Wo mit dem Rendern anfangen?
DWORDdwNumPrimitives;// Wie viele Primitiven rendern?
DWORDdwMinIndex;// Kleinster verwendeter Index
DWORDdwNumVertices;// Größter Index - Kleinster Index + 1
DWORDdwEffectCodeSize;// Größe des Effektquellcodes

};










To be continued…