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

Aktuelle Zeit: Do Mai 16, 2024 21:01

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 22 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
BeitragVerfasst: Sa Jan 14, 2012 10:12 
Offline
DGL Member

Registriert: Di Mai 10, 2011 19:38
Beiträge: 63
Bei den Tuts und Demos habe ich unterschiedliche Methoden gesehen wie dort die FPS berechnet werden.

Habe zwei Methoden bei mir mal probiert und bekomme zwei unterschiedliche Werte.
Eigentlich müsten diese beide das gleiche ausgeben...

Methode 1: Beim Rendern counter hochzählen
Code:
  1.  
  2.   //Zeitmessung starten für Bewegungsfaktor
  3.   QueryPerformanceCounter(QPCStart);
  4.  
  5.   //FPS Berechnen
  6.   StartTime := GetTickCount;
  7.  
  8.   //Rendern
  9.   inc(gvIntFPSCount);
  10.   if Assigned(AOnRender) then
  11.     AOnRender;
  12.  
  13.   //Ausgabe
  14.   glBaseSwapBuffers;
  15.  
  16.   // Zeitmessung beenden
  17.   QueryPerformanceCounter(QPCEnd);
  18.   glBaseTimeFactor := (QPCEnd-QPCStart) / gvIntQPCFreq * 1000;
  19.  
  20.   //FPS berechnen
  21.   DrawTime := GetTickCount - StartTime;
  22.   Inc(gvIntTimeCount, DrawTime);
  23.   Inc(gvIntFrameCount);
  24.  
  25.   if gvIntTimeCount >= 1000 then begin
  26.     glBaseFPS := gvIntFrameCount;
  27.     gvIntTimeCount := gvIntTimeCount - 1000;
  28.     gvIntFrameCount := 0;
  29.   end;
  30.  


Methode 2: Timer der alle 0,5 Sekunden gestartet wird
Code:
  1.  
  2. SetTimer(0, 0, gvIntFPSTimerInterval, @glBaseIntTimerFPSCallBack);
  3. ...
  4. procedure glBaseIntTimerFPSCallBack(hWnd: HWND; Msg: UINT;  wParam: WPARAM;  lParam: LPARAM); stdcall;
  5. begin
  6.   glBaseFPSTimer := Round(gvIntFPSCount * 1000 / gvIntFPSTimerInterval);
  7.   gvIntFPSCount := 0;
  8. end;
  9.  

gvIntFPSCount wird oben beim Render verändert.

Im Anhang sieht man wie start die Unterschied ist.


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 14, 2012 11:35 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Apr 13, 2011 22:05
Beiträge: 218
Programmiersprache: Lazarus/FPC
Ich würde mal spontan sagen das da bei dir die erste Methode eher stimmt.
2400+ Frames per Second sind da schon mal leicht drin =D

Du kannst es ganz einfach testen indem du deine Grafikkarte dazu zwingst VerticalSynchronisation zu nutzen, sprich genau 60 Bilder/Sekunde zu berechnen.
Dafür musst du einfach nur die Zeile
wglSwapIntervalEXT(1);
irgendwo am Begin einmal hinschreiben!
Dann sollte bei einer korrekten FPS-Berechnung die Zahl bei 58-62 FPS verbleiben!
(Achtung, hab die Erfahrung gemacht das das bei INTEL-Grafikchips in Notebooks oft nicht wirkt. Aber bei 2400+ FPS geh ich mal nicht davon aus das du so einen hast^^)

_________________
Ich teile manchmal heimlich durch Null. - Alber Einstein


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 14, 2012 12:23 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Problem wird sein, dass die Timer nicht sonderlich genau sind und das Timer-Event auch gerne verzögert werden kann. Das gelbe vom ei sind beide Methoden fürchte ich, nicht, da keine beachtet, was passiert, wenn gvIntTimeCount mal signifikant über die 1000 geht.

Wir haben das bei uns so gelöst:
Code:
  1.             if (fpsInterval >= 1.0) {
  2.                 currentFPS = (double)(frameCount) / fpsInterval;
  3.                 frameCounterStart = currentUpdate;
  4.             }

wobei:
frameCount := Frames seit letztem Zurücksetzen der FPS-Zählung
frameCounterStart := Zeitpunkt des letzten Zurücksetzens der FPS-Zählung
fpsInterval := Sekunden seit frameCounterStart

So wird also ca. jede Sekunde die Framezählung neu gestartet. Und wenn fpsInterval mal deutlich größer wird als 1.0 stimmt die berechnung immer noch, da wir durch fpsInterval teilen.

Wichtig ist natürlich auch, dass du einen genauen Counter verwendest. Der PerformanceCounter ist da schon das beste, was man bekommen kann. Leider benutzt du den bei der FPS-Zählung nicht, das solltest du mal ändern.

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: Sa Jan 14, 2012 12:35 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Apr 13, 2011 22:05
Beiträge: 218
Programmiersprache: Lazarus/FPC
Die einfachste Methode um die Frames zu zählen: (die ich übrigens auch benutze)

2 globale Variablen: frames und second, beides Integer.

Code:
  1. //Ausführen bei Programmstart:
  2. Frames := 0;
  3. second := GetTickCount;
  4.  
  5. // Beim Rendern ausführen
  6. inc(Frames);
  7. if GetTickCount > second + 1000 then
  8. begin
  9.   Form1.caption := inttostr(Frames); //Ausgabe der FPS
  10.   Frames := 0
  11.   second := GetTickCount;
  12. end;

_________________
Ich teile manchmal heimlich durch Null. - Alber Einstein


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 14, 2012 14:33 
Offline
DGL Member

Registriert: Di Mai 10, 2011 19:38
Beiträge: 63
Ida hat geschrieben:
wglSwapIntervalEXT(1);
irgendwo am Begin einmal hinschreiben!
Dann sollte bei einer korrekten FPS-Berechnung die Zahl bei 58-62 FPS verbleiben!


Hmmmm jetzt habe ich per Timer 60FPS und der andere FPS Zähler liegt bei über 2000FPS.
Irgendwie funktioniert der Timer besser. Da habe ich nebenbei auch festgestellt das mein time move based auch nicht funktioniert....

//Edit
Der FPS Zähler über 2000 dauert auch super lange bis die Zahl sich aktualisiert. Irgendwie scheint es so als ob GetTickCount nicht richtig funktioniert.

Anwendung ist nonVCL


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 14, 2012 16:15 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Jackie1983 hat geschrieben:
//Edit
Der FPS Zähler über 2000 dauert auch super lange bis die Zahl sich aktualisiert. Irgendwie scheint es so als ob GetTickCount nicht richtig funktioniert.

Wie gesagt, GetTickCount ist relativ ungenau. Gerüchteweise nur auf 40ms, und eine Differenz zwischen zwei GetTickCount-Aufrufen gibt auch gerne 0. Deshalb den PerformanceCounter verwenden, das ist genauer. Damit sollte es gehen.

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 Jan 15, 2012 12:47 
Offline
DGL Member

Registriert: Di Mai 10, 2011 19:38
Beiträge: 63
Irgendwie hängt es schon bei so einfachen sachen :(.

Die FPS und Timebased Movement klappt vorn und hinten nicht. Obwohl ich es genauso mache
wie bei den Tuts im Wiki und dem Bomberman Tut.

Code:
  1.  
  2. Procedure glBaseRender(AOnRender : TglBaseProc);
  3. var
  4.   QPCStart, QPCEnd : Int64;
  5. begin
  6.   QueryPerformanceCounter(QPCStart);
  7.  
  8.   if Assigned(AOnRender) then
  9.     AOnRender;
  10.  
  11.   glBaseSwapBuffers;
  12.  
  13.   QueryPerformanceCounter(QPCEnd);
  14.   glBaseTimeFactor := (QPCEnd-QPCStart) / gvIntQPCFreq * 100;
  15.  
  16.   glBaseFPS := 100 / glBaseTimeFactor;
  17. end;
  18.  


Wenn ich zum Test einfach die Kamera drehen lasse
Code:
  1.  
  2.   glRotated(Counter1, 0, 1, 0);
  3.   Counter1 := Counter1 + 1*glBaseTimeFactor;
  4.  


Bekomme ich mit wglSwapIntervalEXT(1) unterschiedliche Geschwindigkeiten und die FPS bleibt aber immer gleich > 2000 FPS.

Ich verstehe es nicht :(


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jan 16, 2012 17:06 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Die Punkte an denen die misst sind falsch gewählt. Wobei du aber recht hast, das die im Bomberman-Tutorial auch so sind. Also entweder wird da noch was gemacht was ich beim überfliegen nicht gesehen hab' oder es ist tatsächlich falsch beschrieben.

Normalerweise sollte man die Zeitdifferenz aus Werten bestimmen, die an der gleichen Stelle (im Quelltext) gemessen wurden. Dazu brauchst du eine globale Variable die immer die Zeit beim letzten Frame speichert. In eine lokale Variable kommt dann die aktuelle Zeit und aus beiden Werten wird die Differenz gebildet. Zum Schluss schreibt man noch die neue Zeit in die globale Variable, damit sie beim nächsten Frame verfügbar ist. Und dann kann man mit dem nächsten Frame fortfahren.

Wenn man es wie du beschrieben hast macht, wird die Zeit, die zwischen 2 Aufrufen von glBaseRender mit Nichtstun verbracht wird, nicht mit einberechnet. Wenn man die Funktion von einem Timer aus aufruft, der nicht allzu oft tickt, ist diese Zeit besonders groß und die Abweichung enorm.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jan 17, 2012 21:24 
Offline
DGL Member

Registriert: Di Mai 10, 2011 19:38
Beiträge: 63
Ok wenn ich das dann alles richtig verstanden habe, muss ich am anfang irgendwo
QueryPerformanceCounter(CounterStart) schreiben und nach dem Render dann sowas in der Art
Code:
  1.  
  2.   DrawScene;
  3.   inc(FPSCount);
  4.   SwapBuffer;
  5.  
  6.   QueryPerformanceCounter(CounterEnde);
  7.   if (CounterStart-CounterEnde) / QPCFreq * 100 >= 1000 then begin
  8.     FPSNow := FPSCount /  ( (CounterStart-CounterEnde) / QPCFreq);
  9.     QueryPerformanceCounter(CounterStart);
  10.     FPSCount := 0;
  11.   end;
  12.  


Das müste dann doch so passen oder? Muss ich morgen gleich mal probieren....


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jan 19, 2012 22:46 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Das sieht schon ganz gut aus. Allerdings musst du bei den Subtraktionen CounterEnde und CounterStart vertauschen, weil CounterEnde ja immer größer gleich CounterStart ist, aber das hast du vllt schon selbst mitbekommen.
Und als kleine Verbesserung könntest du auch in Zeile 9 einfach "CounterStart:=CounterEnde" schreiben. Ansonsten könnten sich kleine (und eigentlich vernachlässigbare) Abweichungen ergeben. Abgesehen davon ist es aber auch schneller.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jan 20, 2012 11:07 
Offline
DGL Member

Registriert: Di Mai 10, 2011 19:38
Beiträge: 63
Start und Ende habe ich getauscht :wink:
Ne leider haut es so nicht hin. Es kommt als FPS = 0 raus.
Irgendwie sehe ich den Fehler aber noch nicht.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jan 20, 2012 15:45 
Offline
DGL Member

Registriert: Fr Aug 26, 2011 09:26
Beiträge: 25
Programmiersprache: FreePascal
Vielleicht hilft dir dieser Quelltext - der zeigt bei mir zuverlässig die FPS an :D

Code:
  1. // globale Variablen bzw. in der Counter-Class
  2. // FPSZ  : Zählt Renderzyklen
  3. // FPSST : Speichert "Startzeit"
  4.  
  5. procedure UpdateFPS;
  6. Const Rate = 20;
  7. begin
  8.   Inc(FPSZ);
  9.   If FPSZ = Rate then  //Aktualisiert FPS-Anzeige
  10.   begin
  11.     FFPS  := Round(1000 / (SDL_GetTicks - FPSSt) * Rate);
  12.  
  13.     FPSZ := 0;  //Zähler zurücksetzen
  14.     FPSSt := SDL_GetTicks;  // Aktuelle Zeit holen
  15.   end;
  16. end;


Die Funktion wird in der Renderschleife aufgerufen. Rate ist nur dazu da, dass der Code, der bei mir die FPS-Anzeige aktualisiert nicht zu oft aufgerufen wird.
SDL_GetTicks ~ QueryPerformanceCounter

Grundsätzlich:

FPS = 1000 / (StopZeit - StartZeit) * gezeichnete Frames (Zeiten in ms)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jan 20, 2012 16:24 
Offline
DGL Member

Registriert: Di Mai 10, 2011 19:38
Beiträge: 63
d.l.i.w hat geschrieben:
Code:
  1.  
  2.     FFPS  := Round(1000 / (SDL_GetTicks - FPSSt) * Rate);
  3.  

FPS = 1000 / (StopZeit - StartZeit) * gezeichnete Frames (Zeiten in ms)


Hmmmm das kann so doch nicht funktionieren, oder?
Wenn man die Rate ändert kommen andere Wert raus.
Oben in den Sourcen fehlt doch noch "gezeichnete Frames" und die PerformanceFrequency fehlt auch..... so habe ich das zumindestens in den Tuts gesehen....

//Edit
okay nach einem Test mit wglSwapIntervalEXT(1); sieht man das die FPS Zahl nicht stimmen kann.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jan 20, 2012 17:56 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Ich hab' deinen Code von oben mal probiert und bei mir klappt es, zumindest in der korrigierten Fassung.

Code:
  1. inc(FPSCount);
  2. QueryPerformanceCounter(CounterEnde);
  3. if (CounterEnde-CounterStart) / QPCFreq >= 1 then begin
  4.   FPSNow := FPSCount /  ( (CounterEnde-CounterStart) / QPCFreq);
  5.   CounterStart:=CounterEnde;
  6.   FPSCount := 0;
  7. end;

CounterEnde ist eine lokaleVariable, der Rest ist global. Ich hab' außerdem mal die If-Bedingung ein bisschen geändert. Wenn man es wie bei dir oben mit den Zahlen macht, würde sich FPSNow nur alle 10sek aktualisieren (vorausgesetzt man hat Start und Ende auch richtig rum).


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jan 20, 2012 20:04 
Offline
DGL Member

Registriert: Di Mai 10, 2011 19:38
Beiträge: 63
thx.

Jetzt stoße ich von einem zum nächsten Problem, Timebased Movement.
Nach einer Suche hier im Forum hat es wohl mit der CPU zutun, da Mehrkern.

Man soll wohl auch nicht zum Render OnIdle verwenden, sondern eher einen Timer?
Mit wglSwapIntervalEXT(1) teste ich dann meinen Faktor und der stimmt nicht.

Der Faktor sollte doch in etwa so gemessen werden?
Code:
  1.  
  2. QueryPerformanceCounter(Start);
  3. Render;
  4. QueryPerformanceCounter(Ende);
  5. TimeFaktor = (Ende - Start) / frequenz;
  6. ...
  7. TempRotate := TempRotate + 0.2 * TimeFaktor;
  8.  


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


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 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.028s | 17 Queries | GZIP : On ]