Was ist ein guter Algorithmus zur Berechnung von Bildern pro Sekunde in einem Spiel? Ich möchte es als Zahl in der Ecke des Bildschirms anzeigen. Wenn ich mir nur ansehe, wie lange es gedauert hat, den letzten Frame zu rendern, ändert sich die Zahl zu schnell.
Bonuspunkte, wenn Ihre Antwort jedes Bild aktualisiert und nicht anders konvergiert, wenn die Bildrate steigt oder sinkt.
last_frame
bedeutet nicht (oder sollte zumindest nicht bedeuten) die Dauer des vorherigen Frames; Es sollte den Wert bedeuten, dentime
Sie für den letzten Frame berechnet haben. Auf diese Weise werden alle vorherigen Frames eingeschlossen, wobei die neuesten Frames am stärksten gewichtet werden.Das habe ich in vielen Spielen verwendet.
quelle
tickindex = (tickindex + 1) % MAXSAMPLES;
Na klar
Wie Sie bereits betont haben, gibt es große Unterschiede in der Zeit, die zum Rendern eines einzelnen Frames benötigt wird, und aus Sicht der Benutzeroberfläche kann die Aktualisierung des fps-Werts mit der Framerate überhaupt nicht verwendet werden (es sei denn, die Anzahl ist sehr stabil).
Was Sie wollen, ist wahrscheinlich ein gleitender Durchschnitt oder eine Art Binning / Reset-Zähler.
Sie können beispielsweise eine Warteschlangendatenstruktur verwalten, die die Renderzeiten für jeden der letzten 30, 60, 100 oder What-Have-You-Frames enthält (Sie können sie sogar so gestalten, dass das Limit zur Laufzeit einstellbar ist). Um eine anständige fps-Näherung zu ermitteln, können Sie die durchschnittlichen fps aus allen Renderzeiten in der Warteschlange ermitteln:
Wenn Sie mit dem Rendern eines neuen Frames fertig sind, stellen Sie eine neue Renderzeit in die Warteschlange und eine alte Renderzeit aus der Warteschlange. Alternativ können Sie die Warteschlange nur dann deaktivieren, wenn die Summe der Renderzeiten einen voreingestellten Wert (z. B. 1 Sek.) Überschreitet. Sie können den "letzten fps-Wert" und einen zuletzt aktualisierten Zeitstempel beibehalten, um auf Wunsch auszulösen, wann die fps-Zahl aktualisiert werden soll. Obwohl bei einem gleitenden Durchschnitt, wenn Sie eine konsistente Formatierung haben, das Drucken der "momentanen Durchschnitts" -Fps auf jedem Frame wahrscheinlich in Ordnung wäre.
Eine andere Methode wäre ein Rücksetzzähler. Behalten Sie einen genauen Zeitstempel (Millisekunden), einen Bildzähler und einen fps-Wert bei. Wenn Sie mit dem Rendern eines Frames fertig sind, erhöhen Sie den Zähler. Wenn der Zähler ein voreingestelltes Limit erreicht (z. B. 100 Frames) oder wenn die Zeit seit dem Überschreiten eines voreingestellten Werts des Zeitstempels (z. B. 1 Sek.) Die fps berechnet hat:
Setzen Sie dann den Zähler auf 0 zurück und setzen Sie den Zeitstempel auf die aktuelle Zeit.
quelle
Erhöhen Sie einen Zähler jedes Mal, wenn Sie einen Bildschirm rendern, und löschen Sie diesen Zähler für ein Zeitintervall, über das Sie die Bildrate messen möchten.
Dh. Holen Sie sich alle 3 Sekunden Zähler / 3 und löschen Sie den Zähler.
quelle
Es gibt mindestens zwei Möglichkeiten:
Das erste ist das, was andere hier vor mir erwähnt haben. Ich denke, es ist der einfachste und bevorzugte Weg. Sie nur um den Überblick zu behalten
Die Berechnung der fps ist in diesem Fall so einfach wie die Auswertung dieser Formel:
Dann gibt es die überaus coole Art, die Sie eines Tages nutzen möchten:
Angenommen, Sie müssen 'i'-Frames berücksichtigen. Ich werde diese Notation verwenden: f [0], f [1], ..., f [i-1], um zu beschreiben, wie lange es gedauert hat, Frame 0, Frame 1, ..., Frame (i-1) zu rendern ) beziehungsweise.
Dann wäre die mathematische Definition von fps nach i Frames
Und die gleiche Formel, aber nur unter Berücksichtigung von i-1-Frames.
Der Trick hier besteht nun darin, die rechte Seite der Formel (1) so zu ändern, dass sie die rechte Seite der Formel (2) enthält, und sie durch die linke Seite zu ersetzen.
So (Sie sollten es klarer sehen, wenn Sie es auf Papier schreiben):
Nach dieser Formel (meine mathematischen Fähigkeiten sind allerdings etwas verrostet) müssen Sie zur Berechnung der neuen fps die fps aus dem vorherigen Frame, die Dauer des Renderns des letzten Frames und die Anzahl der Frames kennen gerendert.
quelle
Dies könnte für die meisten Leute übertrieben sein, deshalb hatte ich es bei der Implementierung nicht gepostet. Aber es ist sehr robust und flexibel.
Es speichert eine Warteschlange mit den letzten Frame-Zeiten, sodass ein durchschnittlicher FPS-Wert viel besser genau berechnet werden kann als nur der letzte Frame.
Sie können damit auch einen Frame ignorieren, wenn Sie etwas tun, von dem Sie wissen, dass es die Zeit dieses Frames künstlich verkürzt.
Außerdem können Sie die Anzahl der Frames ändern, die während der Ausführung in der Warteschlange gespeichert werden sollen, damit Sie im Handumdrehen testen können, welcher Wert für Sie am besten geeignet ist.
quelle
Gute Antworten hier. Wie Sie es implementieren, hängt davon ab, wofür Sie es benötigen. Ich bevorzuge den laufenden Durchschnitt selbst "time = time * 0.9 + last_frame * 0.1" von dem Typ oben.
Ich persönlich mag es jedoch, meinen Durchschnitt stärker auf neuere Daten auszurichten, da es in einem Spiel SPIKES sind, die am schwersten zu quetschen sind und daher für mich am interessantesten sind. Ich würde also eher einen .7 \ .3-Split verwenden, bei dem ein Spike viel schneller angezeigt wird (obwohl der Effekt auch schneller vom Bildschirm abfällt. Siehe unten).
Wenn Sie sich auf die RENDERING-Zeit konzentrieren, funktioniert die .9.1-Aufteilung ziemlich gut, da sie in der Regel flüssiger ist. Für Gameplay / KI / Physik sind Spikes jedoch viel besorgniserregender, da dies normalerweise dazu führt, dass Ihr Spiel abgehackt aussieht (was oft schlechter ist als eine niedrige Bildrate, vorausgesetzt, wir fallen nicht unter 20 fps).
Also würde ich auch so etwas hinzufügen:
(Füllen Sie 3.0f mit der Größe aus, die Sie für eine inakzeptable Spitze halten.) Auf diese Weise können Sie FPS-Probleme am Ende des Rahmens finden und lösen .
quelle
time = time * 0.9 + last_frame * 0.1
durchschnittliche Berechnung, mit der sich die Anzeige reibungslos ändert.Ein viel besseres System als die Verwendung einer großen Anzahl alter Frameraten besteht darin, einfach Folgendes zu tun:
Diese Methode benötigt viel weniger Speicher, benötigt viel weniger Code und legt mehr Wert auf aktuelle Frameraten als auf alte Frameraten, während die Auswirkungen plötzlicher Frameratenänderungen immer noch geglättet werden.
quelle
Sie können einen Zähler beibehalten, ihn nach dem Rendern jedes Frames erhöhen und dann den Zähler zurücksetzen, wenn Sie sich in einer neuen Sekunde befinden (wobei der vorherige Wert als Anzahl der gerenderten Frames der letzten Sekunde gespeichert wird).
quelle
JavaScript:
quelle
Hier ist ein vollständiges Beispiel mit Python (das jedoch leicht an jede Sprache angepasst werden kann). Es verwendet die Glättungsgleichung in Martins Antwort, also fast keinen Speicheraufwand, und ich habe Werte ausgewählt, die für mich funktionieren (Sie können gerne mit den Konstanten herumspielen, um sie an Ihren Anwendungsfall anzupassen).
quelle
Zähler auf Null setzen. Jedes Mal, wenn Sie einen Frame zeichnen, erhöhen Sie den Zähler. Drucken Sie nach jeder Sekunde den Zähler aus. einschäumen, ausspülen, wiederholen. Wenn Sie zusätzliches Guthaben wünschen, behalten Sie einen laufenden Zähler und dividieren Sie durch die Gesamtzahl der Sekunden für einen laufenden Durchschnitt.
quelle
In (c ++ like) Pseudocode habe ich diese beiden in industriellen Bildverarbeitungsanwendungen verwendet, die Bilder von einer Reihe von extern ausgelösten Kameras verarbeiten mussten. Variationen in der "Bildrate" hatten eine andere Quelle (langsamere oder schnellere Produktion am Band), aber das Problem ist das gleiche. (Ich gehe davon aus, dass Sie einen einfachen Aufruf von timer.peek () haben, der Ihnen seit dem Start der Anwendung oder dem letzten Aufruf so etwas wie die Nr. Von ms (ns?) Gibt.)
Lösung 1: schnell, aber nicht bei jedem Frame aktualisiert
Lösung 2: Aktualisiert jeden Frame, benötigt mehr Speicher und CPU
quelle
quelle
Wie ich es mache!
In Worten, eine Tick-Uhr verfolgt Ticks. Wenn es das erste Mal ist, nimmt es die aktuelle Zeit und setzt sie in "Tickstart". Nach dem ersten Tick entspricht die Variable 'fps' der Anzahl der Ticks der Tick-Uhr geteilt durch die Zeit minus der Zeit des ersten Ticks.
Fps ist eine ganze Zahl, daher "(int)".
quelle
So mache ich das (in Java):
quelle
In Typescript verwende ich diesen Algorithmus, um Framerate- und Frametime-Durchschnittswerte zu berechnen:
Verwendung:
Tipp: Wenn Samples 1 ist, ist das Ergebnis Echtzeit-Framerate und Frametime.
quelle
eine Startzeit speichern und Ihren Framecounter einmal pro Schleife erhöhen? Alle paar Sekunden können Sie einfach Framecount / (Jetzt - Startzeit) drucken und dann neu initialisieren.
edit: oops. Doppel-Ninja'ed
quelle