Performance-Frage [weiteres Problem!]
-
Powerpaule schrieb:
Also wenn du jede Textur jedesmal neu laden würdest wäre es sicher kein Wunder

Also sinds 6 Texturen pro Würfel, macht demnach ca. 1500 Wechsel? Das solltest du auf jeden Fall ausmerzen.
Es dürfte schneller sein, Erst eine Textur zu binden, dann durch alle Würfel zu gehen und die entsprechende Seite zu zeichnen, und dann die nächste Textur zu binden. Sind zwar mehr Schleifendurchläufe, aber am Ende müsste es trotzdem um einiges schneller gehen.Das ist eine gute Idee, danke!
Nein nein..die Textur wird vorher geladen und dann wird nur der Zeiger auf die Textur übergeben
-
Sorry wg Doppelpost aber:
Mir sind nun einige Dinge eingefallen:
Wie speichere ich am Besten die Vertices ab?
Soll ich erst alle Objekte beim Zeichnen initialisieren (also vertices festlegen) und in einem vector speichern?
Damit ich die nicht bei jedem der 6 Zeichenvorgänge neu initialisieren muss...UND das Wichtigste:
Das mit den Würfeln ist ja nur ein Beispiel...im Spiel wird es viele verschiedene Würfeltexturen geben.
Da müsste ich ja dann die Fahrzeuge alle Objekt für Objekt zeichnen. Also...z.b. erst alle Räder dann das Chassis,...usw.Das werden dann ja verdammt viele Durchläufe und ein großer Aufwand. mh
-
Das Stichwort lautet Renderqueues, das sind Puffer welche einen bestimmten Renderkontext enthalten und alle Vertices die diesen Kontext besitzen werden in diese Queue gestellt. Anschließend muss man nur die einzelnen Queues rendern und spart sich eine Menge unnötiger Texturwechsel&Co.
Das ganz ist allerdings etwas komplexer um es hier genauer zu beschreiben. In Stefan Zerbst's Buch 3D Game Engine Programming entwirft er eine Engine die das implementiert (mit DirectX).
-
Im Prinzip geht es, wenn ich das richtig verstehe, nur darum Batches nach gewissen Eigenschaften zu sortieren, und sie dann in dieser Reihenfolge zu rendern. Die Render-Queues wären dann Buckets in einem Bucket-Sort wenn man es von der Seite aus betrachtet. Bei ausreichend kleiner Anzahl von Buckets (also hier Render-Queues) ist das ziemlich sicher die beste (schnellste) Lösung.
Falls das Blödsinn sein sollte bitte mich entsprechend zu korrigieren.
-
kein bloedsinn, du hast es schon richtig gesagt. man sammelt alle 'renderjobs', sortiert die dann (quicksort reicht meist) und rendert das dann mit moeglichst wenig statechanges.
das waere bei den boxen aber irgendwie nicht die loesung. besser waere es soviele texturen wie moeglich in eine zu stecken, genauso die vertices der boxen und dann mit moeglichst wenig drawcalls alles abrendern.
-
Danke für die vielen Antworten!
Ich hab schon 2 große Fehler gefunden ..... verdammt blöde Fehler obendrein.....
und jetzt läuft es flüssig bei 60 FPS ohne irgendwelche Probleme.Lag wohl echt daran dass ich schon so lang nichts mehr in C++ und DX programmiert hab.
-
Ich bin nun auf ein anderes seltsamens Problem gestoßen ... wollte aber nicht extra nen Thread aufmachen.
Das Spiel ist jetzt schon etwas fortgeschritten und sieht so aus:
http://i191.photobucket.com/albums/z231/kuldren/Screenshot28August200802.jpgDas Problem ist...Gestern lief alles noch sauber bei 60 FPS ...
Nun habe ich nur die Datenstruktur für das Spielfeld (also statt einem Viereck dass aus 2 Dreiecken besteht direkt nur 2 Dreiecke verwendet) umstrukturiert.
Nach dem dabei aber aus der Perspektive die man auf dem Screenshot sieht die FPS auf ca 50 gesunken sind hab ich alles rückgängig gemacht und dachte es liegt einfach daran dass ich ja bei 2 dreiecken drawprimitve 2 mal aufrufe anstatt einmal bei einem viereck( wg. der matrizen).
Nach dem ganzen rückgängig machen hat sich aber nichts an den FPS verändert ...
Wenn ich allerdings die Kamera noch weiter nach oben bewege, bzw. ganz nah an der Spielfeld heran steigen die FPS wieder auf 59/60 an....
Im Vollbildmodus läuft sowieso alles auf 60 fps....
Nun meine Frage: Habt ihr eine Ahnung wieso das so sein könnte?Die ZBuffer Einstellungen sehen so aus:
D3DXMATRIX ProjMatrix; D3DXMatrixPerspectiveFovLH(&ProjMatrix, D3DX_PI/4, (float)ResolutionX / (float)ResolutionY, 1000.0f, 10000.0f );BTW: Ist egal ob 1024x768 oder 1280x800 (Das war bisher standard) - der effekt ist der gleiche.
-
Habt ihr eine Ahnung wieso das so sein könnte?
Ich vermute mal, dass es *nicht* an den ZBuffer-Einstellungen liegt.
Du koenntest mal den VSync abschalten um zu sehen, wieviel FPS Du wirklich hast.
-
hellihjb schrieb:
Habt ihr eine Ahnung wieso das so sein könnte?
Ich vermute mal, dass es *nicht* an den ZBuffer-Einstellungen liegt.
Du koenntest mal den VSync abschalten um zu sehen, wieviel FPS Du wirklich hast.Ohne Irgendwas in Kamerareichweite hab ich ohne VSync 100 FPS ... wenn ich 25 Turrets und das Spielfeld darstelle (->siehe screenshot)
dann sinds etwa 80-85 aus der höheWenn ich so nahe heranscrolle dass ich die Turrets alle im Bild habe sinken die fps auf 50 herab
-
So...ich wollte keinen extra Thread aufmachen - auch weil die Frage wieder zum gleichen Thema gehört.
Mein Spiel ist jetzt so weit dass es ein Spielfeld gibt (10x10 Felder zu je 2 Dreiecken.
Dazu eine große Fläche dahinter (wieder 2 Dreiecke) und zum Austesten auf jedem Feld ein Geschützturm (bestehend aus 13 Würfeln zu je 12 Dreiecken)Also ca 13*12*100=15600 Dreiecke.
Wobei das Spielfeld zu vernachlässigen ist. Ich habe mich bemüht grobe Fehler auszumerzen und es nun hinbekommen dass das ganze bei ca 40 FPS läuft.
Aber in einem anderen Thread hab ich was von 1.4 Mio! Dreiecken gelesen und 20 FPS ....

Natürlich wäre es toll wenn mein Programm auch mit 100 Geschützturmen auf dem Spielfeld flüssig bei 60 fps laufen würde aber das tut es leider nicht.
Vom logischen Teil her:
Ich stelle die Geschütztürme Objekt für Objekt dar, wobei ich immer das gleiche Objekt der Türme darstelle (dabei alle türme durchlaufe) und dann zum nächsten teil des turms wechsle (wieder alle durchlaufe und dabei darstelle usw.)
Also erst alle Bodenplatten, dann alle Mittelteile usw.
Weil diese Teile alle unterschiedliche Texturen haben.das sieht so aus:
for(int id=2;id<7;id++){ Device->SetStreamSource(0,my3DObjectManager.Objects[id]->VB,0,sizeof(CUSTOMVERTEX)); for(int allTurrets=0;allTurrets<numOfMiniGunTurrets;allTurrets++){ my3DObjectManager.moveTo(MiniGunTurrets[allTurrets]->getPosition()); my3DObjectManager.DrawAll(id,MiniGunTurrets[allTurrets]->outerRotation, MiniGunTurrets[allTurrets]->innerRotation, MiniGunTurrets[allTurrets]->Position); } }"id" sind die einzelteile eben von 1-13 (bzw. 0-12)
die DrawAll Methode sieht so aus (q steht hier für id) :
if(0<q && q<7){ float buf=oR.x; oR.x=0; Objects[q]->FitRotMovToMatrix(iR,oR,pos); oR.x=buf; } else if(q>6){ Objects[q]->FitRotMovToMatrix(iR,oR,pos); } else Objects[q]->FitRotMovToMatrix(iR,D3DXVECTOR3(0,0,0),pos); Device->SetTransform( D3DTS_WORLD, &Objects[q]->WorldMatrix); if(!Objects[q]->activateTextures){ Device->SetTexture(0,NULL); Device->DrawPrimitive(D3DPT_TRIANGLELIST,0,12); } else{ Device->DrawPrimitive(D3DPT_TRIANGLELIST,0,12); }Ich habe die Texturwechsel minimiert, die Abfolge der Darstellung verändert usw. aber ich schaffs einfach nicht dass das ganze flüssiger läuft.
Ich kann mir auch nicht vorstellen dass es an meiner Hardware liegt.
(P4 DualCore (6600 jeweils 1.8 GHZ) und NVIDIA GeForce 7500 LE)
Mag sein dass das eher unteres HW Ende ist aber z.b. Oblivion und WoW lassen sich bei mindestens 1024,768 und mittleren Details gut spielen (flüssig) und diese Spiele müssen doch viel mehr als 16.000 Dreiecke darstellen, oder?Dazu muss ich sagen dass ich noch keine Indexbuffer verwende (noch nicht damit beschäftigt) -soll ja ein Lernprojekt sein-und kommt noch - aber das Problem mit den FPS liegt doch wohl an meinem Code oder?
Wenn ich übrigens einfach den DrawPrimitive Aufruf auskommentiere läuft natürlich alles bei 60 fps (bedeutet aber eigentlich auch nichts)Kann es daran liegen dass ich jedes objekt einzeln darstelle? sollte ich alle in einen vertexbufferpacken? (Kann doch aber auch nicht funktionieren....wg der WorldMatrix...
Habe da leider noch nicht viel Ahnung....
-
Ein DrawPrimitive-Call lohnt sich fuer 12 Triangles nicht.
Steck alle Objekte die zusammen transformiert werden sollen in einen Vertexbuffer.
-
hellihjb schrieb:
Ein DrawPrimitive-Call lohnt sich fuer 12 Triangles nicht.
Steck alle Objekte die zusammen transformiert werden sollen in einen Vertexbuffer.Jeder einzelne Geschützturm hat eine andere ausrichtung...also eine andere Worldmatrix....
und die haben alle den gleichen vertexbuffer nur verschiebe ich dann eben an einen bestimmten punkt, rotiere das ganze und stelle es dar...dann zum nächsten punkt wo eingeschütz stehen soll usw.Ich muss doch für jeden Würfel vor dem darstellen
die rotation und position an eine WorldMatrix angeben oder nicht?
und dann rufe ich
[QUOTE] Device->SetTransform( D3DTS_WORLD, &Objects[q]->WorldMatrix);[/cpp]
auf um mitzuteilen dass das objekt so positioniert und rotiert werden soll
da kann ich doch gar nicht alle gleichen objekte in den gleichen drawprimitiv aufruf packen oder? weil ich ja dazwischen andere matrizen (weil andere rotationen) angeben muss....
Sind zwar die gleichen Türme aber alle nach einem anderen winkel ausgerichtet.
oder seh ich das falsch...??ich hab das so aus den kleinen beispielen aus den büchern die ich hier hab rausgenommen...da steht ja leider nie drin wie das bei vielen objekten am besten machbar ist....

Hier ein Bild damit ihr wisst wie es aussieht:
http://i191.photobucket.com/albums/z231/kuldren/10sept08-1.jpgÜbrigens besteht immer noch das Problem dass die Framerate um ca 10-15 fällt sobald man so nahe heranzoomt (einfach die kamera bewegt) dass man ca 5x5 Geschütze im Bild hat...
-
Dann multiplizierst Du die Vektoren eines Wuerfels eben erst mit der entsprechenden Matrix bevor Du sie in den Vertex-Buffer schreibst.
-
hellihjb schrieb:
Dann multiplizierst Du die Vektoren eines Wuerfels eben erst mit der entsprechenden Matrix bevor Du sie in den Vertex-Buffer schreibst.
Hm
Bisher fülle ich den Buffer so
CUSTOMVERTEX cbuf[]={ { - Objects[q]->Size.x/2, - Objects[q]->Size.y/2, - Objects[q]->Size.z/2, Objects[q]->Color, 0, 1}, // Vorne { - Objects[q]->Size.x/2, + Objects[q]->Size.y/2, - Objects[q]->Size.z/2, Objects[q]->Color, 0, 0}, { + Objects[q]->Size.x/2, + Objects[q]->Size.y/2, - Objects[q]->Size.z/2, Objects[q]->Color, 1, 0}, { + Objects[q]->Size.x/2, + Objects[q]->Size.y/2, - Objects[q]->Size.z/2, Objects[q]->Color, 1, 0}, { + Objects[q]->Size.x/2, - Objects[q]->Size.y/2, - Objects[q]->Size.z/2, Objects[q]->Color, 1, 1}, { - Objects[q]->Size.x/2, - Objects[q]->Size.y/2, - Objects[q]->Size.z/2, Objects[q]->Color, 0, 1}, //usw }; BYTE* VertexBufferStart; Device->CreateVertexBuffer(sizeof(cbuf), D3DUSAGE_WRITEONLY, D3D_CUSTOMVERTEX, D3DPOOL_MANAGED, &Objects[q]->VB, NULL); Objects[q]->VB->Lock(0,0,(void**)&VertexBufferStart,0); memcpy(VertexBufferStart,cbuf,sizeof(cbuf)); //VertSize=sizeof(cbuf); Objects[q]->VB->Unlock(); Device->SetFVF(D3D_CUSTOMVERTEX);Und zeichnen erfolgt so:
Device->SetTransform( D3DTS_WORLD, &Objects[q]->WorldMatrix); Device->SetStreamSource(0,VB,0,sizeof(CUSTOMVERTEX)); Device->SetTexture(0,NULL); Device->DrawPrimitive(D3DPT_TRIANGLELIST,0,12);ich dachte setTransform(D3DTS_WORLD....); legt fest dass alles was als nächstes gezeichnet wird so rotiert wird ?
Wenn ich vor dem Füllen des Buffers die vektoren multipliziere (wie auch immer dass dann geht -> ? ) müsste ich das ja bei jedem draw vorgang für alle objekte machen....kostet das nicht zu viel zeit?
-
ja, beides ist eine suboptimale loesung, da du beim immer neu befuellen von buffern sehr drauf angewiesen bist, dass der treiber dir die buffer ohne stalls gibt. wenn du zuviel fuellen willst, oder zuviele buffer hast, oder... muss der treiber im zweifelsfall warten bis der vorherige aus der pipeline ist (und das koennen manchmal ein paar frames sein). so wenige polys wie du zeichnest koennte aber hellis idee durchaus funktionieren.
eine weitere moeglichkeit waere: vertexshader. du koenntest dann einmal zum start z.b. 32mal den turm in den buffer schreiben, dabei vergibst du jedem dieser tuerme eine andere ID (die du irgendwie mit in den buffer schreibst, also als vertex attribut). dann uebergibst du 32 Worldmatrizen als vertexshader-constants die du mittels der ID pro vertex indizieren kannst.
natuerlich ist das ein overhead 32mal das selbe objekt reinzuschreiben, aber so extrem lowpoly wie das ist, bist du einfach nur drawcall limitiert. mehr als 2000 drawcalls pro frame kann man kaum fluessig darstellen (wenn man texture+statechanges miteinbezieht).
-
Da habt Ihr mich wohl missverstanden.
Dieser Geschuetzturm besteht ja aus 13 einzelnen Wuerfeln die jeweils per Matrix an eben die Stelle gebracht werden wo sie hin sollen - es sind also 13 Render-Calls noetig.
Das Objekt besteht aber nur aus zwei "logischen" Teilen: ein statischer Sockel und ein bewegliche Geschuetz.
Mein Vorschlag war darum, fuer jedes dieser zwei Teilobjekte *einmal* einen Vertexbuffer anzulegen in dem die zugehoerigen Wuerfel bereits transformiert abgelegt sind - somit sind nur noch zwei Render-Calls notwendig und das Geschuetz bleibt beweglich.
-
Kann ich nicht einfach mehrere Streamsources angeben?
Hab mal ein bissl Google bemüht aber kein richtiges Beispiel gefunden...Allerdings wird erwähnt dass es möglich ist mehrere Sources anzugeben (sonst hätte der erste Parameter von setstreamsource auch wenig sinn)EDIT:
Ich werde das ganze jetzt so machen wie von euch vorgeschlagen...direkt die einzelteile zusammen im Buffer Speichern...
Gibt es da eine Möglichkeit mehrere Buffer zu einem zu verschmelzen?
Wenn ich das ganze mit einem vector anstelle funktioniert das erstellen und füllen des buffer leider nicht. Nur mit einem arrayEDIT2:
So hab es jetzt genauso gemacht und es funktioniert auch recht gut. Das darstellen funktioniert bei 100 geschützen bei 60 fps ohne probleme...Allerdings sinken die FPS sobald ich beginne zu feuern (sind ja wieder 10 schuss pro Geschütz und 100 geschütze also 1000 Kugeln und somit 1000 drawcalls)
Gibts dafür ne gute Möglichkeit das ganze effizienter zu machen?
Nebenfrage: Ist es normal dass die FPS um ganze 30 fallen sobald man näher mit der Kamera heranfährt? Wenn ich nache rangehe...dass ich ca 5x5 Geschütze im Sichtfeld habe fallen die fps auf 30

Aber von weitem oder ganz nahe sinds wieder 60....
Es ist sogar so dass sie kontinuierlich fallen je näher ich rangehe....und ganz nah springen sie plötzlich wieder auf 60 ...total seltsam
-
Kuldren schrieb:
Allerdings sinken die FPS sobald ich beginne zu feuern (sind ja wieder 10 schuss pro Geschütz und 100 geschütze also 1000 Kugeln und somit 1000 drawcalls)
Gibts dafür ne gute Möglichkeit das ganze effizienter zu machen?
du weisst doch dass du drawcall limitiert bist und wieder machst du diese mini drawcalls. pack alle particle in einen vertexbuffer und zeichne sie mit einem rutsch (drawcall)
Nebenfrage: Ist es normal dass die FPS um ganze 30 fallen sobald man näher mit der Kamera heranfährt? Wenn ich nache rangehe...dass ich ca 5x5 Geschütze im Sichtfeld habe fallen die fps auf 30

ja, dein stichwort ist vsync.
-
rapso schrieb:
du weisst doch dass du drawcall limitiert bist und wieder machst du diese mini drawcalls. pack alle particle in einen vertexbuffer und zeichne sie mit einem rutsch (drawcall)
Darauf wollte ich hinaus, aber ich müsste Position (das ist ja noch einfach) und Rotation der Schüsse transformieren bevor ich die Vertices in den Buffer schreibe. Da steh ich leider an, weil ich ja bisher einfach die WorldMatrix mit
Device->SetTransform( D3DTS_WORLD, &Objects[q]->WorldMatrix);dazu verwendet habe. Aber wie mache ich das ohne danach direkt den Drawcall zu starten

rapso schrieb:
ja, dein stichwort ist vsync.
Das hab ich schon in einem anderen Thread gelesen. Kann aber nicht wirklich was damit anfangen. Soll ich VSync abschalten? Wär das nicht Kontraproduktiv (Obwohls dann trotzdem mehr Frames wären?
-
Kuldren schrieb:
rapso schrieb:
du weisst doch dass du drawcall limitiert bist und wieder machst du diese mini drawcalls. pack alle particle in einen vertexbuffer und zeichne sie mit einem rutsch (drawcall)
Darauf wollte ich hinaus, aber ich müsste Position (das ist ja noch einfach) und Rotation der Schüsse transformieren bevor ich die Vertices in den Buffer schreibe. Da steh ich leider an, weil ich ja bisher einfach die WorldMatrix mit
Device->SetTransform( D3DTS_WORLD, &Objects[q]->WorldMatrix);dazu verwendet habe. Aber wie mache ich das ohne danach direkt den Drawcall zu starten

ja genau, du machst das, nicht D3d, du per hand in deinem code, in d3d setzt du identity.
rapso schrieb:
ja, dein stichwort ist vsync.
Das hab ich schon in einem anderen Thread gelesen. Kann aber nicht wirklich was damit anfangen. Soll ich VSync abschalten? Wär das nicht Kontraproduktiv (Obwohls dann trotzdem mehr Frames wären?
bitte informier dich doch darueber. wenn du weisst was das ist und wozu, wirst du all deine fragen beantworten koennen. that's no rocked science.