ich arbeite grade an der Simulation einer Wasserfontäne. Allerdings lässt meine Partikelengine noch zu Wünschen übrig. An bei mal ein Foto. Wie ihr seht entstehen bei hohem Speed große Abstände... Kennt jemand das Problem? Was gibt es sonst für Ansätze um dies etwas smoother zu machen??
Dateianhang:
Partikel.JPG
Grüße Thomas
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Ich vermute mal du spawnst in jedem Frame einige Partikel, richtig? Warum spawnst du nicht verteilt über das Frame? Sagen wir mal ein Frame dauert S Sekunden und du willst P Partikel im Frame spawnen.
Bei jedem Partikel i simulierst du direkt beim spawnen schon eine Lebenszeit von i * (S / P) Sekunden. D.h. Partikel 0 spawnt normal, während die folgenden Partikel aber schon virtuell einen Bruchteil eines Frames gelebt haben.
Für mehr Variation kannst du diese virtuelle Lebenszeit natürlich auch zufällig machen.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Genau, Stichwort Subframe Sampling. Du teilst die Frames in Subframes einer Länge, die abhängig von der Spawnrate ist. Wenn du pro Sekunde 100 Partikel spawnen willst und 50FPS hast, musst du 100/50=2 Subframes simulieren, um regelmäßig zu spawnen. Pro Subframe musst du praktisch die komplette Partikelengine durchlaufen lassen, wenn die Physik komplexer ist und die Bewegungskurve nicht als einfache Funktion der Zeit dargestellt werden kann (oder will). Vorsicht aber, wenn es zu viele Partikel werden, kann Subframe Sampling dir mit jedem Frame mehr Arbeit verschaffen und den Rechner einer Rückkopplung gleich in die Knie zwingen. Daher sollte man die Anzahl der Subsamples beschränken.
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Pro Subframe musst du praktisch die komplette Partikelengine durchlaufen lassen, wenn die Physik komplexer ist und die Bewegungskurve nicht als einfache Funktion der Zeit dargestellt werden kann (oder will).
Sofern die Partikel nur fürs Auge sind reicht es die Bewegung nur pro Frame (nicht pro Subframe) zu aktualisieren. Nur beim spawnen musst du die entsprechende Zeit simulieren, was aber auch in einem einzigen Schritt geht. Letztlich brauchst du nur eine Funktion die einen Partikel entsprechend einem Wert "timeElapsed" simuliert. In der Regel reicht da einfach:
Code:
position += velocity * timeElapsed;
velocity += acceleration * timeElapsed;
So ca. 30 fps solltest du aber schon haben. Wenn es weniger sind brauchst du wirklich den Subframe-Ansatz.
Coolcat sein Ansatz gefällt mir. Also rund ne halbe mio Partikel sollten kein Problem darstellen.. ggf. muss ich die berechnung noch auf mehrere Threads auslagern..
hier mal der Code zu meiner aktuellen berechnung:
Code:
procedure T3DNozzle.EmitterCall;
var
I: Integer;
begin
//richtungsvector berechnen
dir[0] := 0;
dir[1] := 1;
dir[2] := 0;
dir := RotateVector(MakeAffineVector([x, y, z]), dir, MakeAffineVector([RotX, RotY, RotZ]));
Coolcat sein Ansatz gefällt mir. Also rund ne halbe mio Partikel sollten kein Problem darstellen.. ggf. muss ich die berechnung noch auf mehrere Threads auslagern..
Aktuell scheinst du da ein dynamisches Array zu benutzen. Ich bin kein Delphi/FPC User und weiß daher nicht wie die delete-Operation implementiert ist, aber bei einem dynamischen Array würde man üblicherweise alle nachfolgenden Werte um eins aufrücken. D.h. im Durchschnitt schreibst du da mal eben das halbe Array neu. Bei einer halben Mio. Partikeln solltest du dir sowas gut überlegen! Eine sinnvollere Lösung könnte etwa sein den "gelöschten" Partikel lieber irgendwo ins unendliche zu schieben damit er nicht gerendert wird. Sobald du wieder einen neuen Partikel spawnst, schreibe ihn an diese Stelle. Dafür solltest du natürlich nicht immer das gesamte Array scannen sondern eine z.B. Heap-Datenstruktur (*) der freien Positionen verwalten. Damit kannst du dann leicht/schnell jeweils die erste freie Position holen.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Coolcat hat geschrieben:
Aktuell scheinst du da ein dynamisches Array zu benutzen. Ich bin kein Delphi/FPC User und weiß daher nicht wie die delete-Operation implementiert ist, aber bei einem dynamischen Array würde man üblicherweise alle nachfolgenden Werte um eins aufrücken.
Dynamische Arrays kennen weder delete noch add, daher tippe ich auf ne TList oder so. Jedenfalls stimmt was Coolcat sagt… Objekte allokieren und freigeben kostet relativ viel Zeit. Es lohnt sich für Partikel, die „toten“ Partikel nur in eine andere Liste zu schieben und immer, wenn ein neuer gebraucht wird, erstmal alte aus dieser Liste zu recyclen. Die zu rendernden Partikel kann man vermutlich am effizientesten aus den aktiven Listen holen, indem man die Swap-Methode nutzt, sofern die Sortierung irrelevant ist. Dann würde man einen sterbenden Partikel per Swap ans Ende der Liste verschieben und dort löschen, das erspart das verschieben der kompletten Liste nach vorne. Wenn man Swap (oder Exchange heißt es glaube ich) nimmt hat man den Vorteil, dass überhaupt keine verschiebung notwendig ist. Wenns diese Methode nicht gibt ist das natürlich auch schnell selber implementiert.
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
@Lord Horazont: Ups...das mit dem Swap ist natürlich viel einfacher/schneller als die Sache mit dem Heap. Wieso ist mir das nicht eingefallen? Hab wieder zu kompliziert gedacht...
Könnte man nicht bei HIER eine Berechnung, die du bei allen Patikeln zu Positionsaktualisierung machst, mit einem Random Timebase Movement Wert machen? FSpeed ist dein doch dein Timebased Movement Wert, oder?
Das hier lässt sich, denke ich noch Optimieren, indem du list[i] in einem Pointer speicherst und dann über den Pointer darauf zugreifst. Dadurch sparst du dir mehrere Multiplikationen.
wie soll das mit dem 2 Listen und Swap aussehen? Hab schon versucht die gestrobenen Partikel nur zu markieren und dann beim erzeugen nach toten Partikeln zu suchen, doch das Suchen in der Liste verlangsamt nur... Kenne keine Swap Methode?
EDIT: Es gibt eine Move Methode welche ein Element verschiebt, allerdings wird da auch Delete ausgeführt und alle nachfolgenden Elemente werden wieder dran geschoben...
Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.