Ich habe mich die letzten paar Tage ein bisschen mit Farben auseinander gesetzt.
Was ich gelernt habe:
1. Verwende sRGB um Farben zu speichern.
2. Wenn es einen Alpha Kanal gibt, verwende premultiplied Alpha.
Nur was mache ich wenn ich Farben + Alpha speichern möchte? Der Alpha Kanal wird nicht Gamma korrigiert, d.h. linear gehalten, aber was mache ich mit den Farbkanälen? Sollte ich Color_srgb = alpha * lin_to_srgb(Color_linear) oder Color_srgb = lin_to_srgb(alpha * Color_linear) rechnen? Gibt es da eine wichtige Regel, die ich noch nicht kenne oder kommt es darauf an, was ich machen möchte?
Edit: Latex tag kaputt?
sRGB + Alpha
Re: sRGB + Alpha
Ich glaube das hat sich so eben selbst beantwortet :D
Es muss Color_srgb = alpha * lin_to_srgb(Color_linear) sein, denn sonst funktioniert die kurze Formel (siehe https://en.wikipedia.org/wiki/Alpha_com ... r_operator ) für das alpha compositing nicht mehr korrekt.
Es muss Color_srgb = alpha * lin_to_srgb(Color_linear) sein, denn sonst funktioniert die kurze Formel (siehe https://en.wikipedia.org/wiki/Alpha_com ... r_operator ) für das alpha compositing nicht mehr korrekt.
- Schrompf
- Moderator
- Beiträge: 5074
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: sRGB + Alpha
Hm. Nö. Eigentlich sollte auch Dein RenderTarget noch im Linear Color Space sein. Und die Konvertierung nach srgb passiert im Post Processing, z.B. als Teil des Tone Mappings.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Re: sRGB + Alpha
Die Antwort passt doch nicht auf die Frage?
Ich fummele eigentlich überhaupt nicht mit den Farben herum, sondern lese 6:6:6 Bit RGB im sRGB Format ein und möchte daraus 8:8:8:8 Bit ARGB in sRGB machen, welches dann angezeigt werden kann. Bei den original 6:6:6 Bit Daten ist eine Farbe als „transparent“ ausgezeichnet. Mein Ziel-Alpha ist also immer entweder 255 oder 0. Die Farbkanäle muss ich von 6 Bit auf 8 Bit interpolieren.
Meine Frage war also nicht für meinen speziellen Fall ausgelegt, sondern für einen allgemeineren Fall, wo der Alpha Wert nicht 0 oder MAX ist.
Ich fummele eigentlich überhaupt nicht mit den Farben herum, sondern lese 6:6:6 Bit RGB im sRGB Format ein und möchte daraus 8:8:8:8 Bit ARGB in sRGB machen, welches dann angezeigt werden kann. Bei den original 6:6:6 Bit Daten ist eine Farbe als „transparent“ ausgezeichnet. Mein Ziel-Alpha ist also immer entweder 255 oder 0. Die Farbkanäle muss ich von 6 Bit auf 8 Bit interpolieren.
Meine Frage war also nicht für meinen speziellen Fall ausgelegt, sondern für einen allgemeineren Fall, wo der Alpha Wert nicht 0 oder MAX ist.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: sRGB + Alpha
Neineinein. Blending (also die Multiplikation mit Alpha) muss im linearen Farbraum, vor der Konvertierung zu sRGB stattfinden! Also Color_srgb = lin_to_srgb(alpha * Color_linear).Biolunar hat geschrieben:Ich glaube das hat sich so eben selbst beantwortet :D
Es muss Color_srgb = alpha * lin_to_srgb(Color_linear) sein, denn sonst funktioniert die kurze Formel (siehe https://en.wikipedia.org/wiki/Alpha_com ... r_operator ) für das alpha compositing nicht mehr korrekt.
Eine nützliche Veröffentlichung dazu ist Alex Vlachos (Valve) – Post Processing in The Orange Box.
Da siehst du auf Seite 6 (unter der Überschrift DX9), wie deine Formel aussieht – D3D 9-GPUs haben Leistung gespart, indem sie Alpha auf sRGB angewendet haben statt auf lineare Farben.
Eine Seite weiter (Überschrift DX10 & X360) siehst du, wie es aussehen soll – D3D 10 und XBox 360 wenden Alpha richtigerweise auf lineare Daten an.
Das Paper hat noch weitere Vergleiche, die sollten dir einen recht guten Eindruck vermitteln.
Re: sRGB + Alpha
Hmmm. Okay.
Das scheint mir entweder sehr viel hin und her Rechnerei für jeden Farbkanal pro Pixel zu sein, wenn ich die Farben als sRGB im Speicher halte, oder sehr viel Speicher zu schlucken, wenn ich die linearen Farben im Speicher halte. Ich verwende im Übrigen noch keine GPU zur Beschleunigung.
Folgendes Szenario: Hintergrund Landschaft wird aus einer Tilemap generiert und in den Backbuffer gezeichnet. Nun werden Figuren als Sprites auf den Hintergrund gezeichnet. Hintergrund hat keine Alpha-Informationen; die Sprites schon. Das Windowing System erwartet alle Farben als ARGB8888 mit premultiplied Alpha.
Entscheide ich mich dazu Speicher zu sparen, liegen alle Bilder als ARGB8888 im Speicher (sRGB) und nicht als 4 × float pro Pixel (linear). Ich zeichne nun den Hintergrund, wobei kein Blending notwendig ist. Nun möchte ich eine Sprite darauf zeichen. Also lese ich die Pixel im Backbuffer und aus der Sprite aus, konvertiere die uint32_t zu 4 × float, transformiere diese in den linearen Farbraum und blende beide Pixel mit dem jeweiligen Alpha. Nun transformiere ich den resultierenden Pixel wieder zu sRGB, konvertiere von 4 × float wieder zu uint32_t und schreibe das Ergebnis wieder in den Backbuffer.
Entscheide ich mich dafür alle Bilder gleich als 4 × float (linear) im Speicher zu halten, spare ich die ganzen Konvertierungen und muss nur einmal konvertieren, wenn ich den ARGB8888 Backbuffer befülle, muss dafür aber den vierfachen Speicherplatz reservieren.
Sehe ich das so richtig?
Das scheint mir entweder sehr viel hin und her Rechnerei für jeden Farbkanal pro Pixel zu sein, wenn ich die Farben als sRGB im Speicher halte, oder sehr viel Speicher zu schlucken, wenn ich die linearen Farben im Speicher halte. Ich verwende im Übrigen noch keine GPU zur Beschleunigung.
Folgendes Szenario: Hintergrund Landschaft wird aus einer Tilemap generiert und in den Backbuffer gezeichnet. Nun werden Figuren als Sprites auf den Hintergrund gezeichnet. Hintergrund hat keine Alpha-Informationen; die Sprites schon. Das Windowing System erwartet alle Farben als ARGB8888 mit premultiplied Alpha.
Entscheide ich mich dazu Speicher zu sparen, liegen alle Bilder als ARGB8888 im Speicher (sRGB) und nicht als 4 × float pro Pixel (linear). Ich zeichne nun den Hintergrund, wobei kein Blending notwendig ist. Nun möchte ich eine Sprite darauf zeichen. Also lese ich die Pixel im Backbuffer und aus der Sprite aus, konvertiere die uint32_t zu 4 × float, transformiere diese in den linearen Farbraum und blende beide Pixel mit dem jeweiligen Alpha. Nun transformiere ich den resultierenden Pixel wieder zu sRGB, konvertiere von 4 × float wieder zu uint32_t und schreibe das Ergebnis wieder in den Backbuffer.
Entscheide ich mich dafür alle Bilder gleich als 4 × float (linear) im Speicher zu halten, spare ich die ganzen Konvertierungen und muss nur einmal konvertieren, wenn ich den ARGB8888 Backbuffer befülle, muss dafür aber den vierfachen Speicherplatz reservieren.
Sehe ich das so richtig?
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: sRGB + Alpha
Ja, ganz genau.
sRGB ohne Hardware-Beschleunigung ist unfassbar hässlich. So ist das eben. pow(rgb, 1/2.4) bei der linear-zu-sRGB-Konvertierung wird sofort zum Flaschenhals und lässt sich mit Taylor-Polynom etc. nur sehr schwer annähern. Selbst hoch optimierter Code wie rygs braucht noch einige Takte pro Pixel.
Das ist übrigens genau der Grund, warum wir überhaupt GPUs haben und nicht nur auf der CPU rechnen. Nutz also die GPU, sobald du kannst ;)
sRGB ohne Hardware-Beschleunigung ist unfassbar hässlich. So ist das eben. pow(rgb, 1/2.4) bei der linear-zu-sRGB-Konvertierung wird sofort zum Flaschenhals und lässt sich mit Taylor-Polynom etc. nur sehr schwer annähern. Selbst hoch optimierter Code wie rygs braucht noch einige Takte pro Pixel.
Das ist übrigens genau der Grund, warum wir überhaupt GPUs haben und nicht nur auf der CPU rechnen. Nutz also die GPU, sobald du kannst ;)