Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Mi Jul 16, 2025 11:58

Foren-Übersicht » Programmierung » OpenGL
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 34 Beiträge ]  Gehe zu Seite 1, 2, 3  Nächste
Autor Nachricht
 Betreff des Beitrags: Partikel - Emitter - Wasserfontäne
BeitragVerfasst: Sa Jun 04, 2011 15:32 
Offline
DGL Member

Registriert: Do Apr 22, 2010 17:17
Beiträge: 543
Hallöchen,

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.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jun 04, 2011 16:30 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
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.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jun 04, 2011 20:12 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
jau... sieht das Zeug einfach nicht so fix an Frames festgetackert, sondern mehr als eine Simulation, die komplett unabhängig von Frames ist :)

Oder so...

_________________
"Für kein Tier wird so viel gearbeitet wie für die Katz'."


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 05, 2011 11:16 
Offline
DGL Member
Benutzeravatar

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 networkmy 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


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 05, 2011 11:39 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
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:
  1. position += velocity * timeElapsed;
  2. velocity += acceleration * timeElapsed;

So ca. 30 fps solltest du aber schon haben. Wenn es weniger sind brauchst du wirklich den Subframe-Ansatz.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 05, 2011 21:54 
Offline
DGL Member

Registriert: Do Apr 22, 2010 17:17
Beiträge: 543
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:
  1.  
  2. procedure T3DNozzle.EmitterCall;
  3. var
  4.   I: Integer;
  5. begin
  6.    //richtungsvector berechnen
  7.    dir[0] := 0;
  8.    dir[1] := 1;
  9.    dir[2] := 0;
  10.    dir := RotateVector(MakeAffineVector([x, y, z]), dir, MakeAffineVector([RotX, RotY, RotZ]));
  11.  
  12.  
  13.  //Spawn Partikel
  14.   for I := 0 to EmitterCount do
  15.    begin
  16.      List.Add(T3DPartikel.Create);
  17.     List.Last.Color[0] := 1.0;
  18.     List.Last.Color[1] := 1.0;
  19.     List.Last.Color[2] := 1.0;
  20.     List.Last.dir := VectorAffineAdd(dir, GetRandomVEctor(FSpray) );
  21.     List.Last.gravity := FPower;
  22.     List.Last.pos :=  MakeAffineVector([x, y, z]);
  23.    end;
  24. //Partikelposition aktualisieren
  25.     for I := 0 to List.Count - 1 do
  26.      begin
  27.       list[i].pos[0] := list[i].pos[0] + (List[i].dir[0] * FSpeed);
  28.       list[i].pos[1] := list[i].pos[1] + (List[i].dir[1] +  List[i].gravity) * FSpeed;
  29.       list[i].pos[2] := list[i].pos[2] + (List[i].dir[2]  * FSpeed);
  30.       List[i].gravity := list[i].gravity - fGravity;
  31.      end;
  32.  
  33.     i:=0;
  34.  
  35.      while i<list.Count do
  36.       begin
  37.        if list[i].coll  then
  38.         List.Delete(i)
  39.          else
  40.       if List[i].Pos[1] < 0 then
  41.        begin
  42.         List[i].pos[1] := -List[i].pos[1] / 5;
  43.         list[i].Coll:=true;
  44.        end;
  45.       inc(i);
  46.       end;
  47. end;
  48.  


Wie soll ich da jetzt einen timefactor einbringen?


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 05, 2011 22:37 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
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.

Ggf. solltest du auch über ein GPU-Partikelsystem nachdenken, zumindest wenn du noch nebenher was anderes machen willst.
http://wiki.delphigl.com/index.php/GLSL_Partikel_2

Zitat:
Wie soll ich da jetzt einen timefactor einbringen?

Nach Zeile 22:
Code:
  1. FSimTime := I / EmitterCount;
  2. List.Last.pos[0] := List.Last.pos[0] + (List.Last.dir[0] * FSpeed * FSimTime);
  3. List.Last.pos[1] := List.Last.pos[1] + (List.Last.dir[1] +  List.Last.gravity) * FSpeed * FSimTime;
  4. List.Last.pos[2] := List.Last.pos[2] + (List.Last.dir[2]  * FSpeed * FSimTime);
  5. List.Last.gravity := List.Last.gravity - fGravity * FSimTime;


(*) sollte eigentlich in den Bordmitteln jeder Programmiersprache verfügbar sein. Ist im Zweifel aber auch flux implementiert. Wikipedia hilft.


Edit: Das muss natürlich I / EmitterCount sein und nicht 1 / EmitterCount.

_________________
Yeah! :mrgreen:


Zuletzt geändert von Coolcat am Mo Jun 06, 2011 07:55, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 05, 2011 22:47 
Offline
DGL Member
Benutzeravatar

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 networkmy 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


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 05, 2011 23:00 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
@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...

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 06, 2011 06:06 
Offline
DGL Member

Registriert: Di Sep 07, 2010 14:28
Beiträge: 34
Wohnort: Frankfurt
Programmiersprache: C++,C#,VB(,Delphi)
Code:
  1.  
  2.  //Spawn Partikel
  3.   for I := 0 to EmitterCount do
  4.    begin
  5.      List.Add(T3DPartikel.Create);
  6.     List.Last.Color[0] := 1.0;
  7.     List.Last.Color[1] := 1.0;
  8.     List.Last.Color[2] := 1.0;
  9.     List.Last.dir := VectorAffineAdd(dir, GetRandomVEctor(FSpray) );
  10.     List.Last.gravity := FPower;
  11.     List.Last.pos :=  MakeAffineVector([x, y, z]);
  12. /* HIER */
  13.    end;
  14.  


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?

Code:
  1.  
  2. //Partikelposition aktualisieren
  3.     for I := 0 to List.Count - 1 do
  4.      begin
  5.       list[i].pos[0] := list[i].pos[0] + (List[i].dir[0] * FSpeed);
  6.       list[i].pos[1] := list[i].pos[1] + (List[i].dir[1] +  List[i].gravity) * FSpeed;
  7.       list[i].pos[2] := list[i].pos[2] + (List[i].dir[2]  * FSpeed);
  8.       List[i].gravity := list[i].gravity - fGravity;
  9.      end;
  10.  

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.

_________________
Das mit dem Dx tut mir leid.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jun 21, 2011 12:24 
Offline
DGL Member

Registriert: Do Apr 22, 2010 17:17
Beiträge: 543
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...


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jun 21, 2011 12:56 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
wie soll das mit dem 2 Listen und Swap aussehen? (...) Kenne keine Swap Methode?

Code:
  1. tmp = list[i];
  2. list[i] = list[j];
  3. list[j] = tmp;

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jun 24, 2011 14:25 
Offline
DGL Member

Registriert: Do Apr 22, 2010 17:17
Beiträge: 543
könnt ihr mir nochn Tipp geben wie ich die Partikel-Zeichenroutine beschleunigen kann?

Code:
  1.  
  2.  
  3. procedure T3DNozzle.DrawPartikel;
  4. var
  5.   I: Integer;
  6. begin
  7.  glPointSize(ThickNess);
  8.  glPushMAtrix;
  9.  glLoadIdentity;
  10.   glMultMatrixf(@glCore.CoreEngine.CamMatrix);
  11.  
  12.   glEnable(GL_BLEND);
  13.     glBlendFunc( GL_DST_ALPHA, GL_ONE );
  14.   glDepthMask(false);
  15.  
  16.  glDisable(GL_LIGHTING);
  17.  glEnable(GL_TEXTURE_2D);
  18.   DrawDirVector;
  19.   glEnable(GL_POINT_SPRITE);
  20.   glColor4f(red, green, blue, 0.3);
  21.  glCore.CoreEngine.dropTex.Bind();
  22.   glBegin(GL_POINTS);
  23.   for I := 0 to list.Count - 1 do
  24.     begin
  25.      glVertex3f(List[i].pos[0], list[i].pos[1], list[i].pos[2]);
  26.     end;
  27.   glEnd;
  28.   glDisable(GL_BLEND);
  29.  
  30.   glDisable(GL_POINT_SPRITE);
  31.   gldepthMask(true);
  32.  glDisable(GL_TEXTURE_2D);
  33.  glEnable(GL_LIGHTING);
  34.  glPopMatrix;
  35. end;
  36.  


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jun 24, 2011 16:09 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
könnt ihr mir nochn Tipp geben wie ich die Partikel-Zeichenroutine beschleunigen kann?

Benutze ein dynamisches VBO. Der Immediate Mode ist recht lahm.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jun 24, 2011 17:35 
Offline
DGL Member

Registriert: Do Apr 22, 2010 17:17
Beiträge: 543
kann da die Vertex anzahl variiren?


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 34 Beiträge ]  Gehe zu Seite 1, 2, 3  Nächste
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

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.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.011s | 16 Queries | GZIP : On ]