Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

01.10.2012, 21:41

Gamma Correction

Moin,

ich konnte mich bisher erfolgreich um das Verstandnis von Gamma Correction drücken, weil es bisher out-of-the-box funktioniert hat.
Jetzt ist allerdings der Zeitpunkt gekommen, wo es nötig wird. Zu beginn erstmal folgendes Bild auf, dass ich mich später beziehen werde:


(Link)


Ich benutze eine Render-Pipeline wo es nötig wird in "linear space" zu rendern. Die Texturen die ich nutze sind natürlich nicht in dem Raum.
Soweit aber noch kein Problem, meine Render-Engine bietet automatische Konvertierung in meinen linearen Raum. Da stellen sich mir aber auch schon die ersten Fragen:
1. Die Texturen liegen alle im sRGB-Farbraum vor, ist das korrekt?
2. Der sRGB-Farbraum ist von der Gamma-Kurve, der unteren Kurve (ungefähr) gleich zu setzen?

Ich gehe im folgenden von einer Beantwortung mit "ja" aus, weil sie meinem Kenntnisstand entspricht.
3. So müssten die Texturen ja einfach mit pow(tex,1.0/2.2) in den linearen Raum gebracht werden? (Ich weiß das die power function nicht ganz korrekt ist, aber ums einfach zu halten...)
Damit kann ich dann schön mein Beleuchtungssystem rauf und runter rechnen wies mir Spaß macht. Dann will ich es aber schließlich an den Framebuffer übergeben, ders auf dem Monitor darstellt.
4. Erwartet der Monitor meinen finalen Output im sRGB-Raum (untere Kurve) ? ("Because the monitor expects a value that is sRGB encoded, a transfer function that converts from gamma 1.0 to gamma 2.2 is applied to the resulting color value before it is send to the framebuffer." http://content.gpwiki.org/index.php/D3DBook:Color_Filters )
5. Wenn ja, warum sagt meine Render-Engine: "When rendering to a final 8-bit per channel display, you’ll also want to convert back to gamma space which can be done in your shader (by raising to the power 1/2.2) or you can enable gamma correction on the texture being rendered to or the render window"? Denn das würde ja den linearen Raum, in die obere Kurve bringen.
6. Warum sieht das ganze auch noch gut aus? :D

Meine weiteren Fragen sind abhängig davon wie die Antworten hier ausfallen.

Da ich momentan echt auf dem Schlauch stehe, würde ich mich über Antworten freuen.

Gruß Mark

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »mark93« (01.10.2012, 22:42)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

01.10.2012, 21:58

Beginnen wir mit einem Artikel, den jeder mal gelesen hab sollte: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html ;)

Wenn du einmal mit einer linearen Pipeline gearbeitet hast und den Unterschied mit eigenen Augen gesehen hast, wirst du dich fragen, wie du das all die Zeit nur ignorieren konntest. Geht mir manchmal sogar immer noch so...

1. Die Texturen liegen alle im sRGB-Farbraum vor, ist das korrekt?

Hängt davon ab, in welchem Format die Texturen vorliegen. Aber wenn es sich da um normale 24Bit Bitmaps handelt oder sowas, dann in der Regel ja, denn so ziemlich alles exportiert in sRGB...

2. Der sRGB-Farbraum ist von der Gamma-Kurve, der unteren Kurve (ungefähr) gleich zu setzen?

Wenn deine x-Achse dem Farbwert und die y-Achse der Intensität entspricht, dann ja.

3. So müssten die Texturen ja einfach mit pow(tex,1.0/2.2) in den linearen Raum gebracht werden? (Ich weiß das die power function nicht ganz korrekt ist, aber ums einfach zu halten...)

Genau umgekehrt, RGB = pow(sRGB, 2.2f). Aber das musst du normalerweise sowieso nicht per Hand machen, denn die Texturesampler deiner Grafikkarte unterstützen die Konvertierung von sRGB in linear RGB in Hardware (in der Regel wohl sogar die korrekte und nicht einfach nur den Gamma 2.2 Hack).

4. Erwartet der Monitor meinen finalen Output im sRGB-Raum (untere Kurve) ?

Normalerweise ja

5. Wenn ja, warum sagt meine Render-Engine: "When rendering to a final 8-bit per channel display, you’ll also want to convert back to gamma space which can be done in your shader (by raising to the power 1/2.2) or you can enable gamma correction on the texture being rendered to or the render window"? Denn das würde ja den linearen Raum, in die obere Kurve bringen.

Deine Render-Engine hat recht, allerdings auch hier wieder: Die Grafikkarte kann die Konvertierung von linear RGB in sRGB in Hardware erledigen...

Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von »dot« (01.10.2012, 22:07)


3

01.10.2012, 22:10

Vielen Dank für deine Antwort!

Deine Antworten zu 3) und 5) erschließen sich mir ncoh nicht ganz.

Meine normalen 8-bit-pro-Channel Texturen sind also im sRGB-Farbraum. Das repräsentiert ja die untere Kurve.
Um nun vom linearen raum zu der unteren Kurve zu kommen muss ich pow(tex, 2.2) machen. Die untere Funktion ist ja als f(x) = x^(2.2) definiert.
Die Umkehrfunktion wäre dementsprechend ja pow(tex,1.0f/2.2f):

Quellcode

1
tex = pow(pow(tex,2.2f),1.0f/2.2f)


Am Ende will ich ja meine Ergebnisse die linear sind, wieder in die untere Kurve bringen, warum also hat meine Render-Engine Recht?
Ich weiß das sie Recht hat, nur sehe ich noch nicht meinen Denkfehler :D.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

01.10.2012, 22:17

Um nun vom linearen raum zu der unteren Kurve zu kommen muss ich pow(tex, 2.2) machen.

Da liegt dein Denkfehler: Der lineare Farbraum sind die Intensitätswerte (y-Achse). Die x-Achse entspricht dem Farbwert in deiner sRGB Bitmap.

Am Ende will ich ja meine Ergebnisse die linear sind, wieder in die untere Kurve bringen, warum also hat meine Render-Engine Recht?

Weil du deine linearen Helligkeitswerte mit 1/2.2 potenzieren musst, um Werte zu bekommen, die, nachdem das Display sie dann mit 2.2. potenziert hat, die richtige Helligkeit produzieren. ;)

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (01.10.2012, 22:27)


5

01.10.2012, 22:40

Zitat

Wenn du einmal mit einer linearen Pipeline gearbeitet hast und den Unterschied mit eigenen Augen gesehen hast, wirst du dich fragen, wie du das all die Zeit nur ignorieren konntest. Geht mir manchmal sogar immer noch so...

Das stimmt wohl, wobei ich lineares Rendering schon sehr lange nutze, nur habe ich da immer auf die automatsiche Gamma Correction gesetzt :).

Ich stehe scheinbar noch sehr aufm Schlauch. ?(

Also ich ja in dem Bild oben folgende 3-Funktionen:
f(x) = x;
g(x) = x^(2.2) (unter Funktion)
h(x) = x^(1/2.2) (obere Funktion)

Meine Texturen liegen also im sRGB-Raum. Dieser Raum wird durch die untere Funktion g(x) beschrieben. In diesen Raum muss auch mein Output wieder gebracht werden.
Die Umkehrfunktion hier für ist ja h(x), denn f(x) = h(g(x)). Warum muss ich also g(g(x)) anwenden? Vielleicht könntest du mir da eine etwas detailierte Betrachtung geben :).

Wenn ich diesen fall verstanden habe, dann dürfte sich der andere ja von selbst erklären :).

Zitat


Weil du deine linearen Werte mit 1/2.2 potenzieren musst, um Werte zu bekommen, die das Display dann mit 2.2. potenzieren kann. ;)

Dann würde ich mich also auf der h(x) Kurve befinden? Der Monitor erwartet aber die untere Funktion g(x). Wenn ich dich richtig verstehe, wendet der Monitor auf mein gelieferten Output also pow(output, 2.2) an? Warum aber liegen dann meine Texturen per Default im sRGB-Bereich wenn der Monitor sie dann automatisch in diesem bringt? Wäre es nicht viel sinnvoller, dass die Texturen im genau dem entgegengesetzten Raum gespeichert werden?

Bin leicht verwirrt, sorry.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »mark93« (01.10.2012, 22:47)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

6

01.10.2012, 22:42

Was genau verstehst du unter

Dieser Raum wird durch die untere Funktion (g(x)) beschrieben.

?

Also was genau verstehst du unter "ein Raum wird durch eine Funktion beschrieben"!?

7

01.10.2012, 22:47

Ich habs dir mal eben aufgemalt:


EDIT: Habe ein paar Klammern entfernt, falls sie dich verwirrt haben.

Nimelrian

Alter Hase

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

8

01.10.2012, 22:50

Ich denke dot meint, dass du sagst, dass die Funktion einen Raum beschreiben soll, aber keine Angaben machst, wovon dieser Raum (abgesehen von der Funktion, denke ich mal) eingegrenzt wird.
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

01.10.2012, 22:54

Mir ist schon klar, wie die Kurven aussehen...meine Frage ist eher: Was genau bedeutet jetzt z.B. die rote Kurve für dich? Was entsprich der x-Achse und was der y-Achse?

10

02.10.2012, 17:58

Neuer Tag, neues Glück.

Habe mir nochmal verschiedenste Quellen durchgelesen. Werde jetzt mal ne kleine Zusammenfassung von meinen Erkenntnissen geben:
Die Gamma-Regelung stammt noch aus der Zeit der CRTs ist aber auch in heutige LCDs übernommen. Viele Monitore haben einen Gamma-Wert von 2.2.
Die allgemeien Regel lautet:

Quellcode

1
output = input^gamma


Der Monitor wendet dies aktiv an! Bedeuted im Schnitt, dass jeden Pixel den ich an den Monitor sende hoch 2.2 genomen wird. Allein das warum, das Monitore machen erschoss sich mir noch nciht ganz, ist aber für das eigentliche Verständnis unerheblich. Wenn ich rechne gehe ich davon aus, das jeder Wert auf sich selbst abgebildet wird. Bedeuted y = f(x) = x . Dies ist dann der lineare Raum. Der Bildschirm verzerrt jeden input allerdings. D.h. nicht jeder Input-Wert wird auf sich selbst als Output-Wert abgebildet. Sondern es gilt die Regel von oben und jeder Monitor wendet Output = Input^2.2 an. Allerdings ist das nicht das, was man haben will. Deswegen wendet man zum Schluss (bzw. lässt anwenden) die Inverse-Funktion für die Gamma-Kurve an. Die lautet:

Quellcode

1
output = input^(1.0/gamma)


So wird sichergestellt, dass auf dem Monitor das dargestellt wird, was man letztlich auch errechnet hat.

Shading an sich könnte jedoch niemals ohne Input geschehen und deshalb müssen vorallem Texturen auch im linearen Raum sein. Das sind sie meistens von sich aus nicht! Die sind bereits Gamma-korregiert. Sie sind so abgepeichert, dass wenn sie auf dem Monitor dargestellt werden, linear sind. Die Inversefunktion ist also schon auf jedem Pixel angewendet. Deshalb müsste ich auch, wenn ich sie manuell in den linearen Raum bringen will
hoch 2.2 nehmen.

Soweit ist das korrekt?

Werbeanzeige