[DX9] FVF und Vertexbuffer befüllen dynamisch

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
HLTO
Beiträge: 10
Registriert: 09.09.2002, 17:46
Kontaktdaten:

[DX9] FVF und Vertexbuffer befüllen dynamisch

Beitrag von HLTO »

Hallo zuammen,

wie immer um diese Jahreszeit finde ich wieder etwas Zeit meinem geliebten Hobby nachzugehen. Der Grafikprogrammierung :)

Und schon wieder stehe ich vor einer Frage (wie immer) auf dessen Lösung ich nicht selber komme. Ich mache gerade ein paar DX9 Turorials durch und es klappt auch toll mit dem anzeigen von ein paar Dreiecken. In den Tutorials wird immer eine Strukur(C/C++) definiert für die Vertex und Farbinformationen. Das ist auch alles gut zu verstehen und nachzuvollziehen. Aber das ist doch alles sehr statisch, oder nicht?

In diesen Beispielen müsste man während der Programmierung wissen was alles in diesen Strukturen gespeichert wird. Wie gehe ich vor wenn ich ein 3D-Model laden will? Ich kann während der Programmierung nicht wissen wie groß das 3D-Model sein wird.

Ich habe mir gedacht ich erstelle eine verlinkte Liste und befüllen diese mit den Vertex-Daten. Danach laufe ich im Programm durch diese Liste und vefüllen den Vertexbuffer. Würde so etwas gehen? Wie mache ich das am besten mit dem Vertexbuffer? Weil dem kann ich ja nicht einfach die verlinkte Liste übergeben. Was müsste ich machen damit der Vertexbuffer auch richtig befüllt wird.

Habt ihr ein paar Beispiele für mich? Ich hoffe ihr versteht mein Problem. :)

Naja, allen noch erholsame Feiertage ;)
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [DX9] FVF und Vertexbuffer befüllen dynamisch

Beitrag von dot »

Natürlich könnte man das alles voll dynamische machen. Die Frage ist aber, was genau das bringen soll. Ich würde eher dafür sorgen, dass die Modelle die benötigten Daten enthalten, anstatt ein hochkompliziertes System zu bauen, das fehlende Information am Ende auch nicht herzaubern kann...
HLTO
Beiträge: 10
Registriert: 09.09.2002, 17:46
Kontaktdaten:

Re: [DX9] FVF und Vertexbuffer befüllen dynamisch

Beitrag von HLTO »

Hmmm, mein Problem ist eigentlich was anderes. Ein Beispiel ->

in den Tutorials sieht man so etwas. Eine Struktur wird mit Vertex/Farb Daten gefüllt.

Code: Alles auswählen

UntransformedColouredVertex vertices[] = {
// Front Face (1-2-3-4)
{ -1.0f, 1.0f, -1.0f, 0xffff0000 },
{ 1.0f, 1.0f, -1.0f, 0xffffafaf },
{ -1.0f, -1.0f, -1.0f, 0xffffafaf },
{ 1.0f, -1.0f, -1.0f, 0xffff0000 },

// Right Face (2-6-4-8)
{ 1.0f, 1.0f, -1.0f, 0xff00ff00 },
{ 1.0f, 1.0f, 1.0f, 0xffafffaf },
{ 1.0f, -1.0f, -1.0f, 0xffafffaf },
{ 1.0f, -1.0f, 1.0f, 0xff00ff00 },
... usw....
};
Aber in diesem Fall werden die Daten Hardgecodet. Wie sieht so etwas aus wenn ich die Daten aus einem Model laden will?
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [DX9] FVF und Vertexbuffer befüllen dynamisch

Beitrag von dot »

Naja, dann liest man die Daten eben aus einer Datei!? Wo genau liegt dabei das Problem?
HLTO
Beiträge: 10
Registriert: 09.09.2002, 17:46
Kontaktdaten:

Re: [DX9] FVF und Vertexbuffer befüllen dynamisch

Beitrag von HLTO »

hmmm, ich meine so was

Code: Alles auswählen

v_buffer->Lock(0, 0, (void**)&pVoid, 0);    
memcpy(pVoid, vertices, sizeof(vertices));
der Funktion memcpy übergebe ich im zweiten Parameter die Struktur vertices.

die so aussieht

Code: Alles auswählen

struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw;    // from the D3DFVF_XYZRHW flag
    DWORD color;    // from the D3DFVF_DIFFUSE flag
}

CUSTOMVERTEX vertices[] =
{
    {320.0f, 50.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255),},
    {520.0f, 400.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0),},
    {120.0f, 400.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0),},
};
Was ist aber wenn die Struktur eine verlinkte Liste ist. In etwa so->

Code: Alles auswählen

struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw;    
    DWORD color; 

   CUSTOMVERTEX *pNext; 
}
und ich diese Struktur dynamisch im Programm fülle. Also mit new neuen Speicher beantragen und befülle.

Wie müsste memcpy in diesem Fall aussehen?
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [DX9] FVF und Vertexbuffer befüllen dynamisch

Beitrag von Krishty »

Wenn du einen zusätzlichen Zeiger in deine Vertex-Struktur packst, wird das vom FVF nicht unterstützt (denn obgleich es Flexible Vertex Format heißt, ist es nicht so flexibel wie man meint). Ganz abgesehen davon ist es eine Verschwendung von Bandbreite und Speicherplatz (und Cache-Misses und Zustandsraum und vielem mehr), weil du Daten auf die GPU scheffelst, die dort garnicht benutzt werden können, aber trotzdem die ganze Zeit mitgeschleppt werden müssen! (Es gibt ganz exotische Ausnahmen, die hier irrelevant sind.) Du brauchst also zwei Strukturen: Einmal (wie gehabt) deine CUSTOMVERTEX-Struktur, mit der die Vertex-Daten in den Puffern liegen; und dann nochmal eine andere Struktur (oder Klasse), die dein Programm intern nutzt um seine Daten vorzuhalten.

Weiterhin ist es ein grundsätzlicher Fehler, als Ziel einen void-Zeiger anzugeben (die Beispiele machen es trotzdem, aber die SDK-Beispiele sind auch die letzte Anlaufstelle um gute Programmierung zu lernen.) Die API gibt dir nämlich einen Speicherbereich zurück, der groß genug für ein Array von Vertices ist, mit einem Array von Vertices befüllt werden soll, … also behandel ihn auch so!
    void * pVoid
würde damit also zu
    CUSTOMVERTEX * pStagedVertices
werden (Staging nennt man die Überführung vom RAM in den VRAM und umgekehrt; die Daten, die du in den Puffer kopierst, werden also gestaget, so schrecklich das klingt.)

Dann iteriert üblicherweise eine Schleife (for, while, do while oder goto, was auch immer dir passt) über die Vertices und befüllt den Staging-Puffer. In deinem Fall hätte die Schleife zwei Iteratoren: Einen, der durch deine eigene Vertex-Klasse (die verkettete Liste) läuft; und einen, der durch das zu stagende Vertex-Array läuft. Die Schleife kopierte dann in jeder Iteration die nötigen Daten (also nicht deinen Zeiger!) von der internen Repräsentation in den Staging-Speicher.

Falls deine interne Vertex-Repräsentation und die Repräsentation der Vertices im Zielspeicher identisch sind, vereinfacht sich diese Schleife zu memcpy(). Das ist purer Zufall – dass diese Funktion hier benutzt wird, hat also nichts Magisches, sondern es ist bloß eine Optimierung.

Diese Optimierung strebt man an, weil Staging teuer ist. GPU und CPU laufen asynchron; und während die CPU die Vertices kopiert, kann die GPU den Puffer nicht benutzen. Der Speicher, in den du da kopierst, sieht zwar auch wie ein normaler Zeiger aus, kann aber dank Speichervirtualisierung je nach Treiber was komplett anderes sein – z.B. ein Stück AGP-gekoppelter Speicher, das für Burst Writes (also gradliniges Schreiben großer Datenmengen) optimiert ist. Darum ist man üblicherweise bemüht, das Staging zeitlich so knapp und gradlinig wie möglich zu halten – und memcpy() ist meist hochoptimiert und höchsteffizient.

Und deshalb halten Programme ihre Vertices intern meist auch schon im korrekten Format vor. Das meinte dot die ganze Zeit: In den allermeisten Anwendungen weißt du genau „Die Anwendung kann nur mit Positionen und Normalen arbeiten“ (Beispiel) und darum wäre es sinnlos, die Vertices auf andere Art vorzuhalten. Selbst, wenn man dynamisch Geometrie erzeugt und dafür sehr komplexe interne Datenstrukturen hat, sammelt man die nötigen Daten zuerst in einem Puffer mit derselben Auslegung wie der Vertex-Buffer auf der GPU, und kopiert dann von dem aus mit memcpy(), um das Staging so kurz und schlank wie möglich zu halten. Und das solltest du auch: Überlegen, ob du den Zeiger nicht loswerden kannst, und stattdessen bereits beim Laden alles in ein passendes Array schreibst, das via memcpy() kopiert werden könnte.

Ich hoffe, ich konnte etwas Licht auf die Sache werfen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
HLTO
Beiträge: 10
Registriert: 09.09.2002, 17:46
Kontaktdaten:

Re: [DX9] FVF und Vertexbuffer befüllen dynamisch

Beitrag von HLTO »

Ja deine Antwort hat mir sehr weiter geholfen. Danke für die ausführliche Erklärung. Vieles ist jetzt klarer. Ich habe das so implementiert wie von dir beschrieben. Und auch das mit dem Zeiger auf void aus der DX Doku erscheint mit jetzt in einem anderen Licht. :)

Beispiel wie es jetzt funktioniert ->

Code: Alles auswählen

int main()
{	
	LPSURFACE lpSurface;

	lpGraphic->Graphic(800,600,true);
	
	// lpSurface speichert Vertex-und Indexbuffer
	// die nachfolgenden Daten werden in lpSurface abgelegt
	lpGraphic->CreateSurface(&lpSurface);

	// lpSurface vorbereiten auf Daten
	lpGraphic->Begin();

	// Die zu verwendende Farbe definieren
	lpGraphic->Color(255,0,0);
	// Einen Vertex definieren
	lpGraphic->AddVertex(300.0f, 75.0f, 0.0f, 1.0f);

	lpGraphic->Color(0,255,0);
	lpGraphic->AddVertex(525.0f, 525.0f, 0.0f, 1.0f);

	lpGraphic->Color(0,0,255);
	lpGraphic->AddVertex(75.0f, 525.0f, 0.0f, 1.0f);		
	
	// es werden keinen neuen Daten mehr für lpSurface kommen
	lpGraphic->End();

	// Rendert alle 3D Objekte die erstellt wurden -> in diesem Fall nur ein Dreieck !!
	lpGraphic->Render();

	Sleep(2500);
	return 0;
}
dieser Code zeichnet ein Dreieck auf dem Monitor :) sieht zwar nach wenig aus, aber im Hintergrund passiert viel mit Vertexdaten sammeln (Indexdaten auch möglich) und wenn die Methode End() aufgrufen wird werden alle Daten in einen Vertexbuffer kopiert (der selbstständig erstellt wird) und in einer Liste abgespeichert. Der Aufruf der Methode Render() rendert alle Objekte die in dieser Liste gespeichert sind.

Ich habe noch ein paar Ideen wie man etwas flexible mir den FVF umgehen könnte, aber ich habe keine Ahnung ob es sich rentiert da noch Energie reinzustecken. Oder soll ich alle nur noch mit Shader realisieren? Wie seht ihr das. Haben FVF noch Zukunft?
Antworten