Designfragen zu Partikelsystem



  • Hallo zusammen, ich bastle mir gerade ein kleines Partikelsystem und würde euch gerne zwei Dinge dazu fragen.

    1. Ich habe eine Klasse ParticleSystem , die alle Partikel in einem Container hält. Man kann dem System auch Emitter und Affektoren hinzufügen, das geschieht je über eine abstrakte Basisklasse. Wie würdet ihr den Besitz der Emitter und Affektoren festlegen? Mir fallen gerade drei Möglichkeiten ein:

    • In ParticleSystem nur Verweise halten. Der Benutzer ist für die Speicherverwaltung zuständig.
    • Ownership an Partikelsystem übertragen (im Sinne von auto_ptr ). Um nachträglich an den Emittern und Affektoren etwas zu ändern, würde eine Schnittstelle (z.B. Iterator-Range, Visitor, IDs) bereitstehen.
    • shared_ptr benutzen, sodass man nach dem Hinzufügen immer noch Zugriff hat. Allerdings läuft das dann trotzdem oft darauf hinaus, dass der Benutzer selbst einen Container für die shared_ptr s hat.

    Welche Wahl würdet ihr treffen? Oder fällt euch eine andere Möglichkeit ein?

    2. Von der abstrakten Emitter-Basisklasse sind mehrere konkrete Klassen abgeleitet. Diese speichern zum Beispiel Anfangswerte für die Partikel (Farbe, Geschwindigkeit, Lebensdauer etc.). Momentan benutze ich dafür einen Prototyp, also ein Partikel-Objekt, das diese Daten hält und von dem vor dem Emittieren eine Kopie erstellt wird. An dieser Kopie werden dann nur noch geringfügigere Änderungen durchgeführt, wie z.B. Streuwinkel.

    Findet ihr so ein Vorgehen gut? Oder würdet ihr lieber alle Eigenschaften separat speichern und beim Emittieren jedes Mal neu zusammensetzen?

    Falls ihr beim Prototypen bleibt, was für eine Schnittstelle gefällt euch besser?

    emitter->SetParticleColor(color);
    emitter->SetParticleVelocity(velocity);
    emitter->SetParticleLifetime(5.f);
    

    oder

    Particle& particle = emitter->AccessParticlePrototype();
    particle.Color = color;
    particle.Velocity = velocity;
    particle.Lifetime = 5.f;
    

    oder noch was anderes?



  • Mir persönlich würde es besser gefallen, wenn die Besitzrechte der Emitter und Affektoren dem Partikelsystem übertragen würden.
    Somit hätte das PS eher den Charakter eines Containers. Allerdings würde ich die Partikel jedes einzelnen Emitters nicht in einem Container des PS speichern, sondern jeder Emitter verwaltet seine emittierten Partikel selber.
    Das PS wäre dann eher eine Art Controller, der die Affektoren auf die Emitter anwendet, die dann entsprechend die Werte der von Ihnen verwalteten Partikel ändern.

    zu 2.)
    Wie unterscheiden sich die von der abstrakten Basisklasse abgeleiteten Emitterklassen? Nach der Art der von Ihnen emittierten Partikel?
    Die Idee mit dem Partikel-Prototypen gefällt mir ansich recht gut. Wie werden tote Partikel behandelt? Werden diese zerstört und neue Partikel generiert, oder werden die Werte durch eine Reinitialisierung einfach neu gesetzt (was wahrscheinlich schneller gehen würde)?

    Zum Prototypeninterface: mir gefällt die zweite Variante wesentlich besser und ohne es jetzt getestet zu haben ist es wahrscheinlich auch performanter.


  • Mod

    ich halte meine particle auch in einem einzigen container im system, aber ich kenne auch einige engines die das so machen wie inter2k3 sagte.

    ich mache das so um alle particle in einem drawcall zu batchen, die anderen engine machen das in emitern um die emiter untereinander zu sortieren.

    meine 'spawner' und 'fields' (also deine emiter und affektoren) sind dabei nicht im particle system, sondern teile der welt. die beeinflussen alle particlesystems die in reichweite sind, sofern die particlesystem description die flags dafuer gesetzt hat.

    meine version ist eher sowas

    SParticle& pParticle = rParticleSystem.Spawn(&m_Desc);
    

    m_Desc ist vom jeweiligen spawner die spawn beschreibung und falls du NULL uebergibst, wird die default description genommen.
    Das hat fuer mich den vorteil dass ich ueberall in der engine, ohne einen spawner zu haben einen particle erstellen kann, z.b. ist der schuss meiner waffe ein 'spawn'. dazu muss ich nicht irgendwelche werte im emiter oder sowas dauerhaft aendern, ich uebergebe nur die description die ich im play objekt habe (um richtung, position usw. zu uebernehmen)



  • inter2k3 schrieb:

    Mir persönlich würde es besser gefallen, wenn die Besitzrechte der Emitter und Affektoren dem Partikelsystem übertragen würden.
    Somit hätte das PS eher den Charakter eines Containers.

    Was für eine Schnittstelle würdest du dann anbieten, um etwas an den Emittern/Affektoren zu ändern? Und wie werden diese gespeichert (rohe Zeiger, shared_ptr , ...)?

    inter2k3 schrieb:

    Allerdings würde ich die Partikel jedes einzelnen Emitters nicht in einem Container des PS speichern, sondern jeder Emitter verwaltet seine emittierten Partikel selber.

    Da könnte ich jedoch nicht Partikel an unterschiedlichen Orten erzeugen und trotzdem die gleichen Affektoren anwenden. Bei starker Unterscheidung würde man bei meiner Implementierung halt zwei Partikelsysteme erzeugen.

    inter2k3 schrieb:

    Wie unterscheiden sich die von der abstrakten Basisklasse abgeleiteten Emitterklassen?

    Momentan eigentlich nur durch das Gebiet, in dem Partikel erzeugt werden. Je nachdem gibt es unterschiedliche Attribute, z.B. macht die Rotation bei einem Kreisgebiet wenig Sinn.

    inter2k3 schrieb:

    Wie werden tote Partikel behandelt? Werden diese zerstört und neue Partikel generiert, oder werden die Werte durch eine Reinitialisierung einfach neu gesetzt (was wahrscheinlich schneller gehen würde)?

    Zerstört und neu generiert. Ich kann die Partikel nicht immer 1:1 wiederverwenden, da sich die Emittierrate ändern kann. Ausserdem fallen durch die Speicherung im std::vector keine Pro-Element-Allokationskosten an (nur Konstruktion, was etwa gleich teuer wie Zuweisung ist).

    Das Problem bei dem Prototypen ist halt, dass es gewisse Member der Partikelklasse gibt, die nicht sinnvoll gesetzt werden können. Zum Beispiel die Position, welche sich bei der Erzeugung an die Emitterposition anpasst (eine relative Position wäre verwirrend, da der gleiche Member sonst absolute Positionen darstellt). Oder die aktuelle Lebensdauer (welche bei der Erzeugung natürlich immer Null ist).



  • rapso schrieb:

    meine 'spawner' und 'fields' (also deine emiter und affektoren) sind dabei nicht im particle system, sondern teile der welt. die beeinflussen alle particlesystems die in reichweite sind, sofern die particlesystem description die flags dafuer gesetzt hat.

    Das ist auch eine interessante Idee, die muss ich mir für später merken. Momentan sind meine Partikelsyteme nicht so intelligent (man muss Affektoren und Emitter explizit hinzufügen), dafür hat man mehr Kontrolle.

    An dieser Stelle ist mir gerade noch ein Argument für shared_ptr eingefallen: Man kann den gleichen Emitter/Affektor auf mehrere Partikelsysteme anwenden.

    rapso schrieb:

    Das hat fuer mich den vorteil dass ich ueberall in der engine, ohne einen spawner zu haben einen particle erstellen kann, z.b. ist der schuss meiner waffe ein 'spawn'. dazu muss ich nicht irgendwelche werte im emiter oder sowas dauerhaft aendern, ich uebergebe nur die description die ich im play objekt habe (um richtung, position usw. zu uebernehmen)

    Interessant, vor diesem Problem bin ich nämlich auch gestanden (bzw. immer noch). Ich habe festgestellt, dass es manchmal Situationen gibt, in denen eine kontinuierliche Erzeugung nicht vorteilhaft ist. Dafür ist es unpraktisch, die stetigen Emitter jedes Mal neu übergeben zu müssen. Von daher käme am ehesten eine Kombination beider Ansätze in Frage.

    m_Desc enthält also Daten wie Spawngebiet, Anfangsgeschwindigkeit, etc? Lustig ist, dass mir sogar was ziemlich Ähnliches in den Sinn gekommen ist. Zusätzlich zu den kontinuierlichen Erzeugern habe ich mir sowas überlegt:

    void ParticleSystem::EmitOnce(Emitter& emitter);
    

    Dann wird auf einmal alles erzeugt, was sonst eine Sekunde benötigen würde. Ich habe aber meine Zweifel gehabt und die Methode vorläufig entfernt (ohne eine Alternative anzubieten).



  • Grüsse,
    ich wollte mich mal erkundigen, ob du dein PS bereits fertig umgesetzt hast und falls ja, wie?
    Ich selbst werd mir wohl ebenfalls wieder etwas zusammenschustern, da meine alten Systeme mir nicht mehr so recht gefallen.
    Nun überlege ich mir eine Variante, in der alle emittierten Partikel wieder ihrerseits Emitter sind (so eine Art Feuerwerk - unten ein zentraler Emitter, der Partikel schiesst (Raketen), die dann irgendwann explodieren und ihrerseits neue Partikel emittieren). Oder aber sollen sie Affektoren sein (denkbar wären z.b. magnetisch aktive Partikel, die sich gegenseitig anziehen oder abstossen).

    Falls dein Projekt privater Natur war, würdest du vlt. deinen code zur Ansicht bereitstellen? Ich freue mich immer wenn ich code von erfahreneren Programmieren studieren kann und dadurch neue Denkanstösse erhalte 😉

    Grüsse.



  • inter2k3 schrieb:

    Grüsse,
    ich wollte mich mal erkundigen, ob du dein PS bereits fertig umgesetzt hast und falls ja, wie?

    In letzter Zeit bin ich leider nicht gross zum Programmieren gekommen, daher bin ich noch nicht wirklich weiter mit der Entwicklung des Partikelsystems.

    Ich bin mir selbst noch nicht ganz sicher, wie das Design am Schluss aussehen soll. Für die Speicherung von Emittern/Affektoren tendiere immer noch zu shared_ptr , da man Emitter/Affektoren so nach dem Hinzufügen von aussen ändern kann (um z.B. die Position an ein bewegtes Objekt anzupassen). Aber ganz gefällt es mir doch nicht, ich würde gerne einen automatischen Anpassungsmechanismus einbauen, so dass man nur im Ausnahmefall nachträglich direkt auf die Emitter/Affektoren zugreifen muss. Doch ich fürchte, das läuft auf sowas wie einen SceneGraph hinaus, was ich im Moment eher vermeiden möchte...

    inter2k3 schrieb:

    Nun überlege ich mir eine Variante, in der alle emittierten Partikel wieder ihrerseits Emitter sind (so eine Art Feuerwerk - unten ein zentraler Emitter, der Partikel schiesst (Raketen), die dann irgendwann explodieren und ihrerseits neue Partikel emittieren). Oder aber sollen sie Affektoren sein (denkbar wären z.b. magnetisch aktive Partikel, die sich gegenseitig anziehen oder abstossen).

    Die Idee klingt gut! Damit lassen sich wahrscheinlich recht komplexe Situationen relativ einfach realisieren. Ich werde vorerst aber beim konventionellen Ansatz bleiben... Zuerst einmal den richtig hinbekommen 🙂

    inter2k3 schrieb:

    Falls dein Projekt privater Natur war, würdest du vlt. deinen code zur Ansicht bereitstellen? Ich freue mich immer wenn ich code von erfahreneren Programmieren studieren kann und dadurch neue Denkanstösse erhalte 😉

    Das Ganze wird Teil einer OpenSource-Bibliothek. Ich schaue, dass ich sie so schnell wie möglich fertig bekomme. Im Moment würde dir mein Partikelsystem wahrscheinlich nicht allzu viel bringen, da vieles noch wirr und ohne erkennbare Struktur ist... 😉

    Ich kann dich per E-Mail benachrichtigen, wenn es soweit ist.



  • Nexus schrieb:

    Ich kann dich per E-Mail benachrichtigen, wenn es soweit ist.

    Würde mich sehr drüber freuen. Dann wünsche ich viel Erfolg bei der Umsetzung 🙂


Anmelden zum Antworten