Gama de corecție și de ce contează

Dacă ești un dezvoltator de jocuri, probabil ai auzit de termeni gamma și corecție gamma. Puteți sau nu să știți ce înseamnă, dar nu ar trebui să fie ușor respinși.

Dezvoltatorii de jocuri tind să ignore gamma, deoarece efectele sale sunt destul de subtile pentru a fi corectate prin ajustarea intensităților luminoase, a intensităților speculare și altele asemenea, dar pentru a obține o adevărată calitate a imaginii cu un iluminat realist, este important să înțelegeți valoarea gamma și pașii necesari pentru a lucra în jurul prezenței sale în imagistica digitală, pentru a obține cea mai bună calitate posibilă. Aplicarea corectă a corecției gamma este una din modalitățile cele mai ușoare de a îmbunătăți radical aspectul graficelor 3D în timp real.

Introducere: Cum funcționează monitorii

Monitoarele CRT care au fost utilizate inițial pentru afișaje pe computer au o proprietate curioasă: răspunsul de culoare pe ecranele lor este non-linear în ceea ce privește valorile brute transferate de pe placa grafică. 

Non-linear, în acest sens, înseamnă că o creștere a uneia dintre componentele dvs. de culoare cu un raport constant (de exemplu, dacă o componentă roșie a unei culori devine de două ori mai mare) nu va duce la o creștere a intensității luminii emise de monitor prin acelasi raport (adica, lumina rosie emisa de pe ecran va nu să fie de două ori mai mare).

Răspunsul color al unui monitor CRT este de fapt un răspuns exponențială funcţie. (La fel ca în toată fizica, aceasta este mult mai complexă decât o descriem, dar, din simplitate, vom rămâne la această presupunere.) Asta este funcția EmittedLight (C), Unde C este o componentă de culoare (roșu, verde sau albastru) care variază de la 0 (fără lumină) la 1 (intensitatea luminii totale), este C ridicată la o anumită putere γ

Acest număr, γ, este numit exponentul gamma sau doar gamma. Valorile tipice ale gamma variază de la 2,0 la 2,4, iar atunci când se ocupă de gamma în sensul general, valoarea este de acord să fie de 2.2 ca un compromis și o mulțime de monitoare mai noi proiectat pentru a avea valoarea gamma exact de 2,2

Într-un scenariu comun de gamma = 2.2, acesta este modul în care monitorul afișează de fapt intensitățile de culoare din joc (curba verde). Linia roșie punctată arată modul în care un monitor liniar ar afișa aceleași intensități.

În practică, acest lucru înseamnă că alb-negru va fi arătat nedistorsionat pe ecran (deoarece zero ridicată la orice putere este zero și una ridicată la orice putere este una), dar toate valorile între ele vor fi înclinate fără o modalitate sigură de a percepe acest lucru se întâmplă doar prin vizionarea. 

De exemplu, dacă afișați o culoare care se presupune că este de două ori mai întunecată decât negrul - adică, RGB (0,5, 0,5, 0,5)-acesta va fi de fapt prezentat ca fiind mai puțin decât patru ori mai întunecată, având în vedere valoarea comună gamma de 2,2, deoarece 0,5 ridicată la 2,2 este în jur de 0,22. În mod clar, acest lucru nu este ceea ce intenționați, și acest lucru nu este cazul doar cu monitoare CRT: LCD-uri, în timp ce nu fara intentie având această proprietate, sunt proiectate să fie compatibile cu omologii lor mai vechi, și astfel să vă afișeze valorile de culoare întinse astfel.

În plus, deoarece componentele roșii, verzi și albastre sunt tratate independent, tonurile de culori intenționate ale imaginilor pot fi umezite cu ușurință, deoarece intensitățile celor trei componente de culoare nu se vor micșora uniform. Ce se va întâmpla când afișați valoarea culorii RGB (1, 0,5, 0,5)? Componenta roșie va rămâne la 1, dar celelalte vor scădea la jumătate din valorile lor, modificând complet tonul culorii.

Cea de-a doua culoare a fost obținută de la prima prin aplicarea barei neliniare pe care monitorii o folosesc. Observați că nu numai luminozitatea culorii, ci și saturația acesteia au fost afectate de această transformare.

Acum, că am văzut ce efecte are această proprietate a monitorului asupra datelor de culoare date monitorului, putem vedea ce pași există pentru a le combate.

Ce este Corecția Gamma??

Corecția gama este actul de a anula munca nefericită a monitorului. Îmbunătățirea gama a unei imagini crește în mod esențial intensitățile de culoare 1 / gamma, astfel încât atunci când monitorul ridică la rândul său valoarea gamma, acestea se anulează și rezultatul este culoarea pe care intenționăm să o afișăm inițial. 

(Sa nu uiti asta A ridicată la B, și apoi ridicat la C, este la fel ca A ridicată la B × C, și de aceea aceste operațiuni se vor anula, ca urmare gamma x (1 / gamma) este 1.) 

Deoarece utilizatorul mediu nu calibrează monitorul pentru a avea un răspuns liniar, multe imagini pe care le întâlnesc sunt corectate astfel încât să nu simtă niciodată diferența. Ca o convenție, majoritatea fișierelor de imagini de pe Internet sunt distribuite în ceea ce se numește spațiul de culoare sRGB-acest lucru înseamnă că valorile originale, intenționate ale culorii sunt aproximativ ridicat la puterea de 1 / 2.2 înainte de a le pune în fișiere (deși au loc ecuații mai complexe în realitate). Acest lucru asigură că toți utilizatorii cu afișaje convenționale văd culorile reale. Scanerele, camerele de luat vederi și o mulțime de dispozitive digitale de imagine iau acest lucru în considerare și își corectează performanța pentru dvs. atunci când salvați în formate de imagine convenționale.

Această imagine prezintă cartografia intensităților de culoare trimise monitorului de placa grafică și intensitățile afișate de monitor.

Uitați-vă la imaginea de mai sus. Dacă nu luăm în considerare gama, curba va fi exponențială (curba inferioară verde). Dacă efectuăm corectarea gama, răspunsul real va fi liniar, așa cum ar trebui să fie. Pentru comparație, imaginea arată, de asemenea, cum arată graficul când efectuăm corecția gamma, dar monitorul are de fapt un răspuns liniar. În acest caz, intensitățile vor fi distorsionate în mod opus și vom vedea că atunci când un monitor neliniar le distorsionează la rândul său, acest lucru se anulează și ajungem cu o linie dreaptă.

Când trebuie să mă îngrijorez?

Până acum, am explicat teoria din spatele acestor fenomene - sigur, monitorii sunt neliniari și majoritatea imaginilor sunt corectate, astfel încât acestea să arate exact pe aceste monitoare, dar ceea ce pare a fi problema? De ce ar trebui, eu, un aspirant dezvoltator de jocuri 3D, să mă îngrijoreze cu corecția gamma și să fac orice altceva doar cunoaștere despre?

Răspunsul este simplu: atâta timp cât imaginile sunt create doar pentru a fi afișate, problema chiar nu există. Cu toate acestea, de îndată ce vreți ca un program să facă ceva la aceste imagini (să le scalați, să le utilizați ca texturi, să le numiți), trebuie să aveți grijă ca programul să știe că valorile sunt nu este real și sunt doar corectate, astfel încât acestea arata real pe un monitor.

În mod particular, acest lucru se întâmplă într-un renderer atunci când este nevoie de hărți de texturi, cum ar fi suprafețe difuze. Acționează asupra lor presupunând că valorile lor de culoare reprezintă cu exactitate intensitățile luminoase; adică, presupunând a corespondență liniară cu fenomene din viața reală pe care le reprezintă.

Dar aceasta este o eroare fundamentală: dacă doriți să însumați valorile culorilor și acestea sunt corectate la gamă (ridicate la 1 / gamma) obțineți valori greșite. Nu are nevoie de un geniu de matematică pentru a realiza acest lucru A ridicată la 1 / gamma la care se adauga B ridicată la 1 / gamma nu este egal (A + B) ridicată la 1 / gamma. Problema se întâmplă, de asemenea, atunci când un renderer emite unele valori, cum ar fi atunci când emite contribuții ușoare: dacă este sume două contribuții ușoare, dar nu știe că rezultatul va fi ridicat la gama atunci când este afișat pe ecran, pe care la produs gresit valorile.

Și tocmai aici apare problema: ori de câte ori un renderer presupune că culorile pe care le primește corespund liniar cu fenomenele din viața reală atunci când nu le acceptă sau presupune că culorile pe care le emite vor corespunde liniar intensităților luminoase pe ecran când vor câștiga " t, sa produs o eroare destul de gravă care poate afecta aspectul imaginilor pe care le produce.

Dacă nu corectați nici o greșeală, nu vă asigurați că culorile textură introduse în randare sunt lineare și nu vă asigurați că imaginea de ieșire a imaginii de randare va fi liniară în raport cu ecranul, aceste imagini vor anula fiecare altele într-o anumită măsură, la fel cum anulează fiecare când afișează fișiere JPEG pre-corectate într-un browser web. Cu toate acestea, de îndată ce includeți câteva calcule intermediare care presupun corespondențe liniare, matematica dvs. va fi greșită.


(A) Nu corectează texturile și nu corectează imaginea finală, (B) nu corectează texturile, ci corectează imaginea finală, (C) corectarea texturilor, dar nu corectarea imaginii finale, (D) corectând texturile și imaginea finală.

Amintiți-vă ce am spus despre schimbarea tonurilor de culoare mai devreme - acest fapt poate (uneori) vă ajută să observați non-linearitatea. O regulă de bază este: dacă, atunci când aplicați parametrii liniari la parametri (cum ar fi dublarea luminozității luminilor din scenă), imaginea rezultată se modifică nu numai în luminozitate, ci și în tonuri de culoare (de exemplu, o zonă care merge dintr- roșu-portocaliu spre galben), aceasta înseamnă că un proces intermediar neliniar are cel mai probabil loc.

Acest lucru se poate întâmpla în cazul hărților de texturi care au fost preluate din diferite surse - Internetul, o cameră digitală care salvează sGBGB JPEG, un scanner sau dacă textura a fost pictată pe un monitor care nu a fost calibrat în mod explicit pentru a avea un răspuns liniar sau nu în mod explicit corectată ulterior. Orice matematică făcută pe aceste hărți de textură va fi greșită și va devia ușor de la valori teoretice corecte. Acest lucru este vizibil cu filtrarea texturilor și cu mipmaps: deoarece filtrarea presupune răspunsuri liniare la media valorilor culorilor, veți observa erori pronunțate: texturile mai mici (cele îndepărtate) vor apărea mult mai întunecate decât cele mai mari (adică când vă apropiați): acest lucru se datorează faptului că, atunci când acestea sunt îndepărtate, algoritmul de filtrare avertizează mai multe eșantioane și ne-liniaritatea lor afectează rezultatul mai mult.

Iluminarea va suferi, de asemenea, de gama necorespunzătoare: contribuții ușoare la suprafețe sumă în lumea reală și, în consecință, într-un renderer, dar însumarea nu este o operație fidelă dacă rezultatul este neclinic înclinat. Dacă aveți shadere complexe de fragmente care fac lumină sofisticată, cum ar fi împrăștierea sub suprafață sau HDR, erorile devin din ce în ce mai accentuate, până la punctul în care vă de fapt întrebați ce este în neregulă cu imaginea, spre deosebire de a avea un sentiment neliniștit de "iluminare poate greșită cam greșit, dar probabil că sunt doar eu", ceea ce se poate întâmpla adesea. Întunecarea texturilor sau strălucirea imaginilor finale printr-un factor constant sau liniar nu ucid efectul, deoarece acestea sunt și operații liniare și aveți nevoie de o caracteristică neliniară pentru a combate curba intrinsecă a răspunsului exponențial întâmplătoare în monitor.

Cum îl pot rezolva??

Acum, sperăm că sunteți pe deplin conștienți de ce corecție gamma și gamma sunt, și de ce este așa de mare atunci când faci grafică 3D în timp real. Dar, desigur, trebuie să existe o cale de a rezolva aceste probleme? 

Răspunsul este da și fixarea gammei este o operație destul de simplă, care nu presupune schimbarea a ceva, în afară de adăugarea câtorva linii de cod, fără a lua în calcul parametrul suplimentar, intensitatea și corecțiile de culoare pe care va trebui să le efectuați pentru a obține iluminarea corectă dacă v-ați stabilit scenele pentru a arăta bine pe monitoarele neliniare fără a le corecta. 

Există trei etape de bază pentru a vă asigura că rămâneți liniar cât mai mult posibil și efectuați corectarea la punctul corect:

1. Asigurați-vă că textura dvs. are culori corecte

În mod normal, nu trebuie să modificați imaginile sursă astfel încât acestea să conțină culori lineare; având culori gama corectate pentru monitorul tipic în câmpuri de culoare de opt biți, vă oferă o rezoluție necesară în zonele mai întunecate, unde ochiul uman este mai sensibil la variațiile de intensitate. Cu toate acestea, puteți să vă asigurați că valorile de culoare sunt lineare înainte de a ajunge la shaderele dvs.. 

În mod normal, în OpenGL, puteți face acest lucru trecând GL_SRGB8 in loc de GL_RGB8, și GL_SRGB8_ALPHA8 in loc de GL_RGBA8, la glTexImage2D (), când specificați o textură. Acest lucru va asigura acest lucru toate valorile citite din această textură printr-un șablon de șablon vor fi corectate înapoi de la spațiul de culoare sRGB la cel liniar, care este exact ceea ce avem nevoie! Dacă utilizați un motor de redare sau de joc care face încărcarea texturilor pentru dvs., s-ar putea să ia în considerare acest lucru sau ar putea fi necesar să îl specificați manual; consultați documentația bibliotecii sau întrebați pe cineva pentru ajutor dacă nu sunteți sigur.

Cu toate acestea, asigurați-vă că nu faceți acest lucru în mod eronat la imagini care, prin definiție, nu reprezintă informații despre culoare și au fost explicit pictate în acest sens. Exemplele includ hărți normale, hărți bombe sau hărți înălțime, care codifică toate unele date altele decât culoarea în canalele de culoare ale unei texturi și, prin urmare, nu este probabil să aibă nevoie de acest tip de preorrecție.

Din demo-ul inclus în acest articol (unii parametri au fost înlocuiți cu valorile lor reale pentru claritate):

glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB8, lățime, înălțime, 0, GL_BGR, GL_UNSIGNED_BYTE, date); 

Aceasta va încărca textura într-un spațiu de culoare necorectat. Cu toate acestea, dacă datele din fișierul textură se află în spațiul de culoare sRGB, ar trebui să modificăm al treilea parametru GL_SRGB8, rezultând:

glTexImage2D (GL_TEXTURE_2D, 0, GL_SRGB8, lățime, înălțime, 0, GL_BGR, GL_UNSIGNED_BYTE, date);

Acest lucru va asigura că OpenGL corectează datele de textură atunci când le căutăm.

2. Asigurați-vă că culorile imaginii de ieșire sunt corecte

Acum trebuie să aplicați corecția culorilor la imaginile finale de ieșire ale redării dvs. Asigurați-vă că nu aplicați corectarea la nimic altceva decât la final framebuffer care urmează să fie afișat pe ecran. (Nu atingeți tampoanele intermediare care sunt introduse în alte shadere postprocedimentare, deoarece acestea se vor aștepta să funcționeze cu valori lineare.) 

Acest lucru se poate face în OpenGL prin specificarea renderbuffer (framebuffer final, non-sampleable) pentru a avea o codificare de culoare sRGB prin trecere GL_SRGB in loc de GL_RGB ca parametru pentru glRenderbufferStorage (). După aceea, trebuie să ridicați GL_FRAMEBUFFER_SRGB semn de apel glEnable. În acest fel, shader-ul care scrie în bufferele sRGB va fi corectat astfel încât acestea să fie afișate chiar pe un monitor tipic. 

Dacă utilizați un motor sau un cadru, probabil include o opțiune pentru a crea un framebuffer sRGB pentru dvs. și pentru ao seta corect. Din nou, puteți consulta documentația bibliotecii sau puteți cere pe cineva să vă clarifice acest lucru.

În demo, folosim biblioteca GLFW, care ne oferă o modalitate fără durere de a solicita un framebuffer sRGB. În special, am setat o sugestie de fereastră și apoi, mai târziu, spunem OpenGL pentru a permite ca operațiile framebuffer să fie în spațiul sRGB:

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

3. Fixați intensitățile dvs. de lumină tweaked și parametrii de culoare

Dacă acest lucru nu este un început al unui nou proiect, este posibil ca iluminarea și filtrarea gama incorectă să fi avut un efect asupra dvs. Poate că ți-ai modificat culorile difuzive de reflexie, intensitățile luminoase și nu în încercarea de a compensa neplăcerile subtile pe care le-a adus neglijarea gammei. 

Trebuie să treceți din nou prin aceste valori și să le optimizați, astfel încât acestea să arate bine din nou - totuși, de această dată, scenele dvs. vor arăta mai naturale, datorită faptului că iluminarea reprezintă mai exact împrejurările lumii reale. Cornerele nu vor arăta prea întunecate, astfel încât nu va trebui să adăugați o intensitate mai mare la lumini (astfel distrugând iluminarea obiectelor mai luminoase, care apoi ar arăta artificial luminoase pentru acea cantitate de lumină în scenă). 

Acest lucru se va realiza: revizuirea parametrilor dvs. pentru a crea o atmosferă naturală cu corecție gamma va merge mult spre a oferi utilizatorilor dvs. o experiență și o distribuție a luminozității, care arată exact la ochii lor, atât de obișnuiți și sensibili la modul în care lumina funcționează în viața reală.

Demo

Inclusiv cu acest articol este un mic demo OpenGL 3.3 care arată o scenă simplă cu unele texturi aprinse de două surse de lumină în mișcare. Vă permite să comutați între mai multe scenarii: nu corectați texturile, ci corectați imaginea finală; corectarea texturilor, dar neglijând corectarea imaginii finale; corectând ambele (adică făcând totul bine); și nu reușesc să corecteze (făcând în mod efectiv o dublă greșeală). 

Demo-ul este scris în C ++ (cu două shadere GLSL) și utilizează biblioteci portabile GLFW și GLEW, astfel încât ar trebui să funcționeze pe o varietate largă de platforme. Codul sursă este copiat cu comentarii, astfel încât să puteți explora și explora fiecare aspect al acestei aplicații scurte.

Demo-ul în acțiune.

Folosește 1 cheia de pe tastatură pentru a trece între corectarea texturilor și a nu corecta texturile și 2 tasta pentru a cicla între corectarea framebuffer-ului și corectarea framebuffer-ului. Pentru a le cicliza simultan, apăsați 3-util pentru a vedea diferența dintre neglijarea gammei complet (două erori care se anulează celuilalt în cea mai mare parte) și face totul drept. Când începe demo-ul, niciuna dintre aceste corecții nu este efectuată, așa că a fost lovită 3 pentru a vedea beneficiile corecției gamma corecte.

Am inclus un proiect Microsoft Visual C ++ 2013, versiuni compatibile pe 64 de biți ale bibliotecilor GLFW și GLEW și un executabil Windows pe 64 de biți. Cu toate acestea, puteți compila acest lucru destul de ușor pe orice platformă cu GLFW și GLEW suport: doar compilați main.cpp și loader.cpp împreună și leagă-le împotriva celor două biblioteci. Pe Linux, instalarea acestor biblioteci prin managerul de pachete și trecerea acestora -lglew-lglfw la g++ ar trebui să facă truc. (Rețineți că acest lucru nu a fost testat pe alte sisteme de operare decât Windows, dar ar trebui să funcționeze - dacă întâmpinați probleme, vă rugăm să ne anunțați în comentarii și le voi remedia cât mai repede posibil.)

După cum puteți vedea atunci când rulați demo-ul, efectele sunt destul de vizibile chiar și cu un model simplu și o scenă simplă ca aceasta. Desigur, în acest caz simplu, ați putea să scăpați cu modificarea parametrilor de shader, astfel încât imaginea să arate bine atunci când este necorectată. Cu toate acestea, de îndată ce începeți să construiți complexitatea în scenele dvs., diferența va fi pur și simplu prea vizibilă pentru a compensa vreodată în acest mod.

Concluzie

În acest articol am abordat termeni cum ar fi gama, corecția gamma, intrările și ieșirile neliniare și matematica neliniară. Din fericire, am reușit să vă conving că ar trebui să începeți să vă îngrijorați de corectarea gammei chiar dacă ați fi neglijat-o până acum și dacă ați fi atent cu gama înainte de a vă întâlni cu acest articol, sper să vă fi dat niște noi pentru a face față problemei. 

Am învățat, cel mai important, să rezolvăm problemele care apar atunci când faceți o manipulare incorectă a valorilor culorilor, presupunând că acestea sunt liniare și am analizat capcanele și simptomele obișnuite care apar atunci când neglijezi acest aspect important al graficii pe computer.

Sper că v-ați distrat și ați învățat ceva nou în timp ce citiți acest articol. Pana data viitoare!