Partikelsystem

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
Jonathan
Establishment
Beiträge: 2371
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Partikelsystem

Beitrag von Jonathan »

Also die grundsätzliche Theorie hinter Partikelsystmen ist ja recht einfach und soweit auch klar. Ne Menge (kameraausgerichteter) Quads zeichnen mit irgendwelche Sprites, die am besten noch halb transparent sind und nach einem bestimmten Muster bewegen. Aber wie bekommt man das jetzt möglichst effizient hin?
Man will ja möglichst wenig DrawCalls machen und in jedem Frame möglichst wenig Daten an die Grafikkarte übertragen. Aber im Gegensatz zu einem echten Modell hat so ein Partikel ja kaum Daten, die man z.B. ein einem VertexBuffer speichern könnte, sondern die dynamsichen Daten, die in jedem Frame neu berechnet werden, machen eine Menge aus. Wenn man also nicht für jedes Partikel eine Transformationsmatrix setzen und einen einzelnen DrawCall machen will, würde man dann den kompletten VertexBuffer mit allen Partikel in jedem Frame neu erstellen und hochladen? Oder einen großen Vertexbuffer mit allen Partikel im Ursprung haben und sehen, dass man nur die Tranformationsdaten möglichst kompakt nach oben bekommen und im VertexShader daraus den fertigen partikel basteln?
Also wie man wohl sieht, weiß ich nicht so genau, wie ich es machen würde, aber ich schätze dass man es schon gerne möglichst effizient haben will, weil man mit mehr Partikeln realtiv einfach die Optik verschönern kann. Und da Partikelsysteme ja sehr geläufig sind, hat doch bestimmt jemand von euch ein paar super Tipps und Quellen dazu parat. Weil das was man so spontan findet sind eher Einsteiger Tutorials und ich bin mir recht sicher, dass mit etwas mehr Aufwand da einiges mehr geht.
Achja: Das ganze soll unter OpenGL laufen, aber da es ja eher um die Theorie geht, sollte das ja mehr oder weniger egal sein.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Partikelsystem

Beitrag von dot »

Jonathan hat geschrieben:Wenn man also nicht für jedes Partikel eine Transformationsmatrix setzen und einen einzelnen DrawCall machen will, würde man dann den kompletten VertexBuffer mit allen Partikel in jedem Frame neu erstellen und hochladen?
Das klingt doch ganz gut ;). Man würde eben einen dynamischen VertexBuffer verwenden (nicht in jedem Frame neu erstellen, sondern nur Locken und neu befüllen). Natürlich gibts auch die Möglichkeit Partikelsysteme direkt auf der GPU zu realisieren, aber das sind dann wohl schon etwas fortgeschrittene Techniken...
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Partikelsystem

Beitrag von Krishty »

Zuerst einmal packt man die Quads nicht in Vertex-Buffer, sondern nutzt, weil sie alle mehr oder weniger gleich aufgebaut sind, entweder Instancing oder – noch besser – berechnet die Quads im Geometry Shader.

Weiterhin sind Partikel-Berechnungen ziemlich trivial – die haben meistens nur Position, Bewegungsrichtung und Animationsframe, manchmal eine Kollisionsabfrage mit der Umgebung und so gut wie nie Wechselwirkung untereinander. Dadurch sind sie perfekt parallelisierbar – ergo perfekt für die GPU geeignet.

Man allokiert also zwei Texturen (eine mit Positionsdaten und eine mit Bewegungsvektoren, und in die Alpha-Kanäle füllt man mit Radius, Animationsfortschritt und was man sonst so braucht), bei deren Kombination jeder Texel einen Partikeldatensatz repräsentiert, und setzt, falls es eine Kollisionsabfrage mit der Umgebung gibt, die paar Kollisionsdaten als Shader-Konstanten. Dann zeichnet man Fullscreen-Rects über die Texturen um sie komplett zu überschreiben (heute nimmt man für sowas besser einen Compute Shader) und setzt sie zugleich als Input. Der Shader liest dann die jeweils alten Daten aus der Textur, führt die Berechnungen damit durch und gibt die neuen Daten aus, damit sie auf der Textur landen.

Im zweiten Schritt wird ein Vertex-Shader gesetzt, der seine Eingabe nicht aus einem Vertex-Buffer liest sondern aus ebendiesen Texturen, und ein Vertex mit den daraus gesammelten Daten ausgibt. Der Geometry Shader macht dann ein Quad draus und gibt es auf dem Bildschirm aus.

Im nächsten Frame wiederholt sich das Spiel – die Texturen mit den Partikelinformationen werden aktualisiert, es wird erneut gerendert.

Wenn man wirklich nichts anderes macht als banale Partikel ohne Kollisionen o.ä. zu rendern, kommt man damit auf ein paar hundert Millionen Partikel. Mit trivialer Kollisionsabfrage (nur ein paar Wände & Boden) auf ein paar Millionen. Will man jedes Partikel mit jedem verrechnen (z.B. die Anziehungskraft untereinander berechnen für eine Sternensimulation), sind es einige Zehntausend. In Spielen, wo die Partikel sehr komplex sind (man möchte sanfte Übergänge zur Geometrie dahinter, hochauflösende Texturen, …) und sehr groß (Rauchschwaden und nicht bloß 4×4 Pixel große Pünktchen), kommt man auf eine ähnliche Zahl – bei Spielen, wo die Partikel nicht im Vordergrund stehen (also bei allem außer Space- und Flugsimulatoren ;) ) bedient man sich dann weniger hundert.

Bei sowas wie dynamischen Vertex Buffers wäre man hingegen durch zweierlei Dinge limitiert: Zum einen ist die CPU bei der Aktualisierung der Partikel einige hundert bis tausend Mal langsamer, wenn man nicht hochoptimierten Multi-Core-SIMD-Text schreibt, und zum anderen müssen die horrenden Datenmengen (im GiB-Bereich bei hundert Millionen Partikeln) Frame für Frame über den PCI-Slot aus dem Hauptspeicher in den Grafikspeicher.

Gruß, Ky

Es gibt dann noch ein paar Tricks, das Ganze zu beschleunigen. Imo sehr gut sind die Partikeleffekte in Ace Comabt 6:

Hier hat man, um auf der XBox nicht füllratenlimitiert zu sein, einfach alle Partikel in halber Auflösung berechnet und nachträglich über die Szene gelegt. Da die Partikel eh alle sehr fluffig aussehen, spart man drei Viertel der Füllrate mit geringen optischen Einbußen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4858
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Partikelsystem

Beitrag von Schrompf »

Wenn Du es schlichter magst: die Lösung über einen dynamischen VertexBuffer ist immernoch tauglich und funktioniert bis zu einigen zehntausend Partikeln auch stressfrei. Mit SM4.0 und einem Geometrie-Shader kannst Du Dir einiges an Traffic sparen, aber es geht auch schlicht mit DX9 und vier Vertizes pro Partikel. Krishtys Lösung ist, passende Hardware vorausgesetzt, natürlich deutlich performanter.

Partikel sind übrigens üblicherweise fillrate-limitiert, weil man für einen angemessen fluffigen optischen Eindruck viele kaum sichtbarte Partikel übereinander zeichnen will. Da empfiehlt es sich dann wie von Krishty angedeutet, die Partikel in einen Buffer halber oder Viertel Auflösung zu zeichnen. Gibt an den Kanten hässliche Flecken, die man mit etwas Shadermagie aber verstecken kann.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Maxim
Beiträge: 8
Registriert: 09.07.2011, 10:51

Re: Partikelsystem

Beitrag von Maxim »

Hallo Allerseits !

Erstmal vielen Dank an Jonathan für die Eröffnung des Themas. Ich schlage mich die letzten Tage mit dem Thema rum. Vor paar Tage hat mir ein Kollege diesen Forum empfohlen und als ich heute hier reingeschaut habe, habe ich dieses Thema entdeckt. Was für ein Zufall :-)

Nun zum Thema.

Als Produkt soll ein einigermaßen effizientes Partikelsystem entstehen mit dem man Feuer, Rauch, Schwarmverhalten usw. simulieren könnte. Dies soll mit Hilfe der Unterstützung von Shadern laufen aber auch ohne.

Ich bin erstmals dabei ein sehr primitives System zu entwickeln ohne GLSL oder OpenCL zu verwenden.

Nun analysiere ich wo bei dem primitiven System die Grenzen sind. Die Anforderungen sind erstmals simpel:
eine Menge aus texturierten Partikeln soll sich in zufällige Richtungen bewegen.

Ich habe folgendes Implementiert:

Das Ganze läuft auf OpenGL Basis.

Datenstruktur:
- zwei Float Felder: Pos[], Vel[]

Initialisierung:
- Erstellen der Partikeltextur
- Initialisierung des Pos[] und Vel[] mit Daten
- Erstellen eines VBOs und Transformieren der Pos[] Daten zur diesem VBO.

Zeichnen:
- Binden der Partikelextur
- Binden des Pos[]-VBOs und Transformieren des Pos[] zum VBO.
- Das eigentliche Zeichnen geschieht mit glDrawArrays(GL_POINTS, 0, NUM_OF_PARTICLES)

Update:
- Aktualisierung des Pos[] Feldes anhand des Vel[] Feldes.

Ergebnis: bei einer Textur 32x32 und Anzahl der Partikeln <= 10000 läuft alles noch flüssig.

Nun die Frage. Ist mein Ergebnis völlig normal oder mache ich etwas falsch was zur schlechter Performanz führt (bei Anzahl der Partikeln > 10000) ?
Wenn das Ergebnis Schon normal ist, kann man noch irgendetwas optimieren damit das System schneller wird ? (ohne GLSL, OpenCL, CUDA usw.)

Mein System übrigens:
CPU: Intel Quad Core (2Ghz je Kern)
RAM: 2GB
Grafikkarte: HD4650

Ich würde mich über Tipps sehr freuen. Vielen dank im Voraus !
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Partikelsystem

Beitrag von Krishty »

Dafür musst du herausfinden, ob du in der Pixelfüllrate limitiert bist oder in der CPU-Leistung / Bandbreite. Mach die Partikel einfach ein Drittel größer – falls die Leistung merklich nachlässt, bist du füllratenlimitiert. Falls die Leistung annähernd gleich bleibt, füllt die CPU den Puffer zu langsam oder überträgt zu große Datenmengen.

Was übrigens auch helfen kann, den Füllratenhunger zu drücken, sind angepasste Sprites. Das kann die Füllrate schonmal doppelt so gut ausnutzen, vervielfacht aber die Bandbreite falls man es nicht per Instancing oder im Shader macht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Maxim
Beiträge: 8
Registriert: 09.07.2011, 10:51

Re: Partikelsystem

Beitrag von Maxim »

Danke für die Antwort.
Also ich habe die Partikelgröße folgendermassen geändert: glPointSize(32.0*1.3);
Die Framerate sinkt dabei von 60fps auf 45fps.
Wenn ich allerdings die update Funktion ausschalte (also die Positionen werden nicht mehr neu berechnet), bleibt die Framerate einigermaßen konstant bis 40000 Partikeln (Größe 32)
Also höchstwahrscheinlich liegt das Hauptproblem an der Berechnung der Physik.
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Partikelsystem

Beitrag von Krishty »

Dann musst du aber noch weiter unterscheiden ob die Berechnung oder das Hochladen zur GPU limitieren. Lass die Update-Funktion weiterhin aktiv, aber lass sie in jedem Frame den Puffer mit denselben Daten nochmal beschreiben (ohne dabei was auszurechnen). Bleibt die Framerate konstat, limitiert die Berechnung. Sinkt sie wieder, limitiert die Datenmenge, die du zur GPU schiebst.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Maxim
Beiträge: 8
Registriert: 09.07.2011, 10:51

Re: Partikelsystem

Beitrag von Maxim »

Also die Framerate bleibt sogar bei 40000 Partikeln konstant (60fps) wenn ich nur die Positionen mit alten Werten überschreibe:

for(int i=0; i<NUM_OF_PARTICLES; i++)
{
pos[(i*2)+0] = pos[(i*2)+0];
pos[(i*2)+1] = pos[(i*2)+1];
}

Also limitiert die Berechnung. Wahrscheinlich hilft hier nur Multithreading.
Maxim
Beiträge: 8
Registriert: 09.07.2011, 10:51

Re: Partikelsystem

Beitrag von Maxim »

Hier ist übrigens ein Tutorial wie man ein Partikelsystem auf OpenCL Basis effizient implementiert:

http://enja.org/2010/08/27/adventures-i ... th-opengl/
Benutzeravatar
Schrompf
Moderator
Beiträge: 4858
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Partikelsystem

Beitrag von Schrompf »

Evtl. hast Du aber auch nur Vertical Sync aktiviert. Dann ist die Messung über die FPS reichlich sinnlos, weil der Grafikkartentreiber eh auf die Bildwiederholrate Deines Monitors beschränkt. Schalte also unbedingt Vertical Sync ab! Bei DirectX geht das mit den CreateDevice-Parametern, bei OpenGL sicherlich auch irgendwie. Alternativ schaust Du mal in die 3D-Einstellungen Deines Grafikkartentreibers. Dort kann man solche Einstellungen auch ändern.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Stimpy
Beiträge: 49
Registriert: 02.03.2011, 15:16
Wohnort: Seelze / Hannover
Kontaktdaten:

Re: Partikelsystem

Beitrag von Stimpy »

Code: Alles auswählen

glSwapIntervalEXT(0)
Ist der befehl für Vertical Sync deaktivieren in OpenGL....
Maxim
Beiträge: 8
Registriert: 09.07.2011, 10:51

Re: Partikelsystem

Beitrag von Maxim »

Danke. Ja die Ausschaltung des VSynses wirkt sich auf die Performance positiv aus. Allerdings darf ich es nicht ausschalten, weil das SDK für den ich das Partikel System implementiere VSyns braucht.
Ich bin gerade bei der Planung der Datenstruktur für mein System und habe eine Frage an euch.
Ist es effizienter mehrere VBOs (z.B. für jedes Emitter ein VBO mit Positionen) zu erstellen und diese dann einzeln beim Rendering hochzuladen oder macht es mehr Sinn einen einzigen großen VBO (z.B. für Positionnen aller Partikeln von allen Emittern) zu erstellen und es dann beim Rendering einmal binden und hochladen?
Also ich denke die zweite Möglichkeit ist besser, weil man nur einmal den Buffer beim Rendering bindet und hochlädt aber sicher bin ich mir dabei nicht.
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Partikelsystem

Beitrag von Krishty »

Rein instinktiv würde ich die erste Methode bevorzugen, da die GPU dann schonmal mit dem Rendering des ersten Puffers beginnen kann während du den zweiten noch mit der CPU befüllst. Die Puffer dürfen aber nicht zu klein werden, denke ich. Vielleicht wäre ein Puffer pro Emitter-Typ sinnvoll.

Eine andere Frage: Warum überhaupt Puffer? Bietet OpenGL keine Möglichkeit, direkt aus dem Speicher zu rendern (wie DrawPrimitiveUP() in Direct3D)? Falls doch, würde ich das definitiv mal ausprobieren, einfach so.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Maxim
Beiträge: 8
Registriert: 09.07.2011, 10:51

Re: Partikelsystem

Beitrag von Maxim »

Krishty hat geschrieben:Vielleicht wäre ein Puffer pro Emitter-Typ sinnvoll.
Eine gute Idee. Werde es ausprobieren.
Krishty hat geschrieben:Bietet OpenGL keine Möglichkeit, direkt aus dem Speicher zu rendern
Das mache ich doch schon mit VBO oder?:

glBindBuffer(GL_ARRAY_BUFFER, vboID);
glEnableClientState(GL_VERTEX_ARRAY);
glBufferData(GL_ARRAY_BUFFER, m_iArray_size, &pos_buffer[0], GL_DYNAMIC_DRAW); // upload data to video card
glDrawArrays(GL_POINTS, 0, NUM_OF_PARTICLES); <<< aus dem Videospeicher Rendern
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Partikelsystem

Beitrag von Krishty »

Alles klar. Als OpenGL-Fremdling wusste ich nicht, dass auch Index Buffers als VBOs bezeichnet werden. Nee, da steht ja GL_POINTS – ich meinte was Shoot-and-Forget-mäßiges, wo überhaupt nicht gepuffert wird. Für mich sieht der Text so aus als würden die Daten erst in den Puffer kopiert werden; aber ich habe auch nicht viel Ahnung von OpenGL.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Maxim
Beiträge: 8
Registriert: 09.07.2011, 10:51

Re: Partikelsystem

Beitrag von Maxim »

Krishty hat geschrieben: Für mich sieht der Text so aus als würden die Daten erst in den Puffer kopiert werden.
Ja werden auch. Also das gesamte VertexArray wird zur Grafikkarte gesendet und diese zeichnet dann halt alle Punkte. (in meinem Fall)
Genauso gut könnte man sagen: glDrawArrays(GL_QUADS, 0, NUM_PARTICLES); Dann werden Quads gezeichnet. Allerdings muss dann die Datenstruktur dementsprechend angepast werden.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4858
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Partikelsystem

Beitrag von Schrompf »

DrawPrimitiveUP kopiert doch genauso in einen dynamischen VertexBuffer, bevor es rendert. Geht ja nicht anders, wenn GPU und CPU getrennte Speicher haben. Es macht halt nur Direct3D bzw. der Treiber für Dich, Du musst es nicht selbst machen.

Und was mich an dieser Diskussion stört: das Abschalten von VSync verbessert genau gar keine Performance! Du musst hier aufpassen, dass Du nicht in eine Optimierungsfalle tappst. VSync abschalten ist ein absolutes MUSS, solange Du an der Performance arbeitest. Denn sonst siehst Du an der FPS gar nicht, ob Deine Optimierung was gebracht hat, solange das Gesamtsystem nur schneller als die Monitor-Refreshrate arbeitet. Du schaltest natürlich später VSync in der echten Anwendung wieder an. Aber momenten, da Du zu optimieren versuchst und die Wirkung nur an der Aktualisierungsrate des Gesamtsystems messen kannst, wäre VSync eine sehr sehr sehr dumme Wahl.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Maxim
Beiträge: 8
Registriert: 09.07.2011, 10:51

Re: Partikelsystem

Beitrag von Maxim »

Schrompf hat geschrieben:VSync abschalten ist ein absolutes MUSS, solange Du an der Performance arbeitest. Denn sonst siehst Du an der FPS gar nicht, ob Deine Optimierung was gebracht hat, solange das Gesamtsystem nur schneller als die Monitor-Refreshrate arbeitet. Du schaltest natürlich später VSync in der echten Anwendung wieder an. Aber momenten, da Du zu optimieren versuchst und die Wirkung nur an der Aktualisierungsrate des Gesamtsystems messen kannst, wäre VSync eine sehr sehr sehr dumme Wahl.
Danke. Ja genau das selbe hat mir auch mein Chef gesagt.
IlikeMyLife
Establishment
Beiträge: 212
Registriert: 08.05.2011, 09:59
Benutzertext: Feel Free

Re: Partikelsystem

Beitrag von IlikeMyLife »

An Stelle von Ace Combat würde mich eher bei Silent Hill interessieren, wie es dort mit den Partikeln gemacht wurde.
Bei diversen Nebelschwarden kam es mir doch schon so vor, als wäre da einiges von Leistung von Nöten gewesen...
vielleicht kennt das Game ja noch jemand und hatte mal die gleichen gedanken.

Mir geht es einfach nur darum, dass dieses besagte Spiel doch schon recht alt ist, allerdings zum damaligen Zeitpunkt
ja schon eine technik existiert haben muss, um dieses für den User recht realistisch darstellen zu können.
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Partikelsystem

Beitrag von Krishty »

Schrompf hat geschrieben:DrawPrimitiveUP kopiert doch genauso in einen dynamischen VertexBuffer, bevor es rendert. Geht ja nicht anders, wenn GPU und CPU getrennte Speicher haben. Es macht halt nur Direct3D bzw. der Treiber für Dich, Du musst es nicht selbst machen.
Ob es in einen dynamischen VB kopiert, weißt du doch garnicht. Die Runtime bzw. der Treiber regelt das, und weiß dabei klipp und klar: Diese Daten hier, die kommen jetzt einmal über den Bus und danach sind sie weg. Das kann intern jede mögliche Optimierung auslösen. Wenn man hingegen manuell in einen Puffer kopiert, muss Runtime / Treiber hingegen davon ausgehen, dass man die Daten unbedingt im VRAM behalten will um sie spätestens im nächsten Frame erneut zu verwenden. State is the enemy.

Da erwarte ich jetzt natürlich keine Leistungsverdopplung, aber ausprobieren und vllt nochmal 5 % einsacken kann ja nicht schaden (ganz abgesehen davon, dass man die Programmlogik zur Verwaltung des Puffers spart).
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Jonathan
Establishment
Beiträge: 2371
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Partikelsystem

Beitrag von Jonathan »

Woow, ich saß gerade ungefähr 2 Minuten fassungslos und ungläubig vor meinem Rechner...

Neulich erst hatte ich mal nachgefragt, wie man Partikeleffekte heutzutage am besten umsetzen würde, und hab ewig diesen Thread nicht gefunden. Und dann stellt sich heraus, dass er 3.5 Jahre alt ist, es kam mir ernsthaft eher wie ein halbes Jahr vor...

Wie dem auch sei. Ich habe jetzt einen Vertexbuffer mit den Partikeldaten, einen Geometry-Shader, der daraus Sprites macht und will demnächst einen Compute-Shader schreiben, mit dem ich die Partikel schön animieren kann. Das ist soweit gar nicht so schwer gewesen, und ich denke, dass es auch heutzutage noch extrem performant sein sollte. Aber jetzt habe ich eine Frage:
Der Trick an den Compute-Shadern ist ja, dass man den Buffer nicht ständig updaten muss. Aber jetzt haben Partikel ja eine Lebenszeit, man hat typischerweise einen Emitter und von da fliegen Partikel in alle Richtungen und faden langsam aus. Beim herkömmlichen Rendern hat man halt seine Liste und kann neue Partikel erstellen und alte Löschen und alles ist einfach. Aber wie macht man das, wenn man einen statischen Buffer hat?

Meine spontane Idee ist: Man hat zwei Arten von Partikeleffekten: Kontinuierliche und einmalige. Bei einmaligen sind alle Partikel sofort da und haben eine Lebenszeit. Ist die Zeit abgelaufen, generiert der Geometry-Shader keine Sprites mehr, sind alle Partikel tot, kann der Buffer gelöscht werden. Außerdem könnte man pro Partikel einen Countdown haben, wenn man die Partikel über einen kurzen Zeitraum generieren will. (d.h. sie werden nur angezeigt wenn sie leben, nicht davor und nicht danach).
Für kontinuierliche Effekte macht man etwas ähnliches, nur würden gestorbene Partikel einfach wieder resettet. Die Frage ist natürlich, wo die Werte dafür her kommen, ob man die alten Initialisierungswerte mitschleift, oder im Compute-Shader auch einen kompletten Initialisierungscode inklusiv Zufallsfunktion unterbringt?

Ansonsten: Irgendwelche Tipps, wie man unterschiedliche Systeme am besten/effizientesten organisiert? Partikel haben halt verschiedene Bewegungsmuster und Texturen, spontan hätte ich jetzt für jeden Emitter einen eigenen Buffer und dazugehörigen Shader erstellt (bzw. den Shader wiederverwendet). Aber das treibt ja auch ein wenig die Draw-Calls hoch, je nachdem wie viele Emitter man denn hat (ich kann das momentan noch nicht so ganz abschätzen, aber wenn man einmal mit Partikeln anfängt, will man doch auch seinen Spaß damit haben, oder?).
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: Partikelsystem

Beitrag von Spiele Programmierer »

Ich würde die Partikel einfach mit zwei Buffern verwalten. Da kannst du abswechselnd von einem Buffer in den anderen und wieder zurück die Berechnungen durchführen. Das ermöglicht prinzipiell dann auch Partikelinteraktionen.
Die Partikel in den Ausgabe-Buffer könntest du mit Atomics schreiben. Wird ein Partikel gelöscht, wird einfach der Zähler nicht erhöht und du schreibst einfach nichts in den Ausgabe-Buffer. In OpenGL gibt es ja extra den "AtomicCounterBuffer", der für einen Zähler hier seine Arbeit gut erledigen könnte.

Für das Rendern der Partikel würde ich an deiner Stelle einen Uber-Shader einsetzen, der alle Partikel rendern kann. Du kannst den Partikeln ja Werte wie "Farbe" und "Textur" geben. (Ein Texturarray würde sich anbieten) Wenn es sein muss, ist Dynamic Branching im Shader vermutlich inzwischen auch nicht mehr der Weltuntergang, solange gleichzeitig verarbeitete Fragmente/Vertices(in einem Warp) den gleichen Pfad nehmen.
Benutzeravatar
Ingrater
Establishment
Beiträge: 103
Registriert: 18.04.2007, 21:52

Re: Partikelsystem

Beitrag von Ingrater »

Der Vollständigkeit halber. Für den schnellsten weg mit DX11 quads auf den Bildschirm zu kriegen wird hier vertex shader instancing empfholen (also kein vertexbuffer, generierung über die Vertex-ID und die Daten liegen in einem SRV). Es wird in dieser Präsentation sogar davon abgeraten normales Instancing für Partikel zu verwenden:
http://www.slideshare.net/DevCentralAMD ... l-bilodeau
Antworten