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

Aktuelle Zeit: Mo Jul 14, 2025 11:41

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



Ein neues Thema erstellen Auf das Thema antworten  [ 9 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Partikel Emitter tuts net Oo
BeitragVerfasst: Fr Jul 28, 2006 13:16 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Hi, ich habe mir einen kleinen Partikelemitter geschrieben, aber so richtig tut er es nicht.
man sollte zunächst einmal 2 keyframes angeben können (anfang und ende), die position, die richtung,
den grad der streuung, lebensdauer etc. aber ich sehe nichts, und als ich ein bild hatte, hats net so funktioniert wie es sollte und nach einiger zeit bekam ich eine fehlermeldung. jemand ne idee ?

TVector2D ist einfach ein record
Code:
  1.  
  2. function angle_to_v2d(angle: single): TVector2D;
  3. begin
  4.   result := to_v2d(cos(degtorad(angle)), sin(degtorad(angle)));
  5. end;
  6.  

Code:
  1.  
  2. // Unit ParticleEngine
  3. (**************************************************
  4.  
  5. - Enthält: TParticleEmitter
  6.  
  7. **************************************************)
  8.  
  9. unit F2D_ParticleEngine;
  10.  
  11. interface
  12.  
  13. uses
  14.   dglOpenGL,
  15.   graphics,
  16.   F2D_Vectors,
  17.   F2D_Math,
  18.   F2D_Colors,
  19.   F2D_Core,
  20.   F2D_Const;
  21.  
  22. type
  23.   TKeyFrame = record
  24.     velocity: single;
  25.     alpha: single;
  26.     size: TVector2D;
  27.   end;
  28.  
  29.   TParticle = record
  30.     dir,
  31.     position: TVector2D;
  32.     age: single;
  33.   end;
  34.  
  35.   TParticleEmitter = class
  36.     constructor Create(pEngine: TEngine);
  37.     procedure Free;
  38.   private
  39.     FEngine: TEngine;
  40.     FAngle,
  41.     FEmissionAngle: integer;
  42.     FParticle: TParticle;
  43.     FParticles: array of TParticle;
  44.     EmissionTime: single;
  45.     FLifeSpan: single;
  46.     function GetParticleCount: integer;
  47.     procedure Add(pParticle: TParticle);
  48.     procedure SetLifeSpan(const Value: single);
  49.     procedure CleanUp;
  50.     procedure SetAngle(const Value: integer);
  51.     procedure SetEmissionAngle(const Value: integer);
  52.     procedure NextStep;  
  53.   public
  54.     position: TVector2D;
  55.     EmissionRate,
  56.     ParticlesPerEmission: integer;
  57.     LifeBegin,
  58.     LifeEnd: TKeyFrame;
  59.     Texture: string;
  60.     Color: TColor;
  61.     z: integer;
  62.     property Angle: integer read FAngle write SetAngle;
  63.     property EmissionAngle: integer read FEmissionAngle write SetEmissionAngle;
  64.     property LifeSpan: single read FLifeSpan write SetLifeSpan;
  65.     property NumParticles: integer read GetParticleCount;
  66.     procedure Render;
  67.   end;
  68.  
  69. implementation
  70.  
  71. constructor TParticleEmitter.Create(pEngine: TEngine);
  72. begin
  73.   inherited Create;
  74.   FEngine := pEngine;
  75.   setlength(FParticles, 0);
  76.   FAngle := 0;
  77.   FEmissionAngle := 0;
  78.   EmissionTime := 0;
  79.   FLifeSpan := 0;
  80.   Emissionrate := 0;
  81.   ParticlesPerEmission := 0;
  82.   Color := clwhite;
  83.   z := 0;
  84. end;
  85.  
  86. function TParticleEmitter.GetParticleCount: integer;
  87. begin
  88.   result := length(FParticles);
  89. end;
  90.  
  91. procedure TParticleEmitter.SetLifeSpan(const Value: single);
  92. begin
  93.   if Value > 0 then
  94.     FLifeSpan := Value;
  95. end;
  96.  
  97. procedure TParticleEmitter.CleanUp;
  98. var
  99.   i, j: integer;
  100. begin
  101.   for i := 0 to high(FParticles) do
  102.     if FParticles[i].Age >= FLifeSpan then
  103.     begin
  104.       for j := i to high(FParticles) - 1 do
  105.         FParticles[j] := FParticles[j + 1];
  106.       setlength(FParticles, length(FParticles) - 1);
  107.     end;
  108. end;
  109.  
  110. procedure TParticleEmitter.Add(pParticle: TParticle);
  111. begin
  112.   setlength(FParticles, length(FParticles) + 1);
  113.   FParticles[high(FParticles)] := pParticle;
  114. end;
  115.  
  116. procedure TParticleEmitter.Free;
  117. begin
  118.   if Self <> nil then
  119.     Destroy;
  120. end;
  121.  
  122. procedure TParticleEmitter.SetAngle(const Value: integer);
  123. begin
  124.   if (Value >= 360) OR (Value <= -360) then
  125.   begin
  126.     FAngle := 0;
  127.     Exit;
  128.   end;
  129.   if Value < 0 then
  130.   begin
  131.     FAngle := 360 + Value;
  132.     Exit;
  133.   end;
  134.  
  135.   FAngle := Value;
  136. end;
  137.  
  138. procedure TParticleEmitter.SetEmissionAngle(const Value: integer);
  139. begin
  140.   if (Value >= 360) OR (Value <= -360) then
  141.   begin
  142.     FEmissionAngle := 0;
  143.     Exit;
  144.   end;
  145.   if Value < 0 then
  146.   begin
  147.     FEmissionAngle := 360 + Value;
  148.     Exit;
  149.   end;
  150.  
  151.   FEmissionAngle := Value;
  152. end;
  153.  
  154. procedure TParticleEmitter.NextStep;
  155. var
  156.   i, c: integer;
  157.   vel: single;
  158. begin
  159.   //Emissionszeit erhöhen
  160.   EmissionTime := EmissionTime + FEngine.Timestep;
  161.   //Partikel Emittieren
  162.   if round(EmissionTime / EmissionRate) = 0 then
  163.     for c := 1 to ParticlesPerEmission do
  164.     begin
  165.       with FParticle do
  166.       begin
  167.         dir := v2d_normalize(angle_to_v2d(random(EmissionAngle) - 90 + Angle));
  168.         age := 0;
  169.       end;
  170.       FParticle.position := position;
  171.       Add(FParticle);    
  172.       EmissionTime := 0;
  173.     end;
  174.   //Bewegen
  175.   for i := 0 to high(FParticles) do
  176.     with FParticles[i] do
  177.     begin
  178.       age := age + FEngine.Timestep;
  179.       vel := (age * (LifeEnd.velocity - LifeBegin.velocity)) / FLifeSpan;
  180.       position.x := position.x + dir.x * vel;
  181.       position.y := position.y + dir.y * vel;
  182.     end;
  183.   CleanUp;
  184. end;
  185.  
  186. procedure TParticleEmitter.Render;
  187. var
  188.   i: integer;
  189.   TmpWidth, TmpHeight: Extended;
  190.   size: TVector2D;
  191.   alpha: single;
  192. begin
  193.   NextStep;
  194.   glPushMatrix;
  195.  
  196.   for i := 0 to high(FParticles) do
  197.   begin
  198.    alpha := (FParticles[i].age * (LifeEnd.alpha - LifeBegin.alpha)) / FLifeSpan;
  199.  
  200.     // Matrix auf die Zeichenposition setzen
  201.     glTranslatef(FParticles[i].Position.X * (FEngine.Form.ClientWidth / FEngine.Width),
  202.                  FParticles[i].Position.Y * (FEngine.Form.ClientHeight / FEngine.Height), 0);
  203.  
  204.     FEngine.TextureManager.BindTexture(Texture);
  205.  
  206.     RGBAf(Color, round(alpha));
  207.     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  208.     glEnable(GL_BLEND);
  209.  
  210.     size.x := (FParticles[i].age * (LifeEnd.size.x - LifeBegin.size.x)) / FLifeSpan;
  211.     size.y := (FParticles[i].age * (LifeEnd.size.y - LifeBegin.size.y)) / FLifeSpan;
  212.  
  213.     TmpWidth  := (Size.X * (FEngine.Form.ClientWidth  / FEngine.Width))  / 2;
  214.     TmpHeight := (Size.Y * (FEngine.Form.ClientHeight / FEngine.Height)) / 2;
  215.  
  216.     glBegin(GL_QUADS);
  217.       glTexCoord2f(0,1); glVertex3f(-TmpWidth, -TmpHeight, Z - MaxDepth + 2);
  218.       glTexCoord2f(1,1); glVertex3f( TmpWidth, -TmpHeight, Z - MaxDepth + 2);
  219.       glTexCoord2f(1,0); glVertex3f( TmpWidth,  TmpHeight, Z - MaxDepth + 2);
  220.       glTexCoord2f(0,0); glVertex3f(-TmpWidth,  TmpHeight, Z - MaxDepth + 2);
  221.     glEnd;
  222.   end;
  223.  
  224.   glDisable(GL_BLEND);
  225.  
  226.   glPopMatrix;
  227. end;
  228.  
  229. Initialization
  230.   randomize;
  231.  
  232. end.
  233.  

und die Engine liefert nur timestep und streckung für die fenster, sonst ist der code halbwegs eigenständig.

mfg und danke, ich bin irgendwie schon total am verzweifeln :(


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Jul 28, 2006 13:42 
Offline
Ernährungsberater
Benutzeravatar

Registriert: Sa Jan 01, 2005 17:11
Beiträge: 2068
Programmiersprache: C++
Vielleicht solltest du uns noch verraten, was für eine Fehlermeldung kommt, und an welcher Stelle sie auftritt.
Auch halte ich den Code hier für riskant:
Code:
  1. for i := 0 to high(FParticles) do
  2.     if FParticles[i].Age >= FLifeSpan then
  3.     begin
  4.         for j := i to high(FParticles) - 1 do
  5.         FParticles[j] := FParticles[j + 1];
  6.         setlength(FParticles, length(FParticles) - 1);
  7.     end;

Hier hängt es wirklich vom (intelligenten) Compiler ab, ob der Code so läuft.

Und könnte es sein, dass du einfach Size zu klein und MaxDepth zu gross gewählt hast?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Jul 28, 2006 14:32 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
i0n0s hat geschrieben:
Vielleicht solltest du uns noch verraten, was für eine Fehlermeldung kommt, und an welcher Stelle sie auftritt.
Auch halte ich den Code hier für riskant:
Code:
  1. for i := 0 to high(FParticles) do
  2.     if FParticles[i].Age >= FLifeSpan then
  3.     begin
  4.         for j := i to high(FParticles) - 1 do
  5.         FParticles[j] := FParticles[j + 1];
  6.         setlength(FParticles, length(FParticles) - 1);
  7.     end;



Also in Delphi wird der Code wohl kaum wie erwünscht funktionieren, da die Parameter von FOR-Schleifen nur einmal berechnet werden. Er würde wohl funktionieren wenn du die erste schleife auf rückwärtszählen ändern würdest.
Trotzdem ist der Algo so nicht gerade effizient (O(N^2)) und dazu noch viele SetLength.

Probier mal folgendes (Achtung ungetestet), sollte aber funzen
Code:
  1.  
  2. j:=0;
  3. for i:=0 to high(FParticles)do
  4.  if FParticles[i].Age<FLifeSpan then
  5.   begin
  6.    FParticles[j]:=FParticles[i];
  7.    inc(j);
  8.   end;
  9. setlength(FParticles,j);
  10.  


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Jul 28, 2006 15:27 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
i0n0s hat geschrieben:
Vielleicht solltest du uns noch verraten, was für eine Fehlermeldung kommt, und an welcher Stelle sie auftritt.
Auch halte ich den Code hier für riskant:
Code:
  1. for i := 0 to high(FParticles) do
  2.     if FParticles[i].Age >= FLifeSpan then
  3.     begin
  4.         for j := i to high(FParticles) - 1 do
  5.         FParticles[j] := FParticles[j + 1];
  6.         setlength(FParticles, length(FParticles) - 1);
  7.     end;

Hier hängt es wirklich vom (intelligenten) Compiler ab, ob der Code so läuft.

Und könnte es sein, dass du einfach Size zu klein und MaxDepth zu gross gewählt hast?


im moment tritt kein fehler auf, und ich dachte mir, dass diese stelle probleme macht, ich werde mal the-winners lösung testen

//EDIT: habs getestet, leider immer noch nichts zu sehen, das setup sieht so aus:
Code:
  1.  
  2.   Emitter := TParticleEmitter.Create(Engine);
  3.   with Emitter do
  4.   begin
  5.     position := to_v2d(Engine.width / 2, Engine.Height / 2);
  6.     angle := 0;
  7.     emissionangle := 180;
  8.     Emissionrate := 5000;
  9.     ParticlesPerEmission := 12;
  10.     Texture := 'spark';
  11.     LifeSpan := 5000;
  12.  
  13.     with LifeBegin do
  14.     begin
  15.       velocity := 100;
  16.       alpha := 255;
  17.       size := to_v2d(25, 25);
  18.     end;
  19.  
  20.     with LifeEnd do
  21.     begin
  22.       velocity := 0;
  23.       alpha := 0;
  24.       size := to_v2d(25, 25);
  25.     end;
  26.    
  27.   end;
  28.  


und an size und maxdepth liegt es nicht, da diese auch bei normalen objekten funktionieren,
korrekterweise muss beim zeichnen auch ein z / maxdepth + 1 dahin, statt + 2
maxdepth ist 512

man merkt aber, wie der emitter zunehmend fps schluckt und letztenendes konstant bleibt, nur irgendetwas
stimmt net....


es liegt an der interpolation von LifeBegin und LifeEnd, wenn ich das weglasse, funktioniert es zum teil, die größe ist dann einfach zu klein
Code:
  1.  
  2.     size.x := (FParticles[i].age * (LifeEnd.size.x - LifeBegin.size.x)) / FLifeSpan;
  3.     size.y := (FParticles[i].age * (LifeEnd.size.y - LifeBegin.size.y)) / FLifeSpan;
  4.  
  5.     TmpWidth  := (Size.X * (FEngine.Form.ClientWidth  / FEngine.Width))  / 2;
  6.     TmpHeight := (Size.Y * (FEngine.Form.ClientHeight / FEngine.Height)) / 2;
  7.  


hier gibts das komplette projekt zum download:

http://www.exec-dev.de/ParticleEngine.zip

manchmal sieht man sogar viele partikel, aber das ist alles net so wie gewollt


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Jul 31, 2006 12:54 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
ich stehe leider immernoch ratlos davor und weiß net, was ich noch machen soll :/


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Jul 31, 2006 15:33 
Offline
Ernährungsberater
Benutzeravatar

Registriert: Sa Jan 01, 2005 17:11
Beiträge: 2068
Programmiersprache: C++
Also ohne Doku gehe ich deinen Code nicht weiter durch.
Aber das ist mir bisher aufgefallen:
Code:
  1.   glPushMatrix;
  2.  
  3.   for i := 0 to high(FParticles) do
  4.   begin
  5.    .
  6.    // Matrix auf die Zeichenposition setzen
  7.     glTranslatef(FParticles[i].Position.X * (FEngine.Form.ClientWidth / FEngine.Width),
  8.                  FParticles[i].Position.Y * (FEngine.Form.ClientHeight / FEngine.Height), 0);
  9.    .
  10.    .
  11.    .
  12.   end;
  13.    .
  14.   glPopMatrix;

Ist natürlich die perfekte Routine um die Position der Partikel zu setzen. Oder hängen die alle relativ von ihrem Vorgänger ab?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Jul 31, 2006 15:42 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
ich verstehe nicht genau was du meinst, das translaten mache ich damit sich die größe am ende der fenstergröße anpasst, man kann dafür auch glScalef nehmen, aber ich hab das erstmal so gemacht.

ich denke probleme macht sowas hier:
Code:
  1.  
  2. (FParticles[i].age * (LifeEnd.size.x - LifeBegin.size.x)) / FLifeSpan
  3.  


man gibt ja die größe / geschwindigkeit etc für anfang und ende des lebens eines partikels an, und jetzt soll eben anhand des alters des partikels, die geschwindigkeit etc interpoliert werden, beispiel:

geg:
geschwindigkeit am anfang: 100

geschwindigkeit am ende: 0

lebensdauer: 1000 ms

ges:

geschwindigkeit zum zeitpunkt X

bei 500ms wäre das dann 50


eine dokumentation gibts, wenn das alles fertig ist, bzw wenn text und partikel engine funzen, dann schreiben ich noch ein paar samples und dokumentier den ganzen kram, ich kann aber in die partikel unit noch ein paar kommentare setzen


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Jul 31, 2006 15:45 
Offline
Ernährungsberater
Benutzeravatar

Registriert: Sa Jan 01, 2005 17:11
Beiträge: 2068
Programmiersprache: C++
Seth hat geschrieben:
ich verstehe nicht genau was du meinst, das translaten mache ich damit sich die größe am ende der fenstergröße anpasst, man kann dafür auch glScalef nehmen, aber ich hab das erstmal so gemacht.

Du hast 2 Partikel. Das erste wird korrekt mit Abstand vom Ursprung gezeichnet (mit deiner Skalierung). Das zweite wird aber nicht mehr korrekt gezeichnet, da es nicht vom Ursprung aus verschoben wird, sondern von der Position des ersten Partikels.
Daher wirst du wohl alle Partikel gezeichnet haben, nur sind diese irgendwo im nichtsichtbaren Bereich.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Jul 31, 2006 15:51 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
ups, ich sehe, push und popmatrix müssen in die schleife ^^ ok hätten wir das gelöst ^^ dann fehlen noch die interpolationen
und bewegen tut sich auch grad nichts, aber wir werden sehen ^^


EDIT: ja es lag an der berechnung, es fehlte überall noch ein LifeBegin + davor


hier gibts jetzt ne schöne demo zu sehen: http://www.exec-dev.de/


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 9 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 7 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 ]