|
JLI Spieleprogrammierung
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 02.11.2006, 16:18 Titel: [Direct3D] Performance-Verbesserung (?) mit Vorpuffer |
|
|
Hi,
ich hab beschlossen, meine Engine mal etwas zu aktualisieren und an neue Möglichkeiten anzupassen. Dabei kam mir eine Idee, was das Rendern von Objekten betrifft. Dazu ein wenig Vorgeschichte...
In letzter Zeit gabs mal einige Diskussionen hier, wie zeitaufwändig die Draw-Calls und die SetRenderStates und was weiß ich alles noch seien. Nun dachte ich, dass ich das Ganze etwas beschleunigen könnte, indem ich jeden Render Call intern in meiner Engine "vorrendere"; also ich schreibe alle Daten, die gerendert würden, in eine Liste, und die Vertexdaten aller Objekte zusammen in einen VB. Sind alle Objekte eingetragen, werden die kurz vor EndScene() über D3D gerendert, d.h. ich setze diesen einen VB und rendere dann aus der Liste heraus nacheinander alle Vertices. Zum Schluss kommt der Present()-Befehl. Ich hab schonmal einige Vor- und Nachteile zusammengefasst, die mir so spontan einfielen:
Vorteile:
setzen eines einzigen VertesBuffers
spätere Manipulationen wie nachhaltiges Sortieren, opimieren...
Zusammenfassung der RenderStates, Texturen etc.
(vllt kurzzeitige Entlastung des Grafikspeichers...)
Nachteile:
stärkere Belastung des Arbeitsspeichers wegen Extra-Puffer
(je nach Implementierung zusätzliche Rechenarbeiten)
Das Ganze könnte nun einerseits mir den erhofften Performance-Vorsprung verschaffen, oder aber nur eine sinnlose Schnapsidee sein, die mehr verschlechtert als verbessert.
Meine Frage: Was haltet ihr von der Idee? Wird sowas in der Praxis verwendet?
Gruß DXer |
|
Nach oben |
|
|
Fallen JLI MVP
Alter: 40 Anmeldedatum: 08.03.2003 Beiträge: 2860 Wohnort: Münster Medaillen: 1 (mehr...)
|
Verfasst am: 02.11.2006, 17:33 Titel: |
|
|
Das ist gängige Praxis
Die Objekte werden nach States7Texturen/Shader/Alphablending sortiert und in einem Rutsch gerendert, im DX SDK gibt es afaik einen Statemanager Sample dazu, schaus dir einfach mal an.
Aber evtl habe ich deine Technik auch nicht ganz verstanden, mache doch mal ein par Beispiele. _________________ "I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse." |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 02.11.2006, 17:51 Titel: |
|
|
hmm, also ich glaub schon, dass du das meinst, was ich meine. Also wars doch net nur so en doofer einfall
naja, nur der sicherheit halber mal ein beispiel:
ich habe zwei Objekte, die ich rendern will. Bei Methode1 würden zuerst für das 1. Objekt Textur, Matrix, VB, IB usw. gesetzt; dann per Draw...() übers Device gerendert; und zum schluss weider alles zurückgesetzt. Danach passiert dasselbe für die Daten von Objekt 2.
Bei Methode2, die ich oben beschrieben hab, würden die Daten über jeweilige Funktionen in meiner Engine gesetzt werden; zuerst für Obj1 dann für Obj2. Von außen sieht das ungf. dann so ähnlich aus wie Meth. 1, nur dass die Aufrufe net übers Device sondern bei meiner Engine registriert werden. Die Engine speichert alle Daten zwischen und schreibt alle Vertexdaten in einen VB. Erst am Ende der Szene rendert meine Engine das ganze, indem es den VB setzt und die Objekte auf einen Rutsch dem Device mitteilt, also hier kommen erst die Draw() usw. Methoden des Devices ins Spiel.
Gruß DXer |
|
Nach oben |
|
|
Chriss Senior JLI'ler
Anmeldedatum: 18.08.2004 Beiträge: 267
Medaillen: Keine
|
Verfasst am: 02.11.2006, 18:06 Titel: |
|
|
Also so wie Fallen es beschrieben hat musst du es schon machen, sonst bringt es dir nicht viel.
Du musst deine Objekte intern schon nach Textur, Shader usw. sortieren. So wie ich dich verstanden habe willst du nur alles in einen VB schreiben aber dann trotzdem SetTexture usw. ausführen wie es kommt.
Wenn du das so machst, liegt dein einziger Vorteil darin, dass du alle Vertexdaten in einem Rutsch kopierst (etwas wirds schon bringen) aber erst wenn du deine Aufrufe zusätzlich nach Renderstates usw. sortierst hast du einen wirklichen Vorteil. |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 02.11.2006, 19:20 Titel: |
|
|
über den exakten Gebrauch, bis ins Detail, hab ich noch net nachgedacht, aber die Sache mit dem Sortieren war mir schon klar. Ich hab das wahrscheinlich net etwas zu wenig betont, aber oben bei Vorteilen hatte ich das auf jeden Fall erwähnt.
Gruß DXer |
|
Nach oben |
|
|
Dr. Best Senior JLI'ler
Alter: 34 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 03.11.2006, 14:39 Titel: |
|
|
Ich hab diese Technik in meiner Engine schon umgesetzt. Wenn man komplexe Objekte mit Shadereffekten, Animation oder Multitexturing braucht werden die einzeln gerendert. Aber wenn das nicht der Fall ist kann man was verwenden was ich Primitive getauft hab.
Primitive erstellt man über eine Primitiv Managment Klasse, d.h. mit den Klassen, die intern verwendet werden kommt man garnicht in Kontakt. Der Primitiv Manager verwaltet Instanzen von zwei anderen Klassen. Die erste ist nicht schwer zu erraten. Sie nennt sich CPrimitive, davon gibt es eine Instanz für jeden erstellten Primitiv und sie verwaltet Textur, Material, Transformation, untransformierten Vertex Buffer und Index Buffer des Primitivs. Die andere Klasse nennt sich CPrimitiveGroup. Wann immer ein Primitiv erstellt wird, der in keine der vorhandenen Gruppen passt, wird eine neue erstellt. Die Gruppe enthält dann die Indizes aller enthaltenen Primitive, einen vortransformierten Vertex Buffer, der groß genug für alle Primitive ist (um genau zu sein für 1 1/2 mal so viele Primitive, damit nicht immer sofort erweitert werden muss wenn ein neuer Primitiv hinzkommt) und einen entsprechend großen Index Buffer. Immer wenn eine Änderung an einem der Primitive vorgenommen wird muss das über den Primitiv Manager geschehen. Der schaut dann, ob der Primitiv in eine neue Gruppe verschoben werden muss oder ob der Vertex Buffer neu transformiert werden muss.
Der Primitv Manager hat eine Memberfunktion Render, die dann in einer Schleife jede Primitiv Gruppe ihre Primitive render lässt. Da der Vertex Buffer der Gruppen unter Umständen enorm oft bearbeitet werden muss (vorallem bei Billboards) verwende ich übrigens tatsächlich garkeinen Direct 3D Vertex Buffer sondern einen DrawIndexedPrimitiveUP call.
Das hilft dir vielleicht ein Bisschen bei der Umsetzung in deiner Engine.
MfG
Dr. Best |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 03.11.2006, 21:16 Titel: |
|
|
danke schön,
die Idee ist interessant, ich überleg mal inwiefern ich das einbauen kann. Allerdings musst du dann den z-Buffer benutzen (wenn man das net eh schon macht), da du die Render-Reihenfolge (z.B. Back to Front Order) ja u.U. änderst, oder? Aber das wird sich schon net so scharf auswirken...
Gruß DXer |
|
Nach oben |
|
|
Dr. Best Senior JLI'ler
Alter: 34 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 04.11.2006, 01:04 Titel: |
|
|
Z-buffering hab ich sowieso immer an. Und um back-front-order kümmer ich mich nicht. Wäre mir zu rechenintensiv. Das einzige was ich mache um Probleme mit dem Alphablending größtenteils zu vermeiden ist, dass ich zuerst alle Objekte rendere, die ein nicht transparentes Material verwenden und danach erst die anderen rendere wobei ich dabei Z-buffer-writes deaktiviere. |
|
Nach oben |
|
|
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 04.11.2006, 10:24 Titel: |
|
|
Naja, nur ZBufferwriting zu deaktivieren ist vielleicht schon besser, aber wenn du jetzt z.b. nicht richtig transparente Objekte hast, sonder sowas wie Gitter sieht das schon komisch aus, wenn zwei direkt hintereinander stehen und das hintere über dem vorderen ist. _________________ https://jonathank.de/games/ |
|
Nach oben |
|
|
Dr. Best Senior JLI'ler
Alter: 34 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 04.11.2006, 14:23 Titel: |
|
|
@ Jona
Ich weiß. Darüber hab ich mich schon oft genug geärgert . Aber in jedem Frame alles in Back-to-Front-Order zu bringen (bzw. in jedem Frame einmal für jedes aktive Kameraobjekt) ist einfach ein enormer Rechenaufwand. Und selbst das ist noch keine Patentlösung. Denn wenn ich alles in Back-To-Front-Order bringen will muss ich ja zwangsläufig für jedes Objekt irgendeinen Mittelpunkt definieren. Aber was wenn das eine Objekt größer ist als das andere und deshalb trotzdem noch etwas von dem kleineren verdeckt, obwohl es als dahinter eingestuft wurde? Und noch schlimmer, was passiert wenn ein Objekt Teile von sich selbst verdeckt?
Eine Lösung, die zwar mit einem recht hohen Aufwand für den GPU verbunden ist, dafür aber immer funktionieren sollte ist die Alpha Map separat von der Color Map in den zweiten Textur Stage zu packen und im zweiten Textur Stage dann Nearest-Point Sampling zu verwenden. Wenn man dann im Alphakanal nur volle Deckkraft oder volle Transparenz hat, wird sich da durch den Texturfilter auch nichts mehr dran ändern. Aber wenn man partielle Transparenz will nützt einem das natürlich auch nichts.
Aber ich würd sagen, damit sollten wir das Thema auch beiseitelegen. Sonst driftet das hier zu sehr ins Off-Topic ab.
Nur eins noch. Wer DirectX 10 benutzt wird sich über sowas nie wieder Gedanken machen müssen . |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 14.02.2007, 16:27 Titel: |
|
|
so, ich muss diesen Thread nochmal aufgraben, sry
also, die vorgeschichte: ich hab seit dem erstellen des threads nun an meiner engine rumgewerkelt; ziemlich fleißig (fast schon fanatisch) und bin auch schon ziemlich weit gekommen. Jetzt musste ich aber noch mal an den Grafikpart, den ich eigentlich weitgehend abgeschlossen hatte dran, und da kommt genau wieder das ans Tageslicht was ich hier vor fast 1/3 Jahren gefragt hab: Das Vorpuffern.
Genug Vorgeschichte, zum Thema: Ich hab das ganze ungf. so ähnlich gemacht, wie Dr. Best gemacht, also alle primitiven Objekte registrieren sich in meiner Graphics-Umgebung und werden in maps (ziemlich praktisch, da automatisch sortiert, immer ein key etc.) eingeordnet, um möglichst viele Objekte in einem Draw( Indexed )Primitive()-Call zusammenzufassen. Bei Sprites (bzw. Billboards) hab ich meist 4 vertices mit 6 Indices für ein Quad in D3DPT_TRIANGLELIST genommen. Jetzt wollte ich das mal ohne index buffer machen, d.h. 4 Vertices in D3DPT_TRIANGLESTRIP für ein sprite. Beim Gruppieren der Primitive bin ich dann auf folgendes Problem gestoßen:
Die Objekte werden aneinander gerendert. Grundidee war ja: CPP: | DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); | zu CPP: | DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 4 ); | zusammenzufassen, damals hab ich aber nicht an das Problem mit triangle strips gedacht. Nebenbei liegt die texture dann auch nicht auf jedem sprite einzeln, sondern streckt sich als eine quer über alle anderen.
Lange Rede, kurzer Sinn: Gibt es eine andere Möglichkeit, dieses Problem zu umgehen, außer wieder auf triangle list und IB umzusteigen? Denn wenn ich jetzt doch wieder für jedes Trianglestrip einen eigenen DrawPrimitive-Call machen muss, is das ganze Konzept ja umsonst (zumindest für diese primitive)
Gruß DXer |
|
Nach oben |
|
|
Dr. Best Senior JLI'ler
Alter: 34 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 14.02.2007, 19:36 Titel: |
|
|
Wenn man bei der Verwendung von Triangle Strips bestimmte Vertices Mehrfach in den Vertex Buffer schreibt, separiert man die Quads dadurch voneinander. Problem ist nur, dass man dann auch wieder genau 6 Vertices pro Quad braucht, man hat also keinen Gewinn im Vergleich zu einer Triangle List. Daher würde ich dir raten einfach Triangle Lists zu verwenden. Da brauchst du keinen Index Buffer und bist mit sechs Vertices pro Quad optimal dabei. |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 14.02.2007, 20:35 Titel: |
|
|
ah, thx, dann weiß ich wie ich das problem lösen kann =) also wieder weg vom grafikproblem in den aktuellen part; soundmixer
Danke nochmal,
Gruß DXer |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 14.02.2007, 23:21 Titel: |
|
|
nochmal sorry (für doppelpost), war etwas vorschnell. Also mit den triangle strips geht das ja so, aber gibts da auch ein Trick für triangle fans und line lists? Wäre schön, obwohl ich glaube, dass sowas (leider) nicht geht
Gruß DXer |
|
Nach oben |
|
|
Dr. Best Senior JLI'ler
Alter: 34 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 16.02.2007, 00:24 Titel: |
|
|
Was genau meinst du jetzt? Mit Triangle Fans stößt man immer recht schnell an seine Grenzen. Wenn alle Dreiecke einen gemeinsamen Punkt haben müssen kannst du damit schlecht irgendwelche unverbundenen Quads basteln. Also besser einfach auf Triangle Lists umsteigen. Solang es nur um Vertex Quads geht ist das auf jeden Fall die effizienteste Lösung. Und was willst du jetzt nochmal mit Line Lists machen? |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
Powered by phpBB © 2001, 2005 phpBB Group Deutsche Übersetzung von phpBB.de
|