Correzione gamma e perché è importante

Se sei uno sviluppatore di giochi, probabilmente hai sentito parlare dei termini gamma e correzione gamma. Tu puoi o non puoi sapere cosa significano, ma non dovrebbero essere liquidati alla leggera.

Gli sviluppatori di giochi tendono ad ignorare gamma perché i suoi effetti sono abbastanza sottili da essere approssimativamente corretti regolando intensità luminose, intensità speculari e simili, ma per ottenere una qualità dell'immagine reale con un'illuminazione dall'aspetto realistico, è importante capire il valore gamma ei passaggi necessari per aggirare la sua presenza nell'imaging digitale, in modo da ricevere la migliore qualità possibile. L'applicazione corretta della correzione della gamma è uno dei modi più semplici per migliorare radicalmente l'aspetto della grafica 3D in tempo reale.

Introduzione: come funzionano i monitor

I monitor CRT originariamente utilizzati per i display dei computer hanno una proprietà curiosa: la risposta cromatica sui loro schermi è non lineare rispetto ai valori non elaborati passati dalla scheda grafica. 

Non lineare, in questo senso, significa che l'aumento di una delle componenti del colore di un rapporto costante (ad esempio, se un componente rosso di un colore diventa due volte più alto) non determinerà un aumento dell'intensità della luce emessa dal monitor quello stesso rapporto (cioè, la luce rossa emessa dallo schermo lo farà non essere due volte più alto).

La risposta cromatica di un monitor CRT è in realtà un esponenziale funzione. (Come in tutta la fisica, questo è molto più complesso di quanto stiamo descrivendo, ma per ragioni di semplicità, ci atterremo a questa ipotesi.) Cioè, la funzione EmittedLight (C), dove C è un valore di componente di colore (rosso, verde o blu) che va da 0 (nessuna luce) a 1 (piena intensità della luce), è C elevato a qualche potere γ

Questo numero, γ, è chiamato il gamma esponente o semplicemente gamma. I valori gamma tipici vanno da 2,0 a 2,4, e quando si ha a che fare con la gamma in senso generale, il valore è concordato per essere 2.2 come compromesso, e molti nuovi monitor sono progettato avere il valore gamma di esattamente 2.2

In uno scenario comune di gamma = 2.2, questo è il modo in cui il monitor visualizza effettivamente intensità di colore dal tuo gioco (curva verde). La linea tratteggiata in rosso mostra come un monitor lineare mostrerebbe le stesse intensità.

In pratica, ciò significa che il bianco e nero sarà mostrato senza distorsioni sullo schermo (perché lo zero elevato a qualsiasi potenza è zero, e uno elevato a qualsiasi potenza è uno), ma tutti i valori intermedi saranno distorti senza un modo affidabile di percepire questo succede solo guardando. 

Ad esempio, se stai visualizzando un colore che è presumibilmente due volte più scuro del nero, ovvero, RGB (0,5, 0,5, 0,5)-verrà effettivamente mostrato come inferiore a quattro tempi più scuri, dato il valore gamma comune di 2,2, poiché 0,5 elevato a 2,2 è intorno a 0,22. Chiaramente, questo non è quello che intendi, e questo non è il caso solo con i monitor CRT: LCD, mentre no involontariamente avendo questa proprietà, sono progettati per essere compatibili con le loro controparti più vecchie, e quindi visualizzare i tuoi valori di colore allungati come questo.

Inoltre, poiché i componenti rosso, verde e blu vengono trattati in modo indipendente, le tonalità di colore desiderate delle immagini possono essere facilmente alterate in quanto le intensità delle tre componenti cromatiche non si ridimensionano in modo uniforme. Cosa succederà quando visualizzi il valore del colore RGB (1, 0,5, 0,5)? Il componente rosso rimarrà a 1, ma gli altri scenderanno a metà dei loro valori, cambiando completamente il tono del tuo colore.

Il secondo colore è stato ottenuto dal primo applicando la scala non lineare utilizzata dai monitor. Si noti come non solo la luminosità del colore, ma anche la sua saturazione, è stata influenzata da questa trasformazione.

Ora che abbiamo visto quali effetti ha questa proprietà del monitor sui dati di colore dati al monitor, possiamo vedere quali passi ci sono per combatterli.

Cos'è la correzione gamma?

La correzione gamma è l'atto di annullare il lavoro sfortunato del monitor. La correzione cromatica di un'immagine sta essenzialmente aumentando le sue intensità di colore 1 / gamma, in modo che quando il monitor a sua volta aumenta il valore gamma, questi si cancellano e il risultato è il colore che originariamente intendevamo mostrare. 

(Ricordatelo UN elevato a B, e poi cresciuto a C, equivale a UN elevato a B × C, ed è per questo che queste operazioni si annulleranno, come gamma × (1 / gamma) è 1.) 

Poiché l'utente medio non calibra il proprio monitor per avere una risposta lineare, molte immagini che incontrano vengono corrette in modo che non sentano mai la differenza. Come convenzione, la maggior parte dei file di immagine su Internet sono distribuiti in quello che viene chiamato il Spazio colore sRGB-questo significa che i valori cromatici originali e previsti sono approssimativamente elevato al potere di 1 / 2.2 prima di metterli in file (anche se nella realtà sono presenti equazioni più complesse). Ciò garantisce che tutti gli utenti con display convenzionali vedano i colori reali. Scanner, videocamere e molti dispositivi di acquisizione di immagini digitali tengono conto di tutto ciò e correggono il loro output quando salvate nei formati di immagine convenzionali.

Questa immagine mostra la mappatura delle intensità del colore inviate al monitor dalla scheda grafica e le intensità visualizzate dal monitor.

Dai un'occhiata all'immagine qui sopra. Se non consideriamo la gamma, la curva sarà esponenziale (curva verde più bassa). Se eseguiamo la correzione della gamma, la risposta effettiva sarà lineare, come dovrebbe essere. Per confronto, l'immagine mostra anche come appare il grafico quando eseguiamo la correzione gamma ma il monitor ha effettivamente una risposta lineare. In questo caso, le intensità saranno distorte in modo opposto, e possiamo vedere che quando un monitor non lineare le distorce a sua volta, questo si annulla e finiamo con una linea diritta.

Quando devo preoccuparmi?

Finora, abbiamo spiegato la teoria alla base di questi fenomeni - certo, i monitor non sono lineari e la maggior parte delle immagini viene corretta in modo da sembrare corretta su questi monitor, ma quale sembra essere il problema? Perché dovrei, aspirante sviluppatore di giochi 3D, occuparmi della correzione gamma e fare qualsiasi altra cosa appena sapendo a proposito?

La risposta è semplice: finché le immagini vengono create solo per essere visualizzate, il problema in realtà non esiste nemmeno. Tuttavia, non appena vuoi che un programma faccia qualcosa a queste immagini (ridimensionale, usale come trame, lo chiami), devi fare in modo che il programma sappia che i valori sono non reale e sono semplicemente corretti in modo che loro sembra reale su un monitor.

In particolare, ciò accade in un renderer quando prende come input le mappe di texture, come le superfici diffuse. Esegue operazioni su di essi assumendo che i loro valori cromatici rappresentino accuratamente intensità luminose; cioè, assumendo a corrispondenza lineare con i fenomeni della vita reale che rappresentano.

Ma questo è un errore fondamentale: se si vogliono sommare i valori del colore e sono corretti alla gamma (elevato a 1 / gamma) ottieni i valori sbagliati. Non ci vuole un genio della matematica per rendersene conto UN elevato a 1 / gamma più B elevato a 1 / gamma non è uguale (A + B) elevato a 1 / gamma. Il problema si verifica anche quando un riproduttore emette alcuni valori, ad esempio quando emette contributi leggeri: se lo fa somme due contributi leggeri ma non sa che il risultato sarà elevato a gamma quando visualizzato sullo schermo, ha prodotto sbagliato valori.

Ed è proprio qui che si verifica il problema: ogni volta che un riproduttore assume che i colori ottengono linearmente i fenomeni della vita reale quando non lo fanno, o presume che i colori che emette corrisponderanno linearmente alle intensità luminose sullo schermo quando avranno vinto " t, ha commesso un errore piuttosto grave che può influenzare l'aspetto delle immagini che produce.

Se non correggi nessuno degli errori, non assicurarti che i colori di trama dell'input inseriti nel renderer siano lineari e non assicurarti che l'immagine di output del renderer sia lineare rispetto allo schermo, queste immagini annulleranno ciascuna altri in una certa misura, proprio come il modo in cui cancellano ciascuno quando mostra file JPEG precorretti in un browser web. Tuttavia, non appena includi alcuni calcoli intermedi che assumono corrispondenze lineari, la tua matematica sarà errata.


(un) Non correggere trame e non correggere l'immagine finale, (B) non correggendo le trame ma correggendo l'immagine finale, (C) correggere le trame ma non correggere l'immagine finale, (D) correggendo sia le trame che l'immagine finale.

Ricordiamo ciò che abbiamo detto sul cambiamento delle tonalità di colore in precedenza: questo fatto può (a volte) aiutarti a individuare la non-linearità. Una regola pratica è la seguente: se, applicando le regolazioni lineari ai parametri (come il raddoppio della luminosità delle luci nella scena), l'immagine risultante cambia non solo nella luminosità ma anche nelle tonalità dei colori (ad esempio, un'area che va da una tonalità rosso-arancio verso il giallo), ciò significa che è probabile che alcuni processi intermedi non lineari si verifichino.

Ciò può accadere con mappe di texture recuperate da varie fonti: Internet, una fotocamera digitale che salva in sRGB JPEG, uno scanner o se la texture è stata dipinta su un monitor che non è stato calibrato in modo esplicito per avere una risposta lineare o non esplicitamente corretto in seguito. Qualsiasi calcolo matematico eseguito su queste mappe di texture sarà errato e devierà leggermente dai valori teoricamente corretti. Ciò è visibile con il filtraggio delle texture e le mipmap: poiché il filtraggio assume le risposte lineari durante la media dei valori dei colori, si noteranno degli errori pronunciati: le trame più piccole (quelle distanti) appariranno più scure di quelle più grandi (cioè quando sono più vicine a te): questo perché quando sono distanti, l'algoritmo di filtraggio fa una media di più campioni e la loro non-linearità influenza maggiormente il risultato.

L'illuminazione risentirà anche di una gamma impropria: contributi leggeri alle superfici somma nel mondo reale, e di conseguenza in un renderer, ma la somma non è un'operazione fedele se il risultato è distorto non linearmente. Se hai complessi ombreggiatori di frammenti che eseguono un'illuminazione sofisticata, come la dispersione subsuperficiale o l'HDR, gli errori diventano sempre più pronunciati, fino al punto che tu in realtà mi chiedo che cosa c'è di sbagliato nell'immagine, piuttosto che avere una sensazione inquietante di "forse un po 'di luce sbagliata, ma probabilmente sono solo io" che può anche accadere spesso. Oscurare le trame o illuminare le immagini finali con un fattore costante o lineare non uccidere l'effetto, perché sono anche operazioni lineari, e hai bisogno di uno non lineare per combattere la curva di risposta esponenziale inerente che si verifica nel monitor.

Come lo aggiusto?

Ora, si spera, tu sia pienamente consapevole di cosa sono la correzione gamma e gamma, e perché questo è un grosso problema quando si fa grafica 3D in tempo reale. Ma, ovviamente, ci deve essere un modo per risolvere questi problemi? 

La risposta è sì, e la correzione della gamma è un'operazione piuttosto semplice che non richiede di cambiare nulla oltre all'aggiunta di poche righe di codice, senza contare ulteriori parametri, intensità e ritocchi di colore che sarà necessario eseguire per ottenere la giusta illuminazione se hai impostato le tue scene per avere un bell'aspetto su monitor non lineari senza correggerli. 

Ci sono tre passaggi fondamentali per assicurarti di rimanere lineare il più a lungo possibile e fare la correzione al punto giusto:

1. Assicurati che i colori della trama siano corretti

Normalmente non dovresti modificare le immagini sorgente in modo che contengano colori lineari; la correzione della gamma dei colori per il monitor tipico in campi di colore a otto bit offre la necessaria risoluzione aggiuntiva nelle aree più scure in cui l'occhio umano è più sensibile alle variazioni di intensità. Tuttavia, puoi assicurarti che i valori dei colori siano lineari prima che raggiungano gli shader. 

Normalmente, in OpenGL, puoi farlo passando GL_SRGB8 invece di GL_RGB8, e GL_SRGB8_ALPHA8 invece di GL_RGBA8, a glTexImage2D (), quando si specifica una trama. Questo lo garantirà tutti i valori letti da questa trama attraverso un campionatore di shader verranno corretti dallo spazio colore sRGB a uno lineare, che è esattamente ciò di cui abbiamo bisogno! Se stai utilizzando un motore di rendering o di gioco che ti carica le texture, potrebbe tenerne conto o potrebbe essere necessario specificarlo manualmente; consulta la documentazione della biblioteca o chiedi aiuto a qualcuno se non sei sicuro.

Tuttavia, assicurati di non farlo erroneamente per immagini che, per definizione, non rappresentano informazioni sul colore, e sono state esplicitamente dipinte con questo in mente. Gli esempi includono mappe normali, mappe di rilievi o mappe di altezza, che codificano tutti dati diversi dal colore nei canali di colore di una trama e quindi non hanno probabilmente bisogno di questo tipo di precorrezione.

Dalla demo inclusa in questo articolo (alcuni parametri scambiati con i loro valori reali per chiarezza):

glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB8, larghezza, altezza, 0, GL_BGR, GL_UNSIGNED_BYTE, dati); 

Questo caricherà la trama in uno spazio cromatico non corretto. Tuttavia, se i dati nel file texture sono nello spazio colore sRGB, dovremmo modificare il terzo parametro in GL_SRGB8, cedendo:

glTexImage2D (GL_TEXTURE_2D, 0, GL_SRGB8, larghezza, altezza, 0, GL_BGR, GL_UNSIGNED_BYTE, dati);

Ciò assicurerà che OpenGL corregge i dati della trama quando li cerchiamo.

2. Assicurati che i colori dell'immagine di uscita siano corretti

Ora devi applicare la correzione del colore alle immagini di output finali del tuo renderer. Assicurati di non applicare correzioni a tutto tranne che al finale framebuffer che deve essere visualizzato sullo schermo. (Non toccare i buffer intermedi immessi in altri shader di post-elaborazione, poiché questi si aspettano ancora di lavorare con valori lineari). 

Questo può essere fatto in OpenGL specificando il renderbuffer (il framebuffer finale non campionabile) per avere una codifica del colore sRGB passando GL_SRGB invece di GL_RGB come parametro per glRenderbufferStorage (). Dopo ciò, devi aumentare il GL_FRAMEBUFFER_SRGB flag chiamando glEnable. In questo modo, le scritture shader sui buffer sRGB verranno corrette in modo che vengano visualizzate direttamente su un monitor tipico. 

Se stai usando un motore o un framework, probabilmente include un qualche tipo di opzione per creare un frame buffer sRGB per te e configurarlo correttamente. Di nuovo, puoi consultare la documentazione della biblioteca o chiedere a qualcuno di chiarire questo per te.

Nella demo, usiamo la libreria GLFW, che ci offre un modo indolore per richiedere un framebuffer sRGB. In particolare, impostiamo un suggerimento per le finestre e, successivamente, diamo a OpenGL di abilitare le operazioni del framebuffer nello spazio sRGB:

glfwWindowHint (GLFW_SRGB_CAPABLE, TRUE); ... glEnable (GL_FRAMEBUFFER_SRGB);

3. Correggi le tue intensità di luce ottimizzata e i parametri del colore

Se questo non è l'inizio di un nuovo progetto, è probabile che l'illuminazione e il filtraggio gamma-non corretti abbiano causato il loro pedaggio. Forse hai perfezionato i tuoi colori di riflettanza diffusa, l'intensità della luce e quant'altro nel tentativo di sopperire a fastidi lievi che trascurare la gamma ti ha portato. 

È necessario rivedere questi valori ancora una volta e modificarli in modo che appaiano di nuovo in ordine, tuttavia, questa volta, le scene appariranno più naturali a causa dell'illuminazione che rappresenta in modo più accurato le circostanze del mondo reale. Gli angoli non appariranno troppo scuri, quindi non sarà necessario aggiungere più intensità alle luci (distruggendo così l'illuminazione degli oggetti più luminosi che appariranno quindi artificialmente luminosi per quella quantità di luce nella scena). 

Questo ripaga: rivisitare i tuoi parametri per creare un ambiente naturale con la correzione della gamma farà molto per fornire ai tuoi utenti un'esperienza e una distribuzione della luminosità che sembra giusta per i loro occhi, così abituati e sensibili a come la luce funziona nella vita reale.

dimostrazione

In questo articolo è inclusa una piccola demo di OpenGL 3.3 che mostra una scena semplice con alcune trame illuminate da due sorgenti luminose mobili. Ti consente di alternare diversi scenari: non correggere le trame ma correggere l'immagine finale; correggere le trame ma trascurare di correggere l'immagine finale; correggendo entrambi (cioè, facendo tutto bene); e non riuscendo a correggere entrambi (effettivamente facendo un doppio errore). 

La demo è scritta in C ++ (con due shader GLSL) e utilizza librerie portatili GLFW e GLEW, quindi dovrebbe essere eseguita su un'ampia varietà di piattaforme. Il codice sorgente è ricco di commenti in modo da poter esplorare ed esplorare ogni aspetto di questa breve applicazione.

La demo in azione.

Utilizzare il 1 tasto sulla tastiera per scorrere tra le trame di correzione e non correggere le trame, e il 2 tasto per passare tra la correzione del framebuffer e la mancata correzione del framebuffer. Per ciclare entrambi allo stesso tempo, premere 3-utile per vedere la differenza tra trascurare completamente gamma (due errori che si annullano a vicenda per la maggior parte) e fare tutto bene. Quando inizia la demo, nessuna di queste correzioni viene eseguita, quindi colpita 3 per vedere i benefici della corretta correzione della gamma.

Ho incluso un progetto Microsoft Visual C ++ 2013, versioni compatibili a 64 bit delle librerie GLFW e GLEW e un eseguibile di Windows a 64 bit. Tuttavia, è possibile compilare questo piuttosto facilmente su qualsiasi piattaforma con supporto GLFW e GLEW: basta compilare main.cpp e loader.cpp insieme e collegarli a quelle due librerie. Su Linux, l'installazione di queste librerie tramite il gestore di pacchetti e il passaggio -lglew -lglfw a g++ dovrebbe fare il trucco (Si noti che questo non è stato testato su sistemi operativi diversi da Windows, ma dovrebbe funzionare - se si riscontrano problemi, fatemelo sapere nei commenti e li risolverò il prima possibile.)

Come puoi vedere durante l'esecuzione della demo, gli effetti sono abbastanza evidenti anche con un modello semplice e una scena semplice come questa. Ovviamente, in questo semplice caso, potresti riuscire a farla finita con il tweaking dei parametri dello shader in modo che l'immagine risulti corretta quando non corretta. Tuttavia, non appena inizi a creare complessità nelle tue scene, la differenza sarà semplicemente troppo visibile per compensare in questo modo.

Conclusione

In questo articolo abbiamo trattato termini come gamma, correzione gamma, input e output non lineari e matematica non lineare. Spero di essere riuscito a convincerti che dovresti iniziare a preoccuparti della correzione della gamma in questo momento se l'avessi trascurata fino ad ora, e se sei stato attento con la gamma prima di incontrare questo articolo, spero solo che ti abbia dato qualche nuovo piccola informazione per affrontare il problema. 

Abbiamo, soprattutto, imparato come risolvere i problemi che sorgono quando si fanno manipolazioni errate sui valori dei colori, supponendo che siano lineari e abbiamo esaminato le insidie ​​e i sintomi comuni che si verificano quando si trascura questo importante aspetto della computer grafica.

Spero ti sia divertito e abbia imparato qualcosa di nuovo mentre leggi questo articolo. Fino alla prossima volta!