Framerate

Aus DGL Wiki
(Weitergeleitet von Mikroruckler)
Wechseln zu: Navigation, Suche

Das englische Wort "frame" lässt sich in etwa mit "Rahmen" übersetzen. Das "Frame" in Framerate hat aber nichts mit einem Bilderrahmen o.ä. zu tun, sondern gemeint ist der zeitliche Rahmen, in dem ein bestimmter Rechenvorgang stattfindet. Wenn man von der Framerate von Spielen spricht, ist ein Frame also genau die Zeit, die der Computer benötigt, um ein neues Bild auf den Bildschirm zu rendern. Die Framerate (auch Bildwiederholrate) gibt an, wie viele dieser Frames pro Sekunde (fps) vergehen.

24 fps Mythos

Damit die grafische Ausgabe nicht wie eine Abfolge von Einzelbildern, sondern wie eine flüssige Bewegung aussieht, muss das angezeigte Bild schnell genug aktualisiert werden - mit anderen Worten: Die Framerate muss hoch genug sein. Experimente haben ergeben, dass das menschliche Auge eine Animation ab etwa 24 Bildern pro Sekunde nicht mehr als Bildfolge, sondern als Bewegung wahrnimmt. Daher stammt auch die weit verbreitete Meinung, ein Spieler könne keinen Unterschied zwischen 24 fps und beispielsweise 60 fps erkennen. Diese Annahme ist jedoch aus verschiedenen Gründen falsch! Siehe folgender Text.

Unschärfe bei Bewegung

Überlegen wir einmal, was passiert, wenn ein weißer Ball schnell von links nach rechts durchs Bild fliegt. Das erste Bild, das der Computer rendert, zeigt den Ball auf der linken Seite des Bildes.
Ball links.png

Sofort nachdem das Bild fertig ist, misst das Programm natürlich die Zeit, die es für das eine Bild gebraucht hat (bei 24 fps knapp 42 ms). Anhand der gemessenen Zeit kann es bestimmen, welche Strecke der Ball in dieser Zeit zurückgelegt hat (s = v*t, Timebased Movement). Nun verschiebt es den Ball um die entsprechende Strecke und beginnt sofort, das nächste Bild zu rendern. Nun ist der Ball schon in der Mitte des Bildschirms angelangt.
Ball mittig.png

Wieder misst das Programm die vergangene Zeit, verschiebt den Ball um die entsprechende Strecke und rendert das nächste Bild. Nun ist der Ball rechts.
Ball rechts.png

Im nächsten Bild wird er gar nicht mehr zu sehen sein. Der Betrachter bekommt also hintereinander drei gestochen scharfe Bilder zu sehen, die er als Bewegung interpretieren soll. Das Problem dabei ist das "gestochen scharf".

Betrachten wir zum Vergleich einmal, was passieren würde, wenn sich diese Szene in der Natur abspielt. Der Ball wird von einer oder mehrerer Lichtquellen beleuchtet und reflektiert einen Teil des Lichts zum Auge des Betrachters. (Der Einfachheit halber nehmen wir an, dass der arme Betrachter nur ein Auge hat.) Währenddessen bewegt sich der Ball, und da der Betrachter seine Blickrichtung in dieser Zeit nicht ändert, wird das Licht während des Frames von 42 ms an verschiedene Stellen der Netzhaut reflektiert - allerdings wird kein Teil der Netzhaut 42 ms lang belichtet. Über den Sehnerv wird für jeden "Pixel" auf der Netzhaut der mittlere Helligkeitswert ans Gehirn übermittelt. Das Resultat ist ein grauer (nicht weißer) Streifen quer durchs Bild. Der Ball "verwischt" sozusagen, wie man es auch von Fotos mit zu langer Belichtungszeit kennt.
Ball verwischt.png

Genau diese Unschärfe erwartet auch der Spieler eines Computerspiels. Fehlt dieser Effekt, wirkt die Bewegung ruckelig. Eine Möglichkeit, diesen Effekt zu erzielen, wäre alle Bewegungen unscharf zu zeichnen. Das hat aber einen gewaltigen Nachteil, wie du im nächsten Abschnitt sehen wirst. Die andere Möglichkeit ist, einfach deutlich mehr Bilder pro Sekunde zu rendern, als nur 24.

Schärfe bei Bewegung

Warum ist das Unscharf-Zeichnen (Motion-Blur) keine Lösung des Problems? Ganz einfach: Man stelle sich die selbe Szene noch einmal vor - mit dem einzigen Unterschied, dass der Betrachter dieses Mal nicht auf eine Stelle starrt, sondern den Ball mit seinem Blick verfolgt. Er sieht also erst auf die linke Seite des Bildschirms und bewegt seinen Blick mit konstanter Geschwindigkeit nacht rechts. Was würde er erwarten zu sehen? Denk' mal kurz darüber nach.

Der Spieler erwartet natürlich die selben Effekte, die er (unbewusst) zuvor in der Natur beobachtet hat. Nämlich dass der fliegende Ball gestochen scharf zu sehen ist, während der Hintergrund in Unschärfe verwischt. Denn dadurch, dass der Beobachter sein Auge immer nach dem Ball ausrichtet, trifft das von ihm reflektierte Licht immer die gleichen Stellen der Netzhaut.

Dem Ball auf dem Bildschirm zu folgen, nachdem dieser unscharf gezeichnet wurde, geht aber nicht - man sieht ja nur einen grauen Streifen, überall dort, wo der Ball im Laufe des Frames einmal war. Das Problem ist, dass der Programmierer nicht wissen kann, wie der oder die Betrachter des Bildschirms ihre Augen bewegen. Würde man die gesamte Szene ohne Motion-Blur aber mit 24000 fps rendern (was natürlich kein PC oder Bildschirm schaffen würde), dann würde sich der Ball in jedem Frame um einen oder zwei Pixel verschieben und wäre zu jeder Zeit gestochen scharf, wenn man ihm folgt. Gleichzeitig würde er (für das Auge) verwischen, wenn man ihm nicht folgt.

Die einzige Möglichkeit, dem Spieler ein wirklich realistisches visuelles Erlebnis zu bieten, besteht also darin, eine möglichst hohe Framerate zu erzielen. Eine geringe Framerate lässt sich im Allgemeinen nicht mit Motion-Blur kompensieren. Der Blur-Effekt kostet sogar noch Leistung und sorgt damit für eine geringere Framerate (das gilt natürlich nicht in Filmen). Dennoch hat Motion-Blur seine Existenzberechtigung: Erstens wenn die FPS-Grenze des Monitors bereits erreicht ist. Und zweitens um Dinge mit übertriebenem Motion-Blur schneller aussehen zu lassen, als sie sind.

Variation der Framerate

Auch wenn die Framerate deutlich über 24 fps liegt, können selbst langsamere Bewegungen noch ruckelig wirken. Grund dafür ist dann, dass die Framelänge stark variiert. Als Beispiel muss mal wieder der Ball herhalten, der diesmal aber nicht in einer achtel Sekunde durchs gesamte Bild fliegt, sondern gemächlich mit konstanter Geschwindigkeit ins Bild rollt. Die Szene wird mit (normalerweise sehr flüssigen) 60 fps gerendert. Ein Frame hat also eine Dauer von 16,67 ms. Leider kommt es nun durch ungünstige Umstände dazu, dass ein einziges Frame plötzlich doppelt so lange dauert wie die anderen zuvor. Welche Auswirkungen hat also folgende Frame-Abfolge?

Frame Länge
Frame0 16,67
Frame1 16,67
Frame2 33,33
Frame3 16,67
Frame4 16,67

Die Hälfte von 60 fps sind 30 fps. Man sollte meinen, dass dies immer noch als ruckelfrei empfunden wird. Das Problem ist auch nicht die Framelänge als solches, sondern die Länge von Frame2 im Vergleich zu den anderen Frames. Der Betrachter erwartet, dass der Ball mit konstanter Geschwindigkeit weiterrollt. Während das Bild gezeichnet wird, kann das Programm noch nicht wissen, wie viel Zeit vergangen sein wird, wenn das Bild fertig ist. Deshalb wird der Ball ja immer um die Strecke verschoben, die der letzten Framelänge entspricht. In Frame2 wird also der Ball verschoben, als wenn der Zeichenvorgang nur 16,67 ms dauern würde. In Wirklichkeit vergeht aber doppelt so viel Zeit, so dass es dem Spieler vorkommt, als hätte der Ball seine Geschwindigkeit plötzlich halbiert. Aber es kommt noch schlimmer: Da Frame3 wieder nur 16,67 ms dauert, der Ball aber so weit fortbewegt wird, als würde der Frame 33,33 ms dauern, vervierfacht sich die Geschwindigkeit nun! Erst in Frame4 bekommt der Ball durch eine erneute Tempohalbierung wieder seine wirkliche Geschwindigkeit. Diese Geschwindigkeitssprünge werden auch bei hoher Framerate noch als Ruckeln wahrgenommen. Man nennt diese Ruckler auch Mikroruckler.

Als st-Diagramm dargestellt sieht das so aus:
st-Diagramm (Mikroruckler).png

Bildschirmfrequenz und V-Sync

Kein Bildschirm kann beliebig viele Bilder pro Sekunde darstellen. Eine übliche Refreshrate bei Flachbildschirmen ist 60 Hz (das heißt, das Bild wird 60 mal pro Sekunde erneuert). Es gibt aber auch welche mit 120 Hz (für Stereoskopie) oder 200 Hz. Da 60 Hz auf Röhrenbildschirmen stark flimmern, können diese alten Kisten oft auch 75, 85, oder 100 Hz. Egal, wie oft ein Monitor pro Sekunde sein Bild erneuern kann - es gibt (von Ausnahmefällen wie Benchmarking abgesehen) keinen Grund, die Grafikkarte mehr Bilder berechnen zu lassen, zumal dies zu unerwünschten Artefakten führt (Tearing).

Deshalb gibt es eine Technik, die sich V-Sync nennt. Dabei wartet die Grafikkarte, bis das neue Bild an den Bildschirm übertragen wurde, bis sie das nächste beginnt. Es ist unbedingt zu empfehlen V-Sync einzuschalten, wenn der Computer sowieso mehr Bilder pro Sekunde rendern kann als der Bildschirm darzustellen vermag. Doch was passiert, wenn V-Sync eingeschaltet ist und der Rechner nicht die native Framerate des Bildschirms erreicht?
Nehmen wir an, der Bildschirm wird 60 mal pro Sekunde aktualisiert, die GPU schafft aber nur 50 Bilder pro Sekunde. Sobald die Grafikkarte das Synchronisationssignal empfängt, kopiert sie den Backbufferinhalt in den Frontbuffer und rendert das nächste Bild in den Backbuffer. 16,67 ms später kommt das nächste Synchronisationssignal, aber die Grafikkarte ist noch nicht fertig. Also wird nichts in den Frontbuffer kopiert. Stattdessen zeigt der Bildschirm zweimal hintereinander das gleiche Bild an. Erst weitere 3,33 ms später stellt der Grafikchip das Bild fertig und muss nun 13,34 ms (!) auf das nächste Sync-Signal warten. Bis dieses kommt, sind insgesamt 33,33 ms vergangen - mit anderen Worten wir haben eine Framerate von nur 30 fps, obwohl der Computer 50 fps schaffen würde!

Triple-Buffering

Das Problem dabei ist, dass die Grafikkarte während des Wartens auf das Sync-Signal nichts tut. Doch dafür gibt es eine Lösung: Da wir in den Backbuffer noch nicht schreiben dürfen, schreiben wir halt in einen anderen Backbuffer! Während wir in den zweiten Backbuffer schreiben, wird der erste in den Frontbuffer kopiert, sobald das Sync-Signal wieder kommt. Im nächsten Frame schreiben wir natürlich wieder in den ersten Backbuffer, während der zweite aufs Kopieren wartet. Somit erreichen wir die selbe Performance wie ohne V-Sync, sind aber gleichzeitig das Tearing losgeworden.
Ein Nachteil des Verfahrens ist, dass wir etwas mehr Videospeicher benötigen. Der Mehrverbrauch hält sich aber in Grenzen, denn es wird lediglich ein weiterer Farbpuffer benötigt - den Z- und Stencilbuffer dagegen brauchen wir nicht noch einmal. Zudem handelt man sich natürlich weitere Mikroruckler ein - aber mal ehrlich: 50 fps mit Mikrorucklern sind immer noch besser als 30 fps ohne.

OpemGL bietet selbst keine Möglichkeit, Triple-Buffering an- oder auszuschalten. Dies ist Sache des Treibers. Man kann Triple-Buffering zwar mittels eines FBOs emulieren, jedoch hat man dann in Wirklichkeit Quadruple-Buffering, wenn der Treiber sich bereits darum kümmert. (Quelle: [1])

variable Bildschirmfrequenz

Aktuell (2014) gibt es in der Industrie Bestrebungen, Displays mit variabler Refreshrate zu entwickeln. Bezeichnungen dafür sind Adaptive Sync (DisplayPort-Standard), G-Sync (Nvidia) oder FreeSync (AMD). Dabei soll das Problem der Synchronisation zwischen Bildschirm und Grafikkarte von der anderen Seite als bisher angegangen werden: Nicht mehr der Bildschirm gibt vor, in welchem Takt die Grafikkarte Bilddaten liefern soll, sondern die Grafikkarte signalisiert dem Bildschirm, wann sie fertig mit den Berechnungen ist. Daraufhin überträgt sie das neue Bild an den Schirm, welcher es dann sofort darstellt.
Der Vorteil: Die Latenz (Zeit zwischen Benutzereingabe und Bildausgabe) verkürzt sich, Triple-Buffering wird unnötig und die durch letzteres verursachten Mikroruckler verschwinden. Tearing sieht man ebenfalls nicht, da ja immer noch synchronisiert wird.

Siehe auch

Frameratenbegrenzung
Framecounter