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

Aktuelle Zeit: Fr Jul 18, 2025 11:22

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



Ein neues Thema erstellen Auf das Thema antworten  [ 25 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
 Betreff des Beitrags: FPS Limiter
BeitragVerfasst: Mo Aug 11, 2008 11:53 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
hi,
Ich suche gerade nach einer Möglichkeit eine Beschränkung der FPS in meine Idle Prozedur einzubauen.
Ich habe schon ein paar Ansätze probiert, aber bisher hat nichts so recht funktioniert.
Die Idle Prozedur sieht so aus:
Code:
  1. procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
  2. begin
  3.   MTimer.Update; // Liefert dt (Timestep)
  4.   glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT);
  5.   Init2D;
  6.   glPushMatrix;
  7.     BERECHNUNGEN UND RENDERPROZEDUREN
  8.   glPopMatrix;
  9.   DrawText;
  10.   CheckError;
  11.   Swapbuffers(DC);
  12.   FPSCounter.Update; // Berechnet die FPS
  13.   Done := false;
  14. end;


mfg


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 12:14 
Offline
DGL Member
Benutzeravatar

Registriert: Di Jul 29, 2003 00:11
Beiträge: 436
Vielleicht hilft dir das? Eine kleine Java-Klasse, die einen Thread startet und eigentlich genau das tut, die FPS begrenzen.
Code:
  1.  
  2. package client.glBase;
  3.  
  4. import javax.media.opengl.GLCanvas;
  5.  
  6. /**
  7.  * Eigener FPSAnimator, der in einem Thread läuft und sleep benutzt. Sollte also
  8.  * nicht mehr 100% CPU-Last erzeugen, wenn die ZielFPS erreicht werden. :-D
  9.  */
  10. public final class FPSAnimator extends Thread {
  11.  
  12.     /** Flag, ob der Thread abgebrochen wurde. */
  13.     private boolean aborted;
  14.  
  15.     /** GLCanvas, der aktualisiert werden soll. */
  16.     private GLCanvas glCanvas;
  17.  
  18.     /** Millisekunden, die ein Frame mit der ZielFPS brauchen wird. */
  19.     private long fpsTime;
  20.  
  21.     /**
  22.      * Konstruktor.
  23.      *
  24.      * @param glCanvas
  25.      *            Der GLCanvas.
  26.      * @param targetFPS
  27.      *            Die ZielFPS.
  28.      */
  29.     public FPSAnimator(GLCanvas glCanvas, int targetFPS) {
  30.         this.glCanvas = glCanvas;
  31.         this.fpsTime = 1000 / targetFPS;
  32.     }
  33.  
  34.     /*
  35.      * (non-Javadoc)
  36.      *
  37.      * @see java.lang.Thread#run()
  38.      */
  39.     @Override
  40.     public void run() {
  41.  
  42.         long oldTime;
  43.         long curTime;
  44.  
  45.         this.aborted = false;
  46.  
  47.         // Läuft solange, bis abgebrochen wird.
  48.         while (!this.aborted) {
  49.             oldTime = System.currentTimeMillis();
  50.             this.glCanvas.display();
  51.             curTime = System.currentTimeMillis();
  52.             // Ggf. noch die verbleibende Zeit abwarten, wenn das
  53.             // Framerendern schneller war, als die verfügbare Zeit
  54.             // für ein Frame.
  55.             if (curTime - oldTime < this.fpsTime) {
  56.                 try {
  57.                     Thread.sleep(this.fpsTime - (curTime - oldTime));
  58.                 } catch (InterruptedException e) {
  59.                     this.aborted = true;
  60.                 }
  61.             }
  62.         }
  63.  
  64.     }
  65.  
  66.     /**
  67.      * Thread-Abbruch.
  68.      */
  69.     public void abort() {
  70.         this.aborted = true;
  71.     }
  72.  
  73. }
  74.  


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 12:42 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Ist das nicht ein wenig zu kompliziert ?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 12:48 
Offline
DGL Member
Benutzeravatar

Registriert: Di Jul 29, 2003 00:11
Beiträge: 436
Naja, ansich musst du ja nur den Kern übernehmen, muss ja nicht unbedingt in einem Thread laufen.
Code:
  1.  
  2.          oldTime = System.currentTimeMillis();
  3.          rendern();
  4.          curTime = System.currentTimeMillis();
  5.          // Ggf. noch die verbleibende Zeit abwarten, wenn das
  6.          // Framerendern schneller war, als die verfügbare Zeit
  7.          // für ein Frame.
  8.          if (curTime - oldTime < this.fpsTime) {
  9.                Thread.sleep(this.fpsTime - (curTime - oldTime));
  10.          }
  11.  


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 13:17 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Etwas ähnliches hatte ich schon probiert, allerdings am Anfang der Prozedur:
Code:
  1.   MTimer.Update;
  2.   if MTimer.Timestep < (1/MaxFPS) then
  3.   begin
  4.     d := (1/MaxFPS) - MTimer.Timestep;
  5.     d := d * 1000;
  6.     sleep(round(d));
  7.   end;

irgendwo steckt bei mir noch ein Denkfehler. Ich berechne ja FPS und dt getrennt...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 13:29 
Offline
DGL Member
Benutzeravatar

Registriert: Di Jul 29, 2003 00:11
Beiträge: 436
Naja, du must ja schon messen, wie lange du gebraucht hast, um ein Frame zu rendern.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 14:50 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
tue ich ja auch:
Code:
  1. MTimer.Update;

Code:
  1. procedure TMoveTimer.Update;
  2. var
  3.   FCurrTime: int64;
  4. begin
  5.   QueryPerformanceCounter(FCurrTime);
  6.   FTimestep := min((FCurrTime - FCalcTime) / FFrequency, Flimit);
  7.   FCalcTime := FCurrTime;
  8. end;


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 15:00 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
viewtopic.php?t=5356&start=15

_________________
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 15:23 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Kann ich statt DeltaT mein Timestep benutzen ?

Das müsste die Frames dann ja auf 30 begrenzen (30/1000 = 0,03)
Code:
  1.   if MTimer.Timestep<=0.03 then
  2.   begin
  3.     sleep(1)
  4.     exit;
  5.   end;

Aber dann ruckelt es so sehr, dass ich nichtmal mehr ein Bild bekomme. Kleinere Werte ruckeln weniger, aber es ruckelt halt nur anstatt gescheit zu funktionieren.
Eigentlich ruckelt es immer wenn ich mit den FPS über der Grenze liege.

€: Generell scheint das Problem zu bestehen, dass mein Programm bei höheren FPS Zahlen (sprich mit niedrigerem DeltaT) langsamer läuft, obwohl es das nicht tun sollte.

mfg


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 23:06 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
Miss nur einmal pro frame die Zeit. Und nur in frames die du nicht mit sleep(1)+exit abbrichst.
Bei mir erfolgt die Zuweisung LastTick:=Now; nur falls DeltaT groß genug für nen frame war.

_________________
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Aug 11, 2008 23:22 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Naja aber es kann doch nicht sein, dass ich insgesamt an drei Stellen GetTickCount bzw. den PerfomanceCounter abfragen muss. Kann ich die FPS-Berechnung, Limitierung und die Timestep Berechnung nicht unter einen Hut bringen ?
Und wie kann es sein, dass sich mein Objekt bei höheren FPS langsamer bewegt ?
Code:
  1.   FPosition := v2f_add(FPosition, v2f_add(v2f_scale(FAcceleration, dt * dt * 0.5), v2f_scale(FVelocity, dt)));
  2.   FVelocity := v2f_add(FVelocity, v2f_scale(FAcceleration, dt));    
  3.   FVelocity := v2f_scale(FVelocity, friction);


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Aug 12, 2008 00:06 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
Weil du nicht die korrekte Zeitdifferenz misst. Die Zeit die er in Sleep verbringt zählt bei dir nicht.
Mein code misst die Zeit genau einmal pro frame und der gesamte Timercode ist an einer Stelle konzentriert. Und handhabt afaik alle Fälle korrekt. Was gefällt dir an dem Code nicht?

_________________
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Aug 12, 2008 09:38 
Offline
DGL Member

Registriert: Sa Dez 30, 2006 20:52
Beiträge: 43
Programmiersprache: Delphi
Irgendwo hab ich das mal aufgegriffen zur Berechnung der FPS:

Code:
  1. IsFPS := RoundTo(Freq / (TNow - CalcTime), -2);


Und ich dachte mir jetzt (ich hatte irgendwas ganz kompliziertes, auch mit DeltaT und kA was noch ^^), dann müsste dass doch so gehen:

Code:
  1.   if IsFPS > MaxFPS then
  2.   begin
  3.     Sleep(1);
  4.     Exit;
  5.   end;


Ist das ein Denkfehler? IsFPS ist jetzt tatsächlich etwas kleiner als MaxFPS, aber was mich wundert: Ich hab dann in dem Teil danach mal immer eine Variable um 1 erhöht und das ganze an die Caption ausgegeben. Das ging aber nur 1x pro Sekunde. Etwas langsam?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Aug 12, 2008 10:26 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
The-Winner hat geschrieben:
Weil du nicht die korrekte Zeitdifferenz misst. Die Zeit die er in Sleep verbringt zählt bei dir nicht.
Mein code misst die Zeit genau einmal pro frame und der gesamte Timercode ist an einer Stelle konzentriert. Und handhabt afaik alle Fälle korrekt. Was gefällt dir an dem Code nicht?

Naja selbst ohne das Sleep tritt der Fehler auf ;) Ich dachte ein Framelimiter würde dieses Problem beheben, aber vielleicht gibt es ja noch eine andere Ursache.

Jetzt habe ich es so versucht:
Code:
  1. procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
  2. begin
  3.   if not MTimer.BeginUpdate then
  4.     exit;
  5.   MTimer.EndUpdate;  

Code:
  1. function TMoveTimer.BeginUpdate: boolean;
  2. begin
  3.   result := true;
  4.   QueryPerformanceCounter(FCurrTime);
  5.   FTimestep := min((FCurrTime - FCalcTime) / FFrequency, FMinlimit);
  6.   if FTimestep <= FMaxLimit then
  7.   begin
  8.     sleep(1);
  9.     result := false;
  10.   end;
  11. end;
  12.  
  13. procedure TMoveTimer.EndUpdate;
  14. begin
  15.   FCalcTime := FCurrTime;
  16. end;

(MinLimit war testweise 0,2 und MaxLimit 0,05)
Kein Erfolg, nur tierisches ruckeln.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Aug 13, 2008 15:48 
Offline
DGL Member

Registriert: Sa Dez 30, 2006 20:52
Beiträge: 43
Programmiersprache: Delphi
Was kommt denn bei dir danach? Wie rechnest du die Variable aus, die mit der Bewegung multipliziert wird?


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 25 Beiträge ]  Gehe zu Seite 1, 2  Nächste
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.009s | 15 Queries | GZIP : On ]