Wenn Sie Spieleentwickler sind, haben Sie wahrscheinlich von den Begriffen gehört Gamma und Gamma-Korrektur. Sie wissen vielleicht nicht, was sie bedeuten, aber sie sollten nicht leichtfertig entlassen werden.
Spieleentwickler neigen dazu, Gamma zu ignorieren, da ihre Effekte subtil genug sind, um durch Anpassen von Lichtintensitäten, Spiegelintensitäten und dergleichen annähernd korrigiert zu werden. Um jedoch eine realistische Bildqualität mit einer realistisch wirkenden Beleuchtung zu erzielen, müssen der Gammawert und die erforderlichen Schritte verstanden werden um seine Präsenz in der digitalen Bildverarbeitung zu umgehen, um die bestmögliche Qualität zu erhalten. Mit der richtigen Gammakorrektur können Sie das Erscheinungsbild Ihrer Echtzeit-3D-Grafiken radikal verbessern.
Die CRT-Monitore, die ursprünglich für Computerbildschirme verwendet wurden, haben eine merkwürdige Eigenschaft: Die Farbwiedergabe auf ihren Bildschirmen ist nicht linear in Bezug auf Rohwerte, die von der Grafikkarte übergeben werden.
Nichtlinear bedeutet in diesem Sinne, dass eine Erhöhung Ihrer Farbkomponente um ein konstantes Verhältnis (z. B. wenn eine rote Komponente einer Farbe doppelt so hoch wird) zu keiner Erhöhung der vom Monitor emittierten Lichtintensität führt das gleiche Verhältnis (dh das rote Licht wird vom Bildschirm ausgestrahlt) nicht doppelt so hoch sein).
Die Farbantwort eines CRT-Monitors ist tatsächlich eine exponentiell Funktion. (Wie in jeder Physik ist dies viel komplexer als wir beschreiben, aber der Einfachheit halber bleiben wir bei dieser Annahme.) Das heißt, die Funktion EendedLight (C)
, woher C
ist ein Farbkomponentenwert (rot, grün oder blau) im Bereich von 0
(kein Licht) zu 1
(volle Lichtintensität) ist C
zu etwas Macht erhoben γ
.
Diese Nummer, γ
, heißt das Gamma-Exponent oder nur Gamma. Typische Gamma-Werte liegen zwischen 2,0 und 2,4, und wenn man sich mit Gamma im allgemeinen Sinne befasst, wird als Kompromiss der Wert 2,2 angenommen und viele neuere Monitore entworfen den Gammawert von genau 2.2 haben
In der Praxis bedeutet dies, dass Schwarz und Weiß auf dem Bildschirm unverzerrt dargestellt werden (weil Null für eine beliebige Potenz Null ist und eine für jede Potenz eine Eins ist), aber alle dazwischen liegenden Werte werden verzerrt, ohne dass eine zuverlässige Erkennung möglich ist dies geschieht nur durch das Anschauen.
Zum Beispiel, wenn Sie eine Farbe anzeigen, die angeblich zweimal dunkler als schwarz ist - also, RGB (0,5, 0,5, 0,5)
-es wird tatsächlich als weniger angezeigt vier mal dunkler, wenn man den gemeinsamen Gammawert von 2,2 annimmt, da der um 2,2 erhöhte Wert auf 2,2 um 0,22 liegt. Dies ist eindeutig nicht das, was Sie beabsichtigen, und dies ist nicht nur bei CRT-Monitoren der Fall: LCDs, nicht jedoch unbeabsichtigt Wenn Sie diese Eigenschaft haben, sind sie so konzipiert, dass sie mit ihren älteren Pendants kompatibel sind und somit Ihre Farbwerte so anzeigen.
Da außerdem rote, grüne und blaue Komponenten unabhängig voneinander behandelt werden, können die beabsichtigten Farbtöne von Bildern leicht beeinträchtigt werden, da die Intensitäten der drei Farbkomponenten nicht einheitlich skaliert werden. Was passiert, wenn Sie den Farbwert anzeigen RGB (1, 0,5, 0,5)
? Die rote Komponente bleibt bei 1, aber die anderen werden auf die Hälfte ihres Wertes abgesenkt, wodurch der Farbton Ihrer Farbe vollständig geändert wird.
Nun, da wir gesehen haben, welche Auswirkungen diese Monitoreigenschaft auf die Farbdaten des Monitors hat, können wir sehen, welche Schritte zu ihrer Bekämpfung unternommen werden.
Bei der Gammakorrektur wird die unglückliche Arbeit des Monitors rückgängig gemacht. Die Gammakorrektur eines Bildes erhöht im Wesentlichen seine Farbintensität auf 1 / gamma
, so dass, wenn der Monitor wiederum den Wert auf erhöht Gamma
, diese heben sich auf und das Ergebnis ist die Farbe, die wir ursprünglich zeigen wollten.
(Erinnere dich daran EIN
angehoben zu B
, und dann zu angehoben C
, ist das gleiche wie EIN
angehoben zu B × C
, und aus diesem Grund werden diese Operationen ebenso abgebrochen Gamma × (1 / Gamma)
ist 1
.)
Da der durchschnittliche Benutzer seinen Monitor nicht für eine lineare Reaktion kalibriert, werden viele Bilder, auf die er trifft, so korrigiert, dass er den Unterschied nie spürt. In der Regel werden die meisten Bilddateien im Internet in so genannten Dateien verteilt sRGB-Farbraum-Dies bedeutet, dass die ursprünglichen, beabsichtigten Farbwerte sind grob zur Macht von erhoben 1 / 2,2
bevor sie in Dateien abgelegt werden (obwohl in der Realität komplexere Gleichungen vorkommen). Dadurch wird sichergestellt, dass alle Benutzer mit herkömmlichen Displays die echten Farben sehen. Scanner, Kameras und viele digitale Bildverarbeitungsgeräte berücksichtigen dies und korrigieren ihre Ausgabe für Sie, wenn Sie in herkömmlichen Bildformaten speichern.
Schauen Sie sich das obige Bild an. Wenn wir das Gamma nicht berücksichtigen, ist die Kurve exponentiell (untere grüne Kurve). Wenn wir eine Gammakorrektur durchführen, wird die tatsächliche Reaktion linear sein, so wie es sein sollte. Zum Vergleich zeigt das Bild auch, wie der Graph aussieht, wenn wir eine Gammakorrektur durchführen, der Monitor jedoch tatsächlich linear reagiert. In diesem Fall werden die Intensitäten in entgegengesetzter Weise verzerrt, und wir können sehen, dass, wenn ein nichtlinearer Monitor sie wiederum verzerrt, dies aufgehoben wird und wir mit einer geraden Linie enden.
Bisher haben wir die Theorie hinter diesen Phänomenen erklärt. Sicher, Monitore sind nichtlinear und die meisten Bilder sind korrigiert, so dass sie auf diesen Monitoren richtig aussehen, aber was scheint das Problem zu sein? Warum sollte ich, ein aufstrebender 3D-Spieleentwickler, mich mit der Gammakorrektur beschäftigen und alles andere tun? gerade zu wissen darüber?
Die Antwort ist einfach: Solange Bilder nur für die Anzeige erstellt werden, gibt es das Problem gar nicht. Sobald Sie jedoch möchten, dass ein Programm mit diesen Bildern etwas anstellt (skalieren, als Texturen verwenden, wenn Sie sie benennen), müssen Sie darauf achten, dass das Programm weiß, dass die Werte vorliegen nicht echt und sind nur so korrigiert, dass sie schau echt aus auf einem Monitor.
Dies geschieht insbesondere in einem Renderer, wenn Textur-Maps wie diffuse Oberflächen als Eingabe verwendet werden. Sie führt Operationen an ihnen aus, vorausgesetzt, ihre Farbwerte repräsentieren Lichtintensitäten genau; das heißt, a lineare Entsprechung mit realen Phänomenen, die sie repräsentieren.
Dies ist jedoch ein grundlegender Fehler: Wenn Sie Farbwerte summieren möchten, werden diese gamma-korrigiert 1 / gamma
) Sie erhalten die falschen Werte. Es ist kein mathematisches Genie, um das zu realisieren EIN
angehoben zu 1 / gamma
Plus B
angehoben zu 1 / gamma
ist nicht gleich (A + B)
angehoben zu 1 / gamma
. Das Problem tritt auch auf, wenn ein Renderer einige Werte ausgibt, beispielsweise wenn er leichte Beiträge ausgibt: Wenn dies der Fall ist Summen zwei leichte Beiträge, wissen aber nicht, dass das Ergebnis bei Anzeige auf dem Bildschirm auf Gamma erhöht wird falsch Werte.
Und genau hier tritt das Problem auf: Wann immer ein Renderer davon ausgeht, dass die Farben linear mit den realen Phänomenen übereinstimmen, oder nicht, oder dass Farben, die er ausgibt, linear den Lichtintensitäten auf dem Bildschirm entsprechen, wenn sie gewonnen haben ' Dies ist ein schwerwiegender Fehler, der das Erscheinungsbild der erzeugten Bilder beeinflussen kann.
Wenn Sie keinen der Fehler korrigieren, stellen Sie nicht sicher, dass die in den Renderer eingegebenen Farben für die Eingabe-Textur linear sind, und stellen Sie nicht sicher, dass das Ausgabebild des Renderers in Bezug auf den Bildschirm linear ist. Diese Bilder werden jedes Bild annullieren zu einem gewissen Grad, ähnlich wie sie bei der Anzeige von vorkorrigierten JPEG-Dateien in einem Webbrowser abgebrochen werden. Sobald Sie jedoch einige Zwischenberechnungen einschließen, die lineare Übereinstimmungen voraussetzen, ist Ihre Berechnung falsch.
Erinnern Sie sich daran, was wir früher über das Ändern von Farbtönen gesagt haben - diese Tatsache kann (manchmal) helfen, Nichtlinearität zu erkennen. Als Faustregel gilt: Wenn Sie lineare Parameteränderungen vornehmen (z. B. das Verdoppeln der Helligkeit der Lichter in der Szene), ändert sich das resultierende Bild nicht nur in der Helligkeit, sondern auch in Farbtönen (z. B. einem Bereich, der von a geht rötlich-orange Farbton in Richtung Gelb), bedeutet dies, dass am wahrscheinlichsten ein nichtlinearer Zwischenprozess stattfindet.
Dies kann bei Texturkarten der Fall sein, die aus verschiedenen Quellen abgerufen wurden, z. B. aus dem Internet, einer Digitalkamera, die in sRGB JPEG gespeichert wird, einem Scanner oder wenn die Textur auf einen Monitor gemalt wurde, der nicht explizit für eine lineare Antwort oder nicht explizit kalibriert wurde danach korrigiert. Jede auf diesen Texturkarten durchgeführte Mathematik ist falsch und weicht geringfügig von den theoretisch richtigen Werten ab. Dies ist bei Texturfiltern und Mipmaps sichtbar: Da die Filterung beim Mitteln von Farbwerten eine lineare Reaktion voraussetzt, werden deutliche Fehler angezeigt: Kleinere Texturen (entfernte) erscheinen deutlich dunkler als größere (dh wenn Sie näher bei Ihnen sind): Dies liegt daran, dass der Filteralgorithmus bei entfernten Entfernungen mehr Abtastwerte ermittelt und deren Nichtlinearität das Ergebnis mehr beeinflusst.
Die Beleuchtung leidet auch unter falschem Gamma: leichte Beiträge zu Oberflächen Summe in der realen Welt und folglich in einem Renderer, aber das Summieren ist keine treue Operation, wenn das Ergebnis nicht linear verzerrt ist. Wenn Sie komplexe Fragment-Shader verwenden, die anspruchsvolle Beleuchtungen ausführen, z. B. unterirdische Streuung oder HDR, werden die Fehler immer deutlicher, bis Sie den Punkt erreichen tatsächlich Ich frage mich, was mit dem Bild falsch ist, im Gegensatz zu einem unangenehmen Gefühl, "vielleicht irgendwie falsch beleuchtet zu sein, aber es ist wahrscheinlich nur ich", was auch oft vorkommen kann. Das Verdunkeln der Texturen oder das Aufhellen der endgültigen Bilder um einen konstanten oder linearen Faktor machen den Effekt nicht zunichte, da es sich ebenfalls um lineare Operationen handelt und Sie eine nichtlineare Operation benötigen, um die inhärente exponentielle Reaktionskurve im Monitor zu bekämpfen.
Jetzt wissen Sie hoffentlich, was Gamma und Gamma-Korrektur sind und warum dies bei Echtzeit-3D-Grafiken eine so große Sache ist. Natürlich muss es einen Weg geben, diese Probleme zu beheben?
Die Antwort ist ja, und das Fixieren von Gamma ist eine ziemlich einfache Operation, bei der Sie nichts ändern müssen, außer ein paar Codezeilen hinzuzufügen und zusätzliche Parameter-, Intensitäts- und Farbkorrekturen nicht zu berücksichtigen Sie haben Ihre Szenen so eingestellt, dass sie auf nichtlinearen Monitoren gut aussehen, ohne sie zu korrigieren.
Es gibt drei grundlegende Schritte, um sicherzustellen, dass Sie so lange wie möglich linear bleiben und die Korrektur am richtigen Punkt vornehmen:
Sie sollten die Quellbilder normalerweise nicht so ändern, dass sie lineare Farben enthalten. Wenn die Farben für den typischen Monitor in acht-Bit-Farbfeldern gamma-korrigiert sind, können Sie in dunklen Bereichen, in denen das menschliche Auge für Intensitätsschwankungen empfindlicher ist, eine höhere Auflösung erzielen. Sie können jedoch sicherstellen, dass die Farbwerte linear sind, bevor sie Ihre Shader erreichen.
In OpenGL können Sie dies normalerweise tun, indem Sie übergeben GL_SRGB8
anstatt GL_RGB8
, und GL_SRGB8_ALPHA8
anstatt GL_RGBA8
, zu glTexImage2D ()
, bei der Angabe einer Textur. Dies wird dafür sorgen Alle Werte, die über einen Shader-Sampler aus dieser Textur gelesen werden, werden vom sRGB-Farbraum in einen linearen Bereich zurück korrigiert, genau das brauchen wir! Wenn Sie eine Rendering- oder Game-Engine verwenden, die das Laden von Textur für Sie übernimmt, wird dies möglicherweise berücksichtigt oder Sie müssen es manuell angeben. konsultieren Sie die Dokumentation der Bibliothek oder bitten Sie jemanden um Hilfe, wenn Sie sich nicht sicher sind.
Stellen Sie jedoch sicher, dass Sie dies nicht irrtümlicherweise für Bilder tun, die definitionsgemäß keine Farbinformationen darstellen und ausdrücklich mit diesem Gedanken gemalt wurden. Beispiele sind normale Karten, Bump-Maps oder Höhenkarten, die alle andere Daten als die Farbe in den Farbkanälen einer Textur codieren und daher diese Art der Vorkorrektur wahrscheinlich nicht benötigen.
Aus der in diesem Artikel enthaltenen Demo (einige Parameter wurden zur Klarheit mit ihren tatsächlichen Werten ausgetauscht):
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB8, Breite, Höhe, 0, GL_BGR, GL_UNSIGNED_BYTE, Daten);
Dadurch wird die Textur in einen nicht korrigierten Farbraum geladen. Wenn sich die Daten in der Texturdatei jedoch im sRGB-Farbraum befinden, sollten Sie den dritten Parameter in ändern GL_SRGB8
, nachgebend:
glTexImage2D (GL_TEXTURE_2D, 0, GL_SRGB8, Breite, Höhe, 0, GL_BGR, GL_UNSIGNED_BYTE, Daten);
Dadurch wird sichergestellt, dass OpenGL die Texturdaten korrigiert, wenn wir sie nachschlagen.
Jetzt müssen Sie die Farbkorrektur auf die endgültigen Ausgabebilder Ihres Renderers anwenden. Stellen Sie sicher, dass Sie keine Korrektur auf etwas anderes anwenden Finale Framebuffer, der auf dem Bildschirm angezeigt werden soll. (Berühren Sie nicht die Zwischenpuffer, die in andere Nachbearbeitungs-Shader eingegeben werden, da diese immer noch mit linearen Werten arbeiten.)
Dies kann in OpenGL durchgeführt werden, indem der Renderbuffer (der endgültige, nicht abfragbare Framebuffer) so festgelegt wird, dass eine sRGB-Farbcodierung durch Übergeben erfolgt GL_SRGB
anstatt GL_RGB
als Parameter zu glRenderbufferStorage ()
. Danach müssen Sie das erhöhen GL_FRAMEBUFFER_SRGB
Fahne durch Aufrufen glEnable
. Auf diese Weise werden Shader-Schreibvorgänge in sRGB-Puffer korrigiert, sodass sie direkt auf einem typischen Monitor angezeigt werden.
Wenn Sie eine Engine oder ein Framework verwenden, beinhaltet dies wahrscheinlich eine Option, um einen sRGB-Framebuffer für Sie zu erstellen und ihn richtig einzurichten. Wieder können Sie die Dokumentation der Bibliothek einsehen oder jemanden bitten, dies für Sie zu klären.
In der Demo verwenden wir die GLFW-Bibliothek, die uns einen schmerzlosen Weg bietet, einen sRGB-Framebuffer anzufordern. Insbesondere setzen wir einen Fensterhinweis und teilen OpenGL später mit, dass die Framebuffer-Operationen im sRGB-Bereich sein sollen:
glfwWindowHint (GLFW_SRGB_CAPABLE, TRUE);… glEnable (GL_FRAMEBUFFER_SRGB);
Wenn dies nicht der Beginn eines neuen Projekts ist, haben Sie die Chance, dass Gamma-falsche Beleuchtung und Filterung ihren Tribut fordern. Möglicherweise haben Sie Ihre diffusen Reflexionsfarben, Lichtintensitäten und vieles mehr angepasst, um subtile Belästigungen auszugleichen, die das Vernachlässigen von Gamma für Sie gebracht hat.
Sie müssen diese Werte noch einmal durchgehen und sie so anpassen, dass sie wieder richtig aussehen. Diesmal wirken Ihre Szenen jedoch natürlicher, da die Beleuchtung die Umstände der realen Welt genauer darstellt. Die Ecken sehen nicht zu dunkel aus, sodass Sie den Lichtintensitäten nicht mehr Intensität verleihen müssen (wodurch die Beleuchtung hellerer Objekte zerstört wird, die dann für diese Lichtmenge in der Szene künstlich hell erscheinen)..
Das lohnt sich: Wenn Sie Ihre Parameter erneut durchsehen, um eine natürliche Umgebung mit Gammakorrektur zu schaffen, können Sie den Anwendern eine Erlebnis- und Helligkeitsverteilung bieten, die genau auf Ihre Augen wirkt und so gewöhnt ist, wie Licht im wirklichen Leben wirkt.
In diesem Artikel ist eine kleine OpenGL 3.3-Demo enthalten, die eine einfache Szene mit einigen Texturen zeigt, die von zwei sich bewegenden Lichtquellen beleuchtet werden. Sie können zwischen verschiedenen Szenarien wechseln: Nicht Texturen korrigieren, sondern das endgültige Bild korrigieren. Texturen korrigieren, aber das endgültige Bild nicht korrigieren; Beides korrigieren (das heißt, alles richtig machen); und entweder nicht korrigieren (effektiv einen doppelten Fehler machen).
Die Demo ist in C ++ geschrieben (mit zwei GLSL-Shadern) und verwendet tragbare GLFW- und GLEW-Bibliotheken, sodass sie auf einer Vielzahl von Plattformen laufen sollte. Der Quellcode ist reif mit Kommentaren, so dass Sie jeden Aspekt dieser kurzen Anwendung erkunden können.
Die Demo in Aktion.Verwenden Sie die 1 Taste auf Ihrer Tastatur, um zwischen dem Korrigieren von Texturen und nicht dem Korrigieren von Texturen zu wechseln 2 Taste, um zwischen dem Korrigieren des Framebuffers und dem Nichtbereinigen des Framebuffers umzuschalten. Um beide gleichzeitig zu durchlaufen, drücken Sie 3-Es ist nützlich, den Unterschied zwischen dem vollständigen Vernachlässigen von Gamma (zwei Fehler, die sich zum größten Teil auslöschen) und dem richtigen Vorgehen zu erkennen. Wenn die Demo startet, wird keine dieser Korrekturen durchgeführt 3 um die Vorteile einer korrekten Gamma-Korrektur zu sehen.
Ich habe ein Microsoft Visual C ++ 2013-Projekt, kompatible 64-Bit-Versionen der GLFW- und GLEW-Bibliotheken sowie eine 64-Bit-Windows-Programmdatei beigefügt. Mit GLFW- und GLEW-Unterstützung können Sie dies jedoch relativ einfach auf jeder Plattform kompilieren: Kompilieren Sie einfach main.cpp
und loader.cpp
zusammen und verknüpfen sie mit diesen beiden Bibliotheken. Installieren Sie diese Bibliotheken unter Linux über Ihren Paketmanager und übergeben Sie sie -lglew -lglfw
zu G++
sollte den Trick tun. (Bitte beachten Sie, dass dies nicht auf anderen Betriebssystemen als Windows getestet wurde, aber es sollte funktionieren. Wenn Sie auf Probleme stoßen, teilen Sie mir dies bitte in den Kommentaren mit. Ich werde sie so schnell wie möglich beheben.)
Wie Sie beim Ausführen der Demo sehen können, sind die Effekte selbst mit einem einfachen Modell und einer einfachen Szene wie dieser ziemlich spürbar. Natürlich können Sie in diesem einfachen Fall vielleicht die Shader-Parameter anpassen, damit das Bild unkorrigiert gut aussieht. Sobald Sie jedoch mit dem Aufbau von Komplexität in Ihren Szenen beginnen, ist der Unterschied einfach zu sichtbar, um auf diese Weise jemals kompensiert zu werden.
In diesem Artikel haben wir Begriffe wie Gamma, Gamma-Korrektur, nichtlineare Ein- und Ausgänge und nichtlineare Mathematik behandelt. Hoffentlich konnte ich Sie davon überzeugen, dass Sie sich jetzt um die Gammakorrektur kümmern sollten, wenn Sie dies bisher vernachlässigt hatten. Wenn Sie vor dem Auftauchen dieses Artikels vorsichtig mit Gamma waren, hoffe ich, dass Ihnen etwas Neues gegeben wird winzige Informationen, mit denen das Problem gelöst werden kann.
Vor allem haben wir gelernt, Probleme zu beheben, die entstehen, wenn Sie Farbwerte falsch manipulieren, vorausgesetzt, sie sind linear und wir haben die gängigen Fallstricke und Symptome überprüft, die auftreten, wenn Sie diesen wichtigen Aspekt der Computergrafik vernachlässigen.
Ich hoffe, Sie hatten Spaß und haben beim Lesen dieses Artikels etwas Neues gelernt. Bis zum nächsten Mal!