Poglavlje 16: Color Science Osnove

Poglavlje 16: Color Science Osnove

"Boja nije osobina predmeta. Boja je osobina svetlosti koja stigla do tvog oka -- i načina na koji tvoj mozak tu svetlost interpretira."

Dobrodošli u poglavlje koje mnogi game developeri preskoče, a potom mesecima traže zašto im scena izgleda "nekako čudno", zašto im se boje "isperu" ili zašto im tamni delovi slike izgledaju kao da imaju trake umesto glatkih prelaza. Color science nije akademska zanimacija -- to je fundament na kome počiva svaki piksel koji tvoj engine renderuje.

U ovom poglavlju ćemo proći kompletnu priču: od toga zašto uopšte postoje različiti color space-ovi, kroz gamma korekciju i njenu istoriju, HDR rendering pipeline, tone mapping, color grading, LUT-ove, ACES workflow, pa sve do najčešćih grešaka koje developeri prave. Kada završiš ovo poglavlje, razumećeš zašto Unreal Engine 5 radi stvari onako kako radi, i bićeš u stanju da donosiš informisane odluke o color pipeline-u svog projekta.


16.1 Linear vs sRGB Color Space

16.1.1 Šta je uopšte color space?

Pre nego što uđemo u tehničke detalje, hajde da razjasnimo osnovni koncept. Color space (prostor boja) je matematički model koji opisuje kako se brojevi (vrednosti u memoriji) mapiraju na stvarne boje koje ljudsko oko vidi. Kada kažemo da piksel ima vrednost (0.5, 0.0, 0.0), ta brojka sama po sebi ne znači ništa dok ne znamo u kom color space-u je izražena.

Zamislite to kao merne jedinice: ako kažem "temperatura je 100 stepeni", to može biti i prijatno toplo (Fahrenheit) i ključala voda (Celsius). Isto tako, vrednost 0.5 u sRGB prostoru i vrednost 0.5 u linear prostoru predstavljaju potpuno različite količine svetlosti.

16.1.2 sRGB: Prilagođen ljudskom oku

sRGB (standard Red Green Blue) je color space koji je definisan 1996. godine kao standard za monitore, štampače, i internet. Praktično svaka slika koju vidite na internetu, svaki JPEG, svaki PNG -- sve je u sRGB prostoru.

Ključna karakteristika sRGB-a je da je perceptualno približno uniforman. Šta to znači? Ljudsko oko ne percipira svetlost linearno. Mi smo mnogo osetljiviji na razlike u tamnim tonovima nego u svetlim. Evoluciono, to ima savršen smisao -- u mraku je bilo važno razlikovati senku od predatora, dok u podnevnom suncu razlika između "jako svetlo" i "još svetlije" nije bila pitanje života i smrti.

Evo konkretnog primera. Zamislite da imate 256 nivoa (8 bita) da opišete intenzitet svetlosti od potpunog mraka do pune beline:

Linearno kodiranje (8-bit):
Nivo:      0    1    2    3  ...  252  253  254  255
Svetlost:  ▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓
           ^-- Oko ovde vidi ogromne skokove      ^-- Ovde jedva razliku pravi

sRGB kodiranje (8-bit):
Nivo:      0    1    2    3  ...  252  253  254  255
Svetlost:  ▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░▓
           ^-- Fina gradacija u tami    ^-- Manje nivoa, ali oko ne pravi razliku

Drugim rečima, sRGB je optimizovan za skladištenje i prikaz -- sa ograničenim brojem bitova daje maksimalno dobar rezultat za ljudsko oko.

16.1.3 Linear: Fizički korektan

Linear color space (linearni prostor boja) je, matematički gledano, mnogo jednostavniji. U linear prostoru, ako udvostručiš numeričku vrednost, udvostručiš stvarnu količinu svetlosti. Vrednost 0.5 je tačno duplo svetlija od 0.25, a vrednost 1.0 je tačno duplo svetlija od 0.5.

Ovo je prostor u kome fizika funkcioniše. Svetlost u stvarnom svetu se ponaša linearno:

Rendering engine MORA da radi u linear prostoru jer sve jednačine osvetljenja (BRDF-ovi, refleksije, global illumination, sky lighting, sve) pretpostavljaju da je odnos između numeričkih vrednosti i fizičke količine svetlosti -- linearan.

Evo klasičnog primera zašto je ovo važno. Zamislite da imate dve svetlosti, svaka sa intenzitetom 0.5, i osvetljavate istu tačku:

U linear prostoru:
  0.5 + 0.5 = 1.0  ← Tačno! Dve svetlosti daju dvostruko svetliju tačku.

U sRGB prostoru (gde 0.5 zapravo predstavlja ~0.214 linearne svetlosti):
  0.5 + 0.5 = 1.0  ← Ali ovo bi značilo da je rezultat MNOGO svetliji 
                       nego dvostruko, jer smo sabirali nelinearne vrednosti!

Kada sabiraš, množiš, ili na bilo koji drugi način matematički kombinuješ vrednosti boja -- moraš biti u linear prostoru da bi rezultat bio fizički korektan.

16.1.4 Gamma kriva: sRGB ≈ Gamma 2.2

Veza između sRGB i linear prostora je opisana takozvanom gamma krivom. Pojednostavljeno (i za većinu praktičnih primena dovoljno precizno), možemo reći:

Linear → sRGB:   sRGB_vrednost = Linear_vrednost ^ (1/2.2)    (gamma encoding)
sRGB → Linear:   Linear_vrednost = sRGB_vrednost ^ 2.2        (gamma decoding)

Napomena: Prava sRGB kriva ima malo drugačiju formulu za veoma tamne vrednosti (linearni segment blizu nule), ali za razumevanje koncepta, gamma 2.2 je sasvim dovoljna aproksimacija.

Vizualno, gamma kriva izgleda ovako:

sRGB vrednost
    1.0 |                                    *
        |                                *
        |                            *
        |                        *
        |                    *
    0.5 |               *
        |           *
        |        *
        |     *
        |   *
    0.0 |*
        +------------------------------------->
        0.0                               1.0
                    Linear vrednost

Sredina sRGB skale (0.5) odgovara otprilike linearnoj vrednosti od 0.5^2.2 ≈ 0.217. To znači da ono što ti izgleda kao "50% sivo" na ekranu zapravo emituje samo oko 21.7% maksimalne svetlosti. Ljudsko oko je toliko osetljivije na tamne tonove da mu ta količina svetlosti izgleda kao sredina.

16.1.5 Zlatno pravilo: sRGB za skladištenje, linear za računanje

Hajde da sumiramo u jedno prosto pravilo koje treba da zapamtiš zauvek:

Operacija Color Space
Čuvanje tekstura na disku sRGB
Prikaz na monitoru sRGB
Rendering (osvetljenje, blending, svi shader proračuni) Linear
Post-processing (većina operacija) Linear
Finalni output za display sRGB (za SDR)

Tok podataka u rendereru izgleda ovako:

[sRGB tekstura na disku]
        │
        ▼
  Gamma Decode (sRGB → Linear) ← GPU hardware automatski radi ovo
        │
        ▼
  [LINEAR prostor: svi shader proračuni]
        │
        ▼
  Tone Mapping + Post-Processing
        │
        ▼
  Gamma Encode (Linear → sRGB) ← Za SDR output
        │
        ▼
  [sRGB signal ide na monitor]

U Unreal Engine 5, ovo se uglavnom dešava automatski -- ali moraš znati šta se dešava ispod haube da bi razumeo zašto neke stvari rade kako rade, i gde mogu nastati problemi. Više o tome u sekciji o čestim greškama (16.9).

Veza sa Poglavljem 05: U Poglavlju 05 smo detaljno pokrili kako UE5 tretira sRGB vs linear teksture pri importu, zašto je bitno da color teksture budu markirane kao sRGB, a data teksture (normal mape, roughness, metalness) kao linear. Ovo poglavlje objašnjava zašto je ta distinkcija kritična sa stanovišta color science-a.


16.2 Gamma: Istorija i Praksa

16.2.1 Istorijski kontekst: CRT monitori

Da bi razumeo zašto uopšte imamo ovaj "gamma problem", moraš da se vratiš u prošlost, do doba CRT (Cathode Ray Tube) monitora.

CRT monitori su imali jednu interesantnu fizičku karakteristiku: intenzitet svetlosti koju su emitovali nije bio linearno proporcionalan naponu koji su primali. Umesto toga, intenzitet je bio približno proporcionalan naponu podignutom na stepen oko 2.2:

Intenzitet_svetlosti ∝ Napon ^ 2.2

Ovo je bila inherentna fizička osobina elektronskog topa i fosfora u CRT cevi -- nije to neko namerno dizajnersko rešenje, već čista fizika.

Srećom, ovaj "nedostatak" se ispostavio kao fantastična stvar! Pošto je ljudsko oko logaritamski osetljivo na svetlost (otprilike obrnuto od gamma krive CRT-a), ova nelinearnost je zapravo poboljšavala kvalitet slike -- kompenzovala je nelinearnost našeg vida.

Kamere su počele da snimaju sa inverznom gamma krivom (gamma encoding, vrednost^(1/2.2)), tako da je ceo lanac bio:

Stvarni svet (linearna svetlost)
        │
        ▼
  Kamera: Gamma Encoding (^1/2.2) 
        │
        ▼
  [Signal/Fajl: Gamma-kodirana vrednost]
        │
        ▼
  CRT Monitor: Prirodni Gamma Decoding (^2.2)
        │
        ▼
  Emitovana svetlost (ponovo linearna... otprilike)

Encoding kamere i decoding monitora su se poništavali, i rezultat je bio (otprilike) korektan prikaz. Čitav TV i video industrija se izgradila na ovom principu.

16.2.2 Gamma Encoding vs Gamma Decoding

Važno je jasno razlikovati ova dva procesa:

Gamma Encoding (ponekad se zove i "gamma compression"):

Gamma Decoding (ponekad se zove i "gamma expansion"):

16.2.3 Šta se dešava kad renderuješ u sRGB prostoru

Ovo je kritična sekcija. Hajde da vidimo konkretne primere šta krene po zlu kada rendering matematika radi sa nelinearnim (sRGB) vrednostima umesto linearnih.

Problem 1: Pogrešno osvetljenje

Zamislite da imate sivu površinu sa sRGB vrednošću 0.5 (što je linearna vrednost ~0.217) i osvetljavate je sa svetlošću intenziteta 2.0:

Korektno (u linear prostoru):
  1. Decode: 0.5^2.2 = 0.217 (linearna reflektansa)
  2. Osvetli: 0.217 × 2.0 = 0.434
  3. Encode za display: 0.434^(1/2.2) = 0.683
  Rezultat: sRGB 0.683

Pogrešno (direktno u sRGB prostoru):
  1. Osvetli: 0.5 × 2.0 = 1.0
  Rezultat: sRGB 1.0 (potpuno belo!)

Razlika je dramatična! U korektnom proračunu dobijamo svetlo sivu (0.683), a u pogrešnom -- potpuno belu (1.0)! Scena bi izgledala brutalno prepržena (overexposed).

Problem 2: Pogrešno blendovanje (alpha blending)

Recimo da blendujete dva piksela, beli (1.0) i crni (0.0), sa 50% alpha:

Korektno (u linear):
  1. Decode oba: 1.0^2.2 = 1.0, 0.0^2.2 = 0.0
  2. Blend: 0.5 × 1.0 + 0.5 × 0.0 = 0.5
  3. Encode: 0.5^(1/2.2) = 0.730
  Rezultat: sRGB 0.730 (vizualno srednje siva)

Pogrešno (u sRGB):
  1. Blend: 0.5 × 1.0 + 0.5 × 0.0 = 0.5
  Rezultat: sRGB 0.5 (vizualno TAMNO siva!)

Blend u sRGB prostoru daje rezultat koji je perceptualno pretaman. Zato anti-aliasing, transparencija, i sve operacije koje mešaju boje moraju raditi u linear prostoru.

Problem 3: Pogrešne interpolacije tekstura

Kada GPU sempluje teksturu između dva texela (bilinear filtering), ta interpolacija je linearna matematička operacija. Ako se radi nad sRGB vrednostima bez dekodiranja, rezultat je neispravan -- srednja vrednost dva texela neće biti vizualno korektna sredina.

16.2.4 "Double Gamma" problem

Jedan od najčešćih i najfrustrirajućih problema u game developmentu je takozvani "double gamma" (ili ponekad "gamma banding") problem. Dešava se kada gamma korekcija bude primenjena dva puta umesto jednom.

Tipičan scenario:

1. Tekstura je sačuvana u sRGB (gamma encoded) -- OK, to je normalno.
2. Engine je učita BEZ dekodiranja (tretira je kao linear) -- GREŠKA!
3. Shader koristi tu vrednost za proračune -- rezultat je netačan.
4. Engine potom primeni gamma encoding na output -- DRUGI gamma encoding!

Efektivno: vrednost prolazi kroz encoding DVA PUTA
  Originalna sRGB vrednost: X
  Prikazana vrednost: (X)^(1/2.2) = X^0.4545
  Ovo je MNOGO svetlije i "isprano" od originala!

Simptomi double gamma problema:

Obrnuti scenario (double decoding) je isto moguć:

U UE5, ovi problemi su uglavnom rešeni automatski ako koristiš standardne workflow-ove, ali mogu se pojaviti ako:


16.3 HDR Rendering Pipeline

16.3.1 Zašto 8 bita nije dovoljno za rendering

U stvarnom svetu, raspon svetlosti je ogroman. Zamislite ovu scenu: stojiš u zatamnjenom dnevnom boravku i gledaš kroz prozor na sunčan dan.

Dynamic range od senke u sobi do sunca je oko 1:1,000,000,000 ili 90dB. Čak i ako ignorišemo direktan pogled u sunce, svakodnevne scene imaju dynamic range od 1:100,000 ili više.

A koliko može da prikaže standardni 8-bit per channel format?

8 bita = 256 nivoa po kanalu
Dynamic range = 256:1
To je oko 48 dB -- DALEKO manje od stvarnog sveta.

Ako bi renderovali direktno u 8-bit buffer, morali bi da "zgažemo" čitav ogromni raspon svetlosti u samo 256 nivoa. Rezultat bi bio katastrofalan -- ili bi tamni delovi bili potpuno crni (bez detalja), ili bi svetli delovi bili potpuno beli (clipovani), ili bi sve bilo "muljavo" bez kontrasta.

16.3.2 HDR rendering: Šta to zapravo znači

HDR rendering (High Dynamic Range rendering) znači da engine interno koristi bufere sa mnogo većom preciznošću i rasponom od 8 bita:

Format Bitova po kanalu Raspon vrednosti Dynamic range
UINT8 (LDR) 8 0 - 255 (ili 0.0 - 1.0) ~48 dB
FP16 (half float) 16 ±65,504, sa 10-bit mantise ~77 dB, dovoljan za rendering
FP32 (full float) 32 ±3.4×10³⁸ Ogromni, ali preskup
R11G11B10_FLOAT 32 ukupno Smanjeni float Dobar kompromis

UE5 koristi FP16 (half-precision floating point) za većinu internog renderovanja, ponekad i R11G11B10_FLOAT za scene color buffer. Ovo omogućava:

16.3.3 Rendering u FP16 bufferima

Kada UE5 renderuje scenu, interni tok izgleda ovako:

[GBuffer Pass]
  Svaki piksel čuva: albedo, normal, roughness, metalness, itd.
  GBuffer formati su mešavina: UINT8 za neke kanale, FP16 za emission, itd.
        │
        ▼
[Lighting Pass]
  Za svaki piksel, za svako svetlo:
    Izračunaj doprinos svetla koristeći BRDF
    Akumuliraj u FP16 scene color buffer
    Vrednosti mogu biti > 1.0 (HDR!)
        │
        ▼
[Scene Color Buffer: FP16]
  Sadrži "scene-referred" vrednosti
  Raspon: od ~0.0 do potencijalno stotina hiljada
  Ovo je HDR slika u LINEAR prostoru
        │
        ▼
[Post-Processing u HDR]
  Bloom, DOF, motion blur -- sve radi sa HDR vrednostima
  Bloom posebno profitira: svetli pikseli "cvetaju" prirodno
        │
        ▼
[Tone Mapping]
  HDR → LDR konverzija (detaljno u sekciji 16.6)
        │
        ▼
[Color Grading + LUT]
  Finalno podešavanje boja
        │
        ▼
[Gamma Encoding]
  Linear → sRGB za SDR display
  Ili Linear → PQ/HLG za HDR display
        │
        ▼
[Display Output]

16.3.4 HDR displej standardi

Sa pojavom HDR monitora i TV-a, pojavio se i koncept prikazivanja HDR sadržaja direktno na ekranu, bez agresivnog tone mapping-a koji gubi informacije.

SDR (Standard Dynamic Range) displej:

HDR10:

Dolby Vision:

HDR10+:

Implikacije za UE5 rendering:

Kada renderuješ za HDR display, pipeline se menja:

[Scene Color: Linear HDR, FP16]
        │
        ▼
[Tone Mapping za HDR display]
  Manje agresivan nego za SDR -- ne moraš da "zgažeš" toliko
  Možeš da sačuvaš highlight detalje
        │
        ▼
[PQ Encoding]
  Umesto sRGB gamma, koristiš ST.2084 PQ krivu
  Ovo je perceptualno uniformna kriva za HDR raspon
        │
        ▼
[HDR10 Output]
  10-bit per channel, Rec. 2020 color space

UE5 ima ugrađenu podršku za HDR output, i postoji opcija u Project Settings (Engine > Rendering > HDR Display Output). Možeš da podesiš:

16.3.5 Zašto je HDR rendering bitan čak i za SDR output

Čak i ako tvoj finalni output ide na SDR monitor (klasičnih 8 bita, sRGB), interni HDR rendering je kritičan:

  1. Bloom efekti: Bloom radi tako što uzima piksele svetlije od nekog threshold-a i "razmazuje" ih. Ako su svi pikseli clamped na 1.0, bloom nema informacije sa kojima da radi. U HDR, sunce može biti 100,000, reflekcija 50, nebo 5 -- bloom prirodno izdvaja najsvetlije delove.

  2. Korektno osvetljenje: Ako imaš scenu sa suncem i sijalicama, odnos njihovih intenziteta treba da bude realan (sunce: 100,000, sijalica: 10). U 8-bit bufferu, oba bi bila clamped na 1.0 i izgledala identično.

  3. Exposure adaptation: Simulacija adaptacije oka na svetlost zahteva poznavanje stvarnog raspona svetlosti u sceni.

  4. Tone mapping kvalitet: Tone mapping daje mnogo bolje rezultate kada ima pristup punom HDR rasponu scene (vidi sekciju 16.6).


16.4 Color Grading

16.4.1 Šta je color grading?

Color grading je proces kreativnog podešavanja boja finalne slike da bi se postigao željeni vizualni stil, atmosfera, ili raspoloženje. To je ekvivalent onoga što filmski kolorista radi sa filmskim materijalom.

Color grading NIJE ista stvar kao color correction. Color correction je tehnički proces -- ispravljanje balansa bele, ekspozicije, kontrasta da bi slika bila "korektna". Color grading je kreativni proces -- namerno menjanje boja da bi slika izgledala onako kako želiš.

Primeri:

16.4.2 Alati za color grading

Color grading tipično uključuje podešavanje sledećih parametara:

Contrast:

Saturation:

Hue Shift:

Temperature i Tint:

Shadows / Midtones / Highlights:

Lift / Gamma / Gain:

16.4.3 Color grading u UE5

UE5 nudi izuzetno bogat set color grading opcija kroz Post Process Volume:

Post Process Volume → Color Grading
├── Global
│   ├── Saturation
│   ├── Contrast
│   ├── Gamma
│   └── Gain
├── Shadows
│   ├── Saturation
│   ├── Contrast
│   ├── Gamma
│   ├── Gain
│   └── Shadows Max (gde prestaju senke)
├── Midtones
│   ├── Saturation
│   ├── Contrast
│   ├── Gamma
│   └── Gain
├── Highlights
│   ├── Saturation
│   ├── Contrast
│   ├── Gamma
│   ├── Gain
│   └── Highlights Min (gde počinju highlights)
├── Misc
│   ├── Blue Correction
│   ├── Expand Gamut
│   ├── Tone Curve Amount
│   └── Scene Color Tint
└── Color Grading LUT
    ├── Color Grading LUT Texture
    └── Color Grading LUT Intensity

16.4.4 Gde u pipeline-u se radi color grading?

Ovo je važno pitanje. U UE5, color grading se dešava nakon tone mapping-a, u LDR prostoru (ili tačnije, u procesu koji kombinuje tone mapping i color grading u jedan prolaz koristeći LUT).

Pipeline je sledeći:

[HDR Scene Color, Linear]
        │
        ▼
  [Bloom, DOF, Motion Blur -- u HDR]
        │
        ▼
  [Auto Exposure / Eye Adaptation]
        │
        ▼
  [Combined Tone Mapping + Color Grading]  ← Ovo se bake-uje u LUT!
        │
        ▼
  [LDR Output, sRGB encoded]

UE5 zapravo "peče" (bake) tone mapping i color grading zajedno u jedan 3D LUT. To znači da se sva podešavanja (contrast, saturation, shadows color, itd.) kombinuju sa tone mapping krivom u jednu teksturu, i zatim se primenjuju na HDR scenu u jednom prolazu. Ovo je veoma efikasno!

16.4.5 Kreativna upotreba color grading-a

Hajde da pogledamo nekoliko konkretnih primera kako color grading definiše vizualni identitet igre:

Primer 1: "Bleach Bypass" / High Contrast Desaturated Look

Saturation: 0.5 (desaturisano)
Contrast: 1.4 (pojačan)
Shadows Gain: (0.8, 0.85, 0.9) -- blago plavi senke
Highlights Gain: (1.1, 1.05, 1.0) -- blago topli highlights

Ovaj look se koristi u ratnim igrama, post-apokaliptičnim scenarijima, thriller žanru.

Primer 2: "Teal and Orange" filmski look

Shadows Gain: (0.7, 0.85, 1.0) -- plavo-zelene senke
Highlights Gain: (1.1, 0.95, 0.85) -- toplo narandžasti highlights
Saturation: 1.15 (blago pojačano)

Najčešći filmski color grading -- komplementarne boje stvaraju vizualno privlačan kontrast.

Primer 3: "Neon Noir" look

Shadows Gain: (0.6, 0.6, 0.7) -- duboke tamne senke sa magenta tintom
Midtones Saturation: 1.3 (pojačana saturacija)
Contrast: 1.5 (jak kontrast)
Scene Color Tint: blago magenta

Veza sa Poglavljem 15: U Poglavlju 15 smo detaljno pokrili kako Post Process Volume funkcioniše, kako se blenduju multiple volume-i, i praktične savete za postavljanje post-process efekata uključujući color grading.


16.5 LUT (Look-Up Table)

16.5.1 Šta je LUT?

LUT (Look-Up Table) je, u kontekstu color grading-a, 3D tekstura koja mapira ulaznu RGB boju na izlaznu RGB boju. Umesto da za svaki piksel izračunavaš kompleksnu seriju matematičkih operacija (contrast, saturation, hue shift, tone mapping curve, itd.), sve te operacije "ispečeš" (bake) u jednu 3D teksturu, i zatim za svaki piksel samo uradiš jedan texture lookup.

Koncept je jednostavan:

  1. Za svaku moguću kombinaciju ulaznih (R, G, B) vrednosti, izračunaj šta bi bio izlaz nakon svih color grading operacija.
  2. Sačuvaj taj rezultat u 3D teksturu.
  3. U runtime-u, za svaki piksel, koristi njegovu RGB vrednost kao koordinate u 3D teksturi i pročitaj rezultat.

16.5.2 Kako izgleda 3D LUT

3D LUT je, konceptualno, kocka boja:

         B (blue)
         ▲
        /
       /
      /________▶ R (red)
      |
      |
      ▼
      G (green)

Svaka tačka u ovoj kocki predstavlja jednu specifičnu ulaznu boju (R, G, B), i na toj lokaciji je sačuvana izlazna boja. Pošto je nemoguće sačuvati beskonačan broj tačaka, koristimo diskretnu mrežu:

Između tačaka, GPU koristi trilinearnu interpolaciju da izračuna tačnu izlaznu boju.

U praksi, 3D LUT se čuva kao 2D tekstura koja sadrži "rezove" 3D kocke. Na primer, 32×32×32 LUT se čuva kao 2D tekstura dimenzija 1024 × 32 (32 rezova po blue osi, svaki rez je 32 × 32 za R i G).

Identity LUT (bez transformacije):
Ovo je LUT gde je output = input. Koristi se kao startna tačka.

[Slice B=0][Slice B=1][Slice B=2]...[Slice B=31]
  R →         R →         R →            R →
  ↓G          ↓G          ↓G             ↓G

16.5.3 Efikasnost LUT-a

Zašto koristiti LUT umesto direktnog izračunavanja? Efikasnost!

Zamislite da tvoj color grading pipeline ima sledeće korake:

  1. Tone mapping (kompleksna S-kriva sa više parametara)
  2. Contrast podešavanje za shadows, midtones, highlights
  3. Saturation podešavanje po opsegu
  4. Hue shift
  5. Temperature podešavanje
  6. Color wheel (lift/gamma/gain)
  7. Gamma encoding

Svaki od ovih koraka zahteva ALU operacije (matematičke instrukcije na GPU). Ako ih sve radiš per-pixel, to može biti 50-100+ instrukcija po pikselu.

Sa LUT-om, SVE ovo se zameni jednim 3D texture sample-om -- što je jedna instrukcija! (Plus trilinearna interpolacija, ali to je hardware-ski besplatno.)

Bez LUT-a:                          Sa LUT-om:
Per-pixel cost:                      Per-pixel cost:
  Tone mapping:    ~15 ALU ops        Jedan 3D texture sample
  Contrast:        ~10 ALU ops        (sa trilinearnom interpolacijom)
  Saturation:      ~8 ALU ops         = ~1 texture op
  Hue shift:       ~12 ALU ops
  Temperature:     ~6 ALU ops
  Lift/Gamma/Gain: ~15 ALU ops
  Gamma encode:    ~5 ALU ops
  ─────────────────────────
  Ukupno: ~70+ ALU ops

Kompromis je kvalitet -- interpolacija u 3D LUT-u može da unese male greške, posebno za ekstremne boje ili brze promene. Ali za 32³ LUT, kvalitet je više nego dovoljan za gaming primene.

16.5.4 UE5 Color Grading LUT Workflow

U UE5 postoje dva načina rada sa LUT-ovima:

Metod 1: Interni LUT (automatski)

Ovo je default ponašanje. UE5 automatski generiše interni LUT na osnovu svih color grading podešavanja u Post Process Volume-u. Ti ne treba ništa ručno da radiš -- engine sam kombinuje tone mapping, color grading parametre, i gamma encoding u interni 3D LUT i primenjuje ga.

Interni LUT se regeneriše kad god promeniš color grading parametre. Generisanje je jeftino jer se radi samo jednom (ne per-pixel), a primena je jedan texture sample po pikselu.

Metod 2: Eksterni LUT (ručno)

Možeš da kreiraš svoj LUT u eksternom softveru (Photoshop, DaVinci Resolve, Nuke) i importuješ ga u UE5:

  1. Napravi screenshot iz engine-a (ili koristi UE5-ov "Neutral Color LUT" image)
  2. Otvori screenshot u Photoshop-u (ili drugom image editoru)
  3. Primeni željene color korekcije na screenshot
  4. Primeni ISTE korekcije na Neutral LUT sliku (identity LUT koji UE5 daje)
  5. Sačuvaj modifikovan LUT kao PNG (bez kompresije)
  6. Importuj u UE5 i podesi kao "Color Grading LUT" u Post Process Volume

Koraci za import:

1. Import LUT teksturu u UE5
2. Otvori teksturu i podesi:
   - sRGB: OFF (LUT se čuva u linear!)
   - Compression: VectorDisplacementmap (ili bez kompresije)
   - Texture Group: ColorLookupTable
3. U Post Process Volume:
   - Color Grading → Color Grading LUT → podesi teksturu
   - Color Grading LUT Intensity: 1.0 (ili manje za blending)

Upozorenje: Eksterni LUT zamenjuje interni. Ako koristiš eksterni LUT, podešavanja u Color Grading sekciji Post Process Volume-a neće imati efekta (jer interni LUT biva zamenjen eksternim). Koristi jedno ili drugo, ne oba.

16.5.5 Kreiranje LUT-ova za različite scenarije

LUT-ovi su izuzetno moćan alat za definisanje vizualnog identiteta igre. Evo nekoliko praktičnih saveta:

  1. Jedan bazni LUT za celu igru -- definiše generalni look i feel. Svi nivoi dele ovaj LUT.

  2. Per-level LUT-ovi -- svaki nivo ima svoj LUT za specifičnu atmosferu (pustinjski nivo ima topli, žuti LUT; snežni nivo ima hladni, plavi LUT).

  3. Blendovanje LUT-ova -- UE5 podržava blendovanje između LUT-ova koristeći Post Process Volume blending. Kada igrač prelazi iz jedne zone u drugu, LUT može da se glatko preliva.

  4. Specijalni efekti -- flashback scene mogu imati sepia LUT, trovanje može imati zelenkasto-žuti LUT, itd.


16.6 Tone Mapping -- Zašto je neophodan

16.6.1 Problem: Ogromni dynamic range, mali displej

Ovo je centralni problem koji tone mapping rešava:

16.6.2 Naivni pristup: Clamp

Najjednostavniji pristup je prosto clamping -- svedu sve vrednosti iznad 1.0 na 1.0, i sve ispod 0.0 na 0.0:

output = clamp(input, 0.0, 1.0)

Rezultat je katastrofalan:

Originalni HDR pikseli:
  Senka u sobi:    0.01
  Zid sobe:        0.3
  Svetlo u sobi:   1.5
  Nebo kroz prozor: 5.0
  Oblak:           20.0
  Sunce:           100000.0

Posle clamp:
  Senka:    0.01
  Zid:      0.3
  Svetlo:   1.0  ← clip!
  Nebo:     1.0  ← clip! Ista vrednost kao svetlo!
  Oblak:    1.0  ← clip! Ista vrednost kao nebo i svetlo!
  Sunce:    1.0  ← clip! Ista vrednost kao sve ostalo!

SVE iznad 1.0 postaje identično belo. Gubimo sve detalje u highlight-ima. Nebo, oblaci, sunce, odsjaji -- sve je isto čisto belo. Ovo se zove clipping ili blow-out i izgleda grozno.

16.6.3 S-kriva tone mapper-i

Rešenje je korišćenje tone mapping krive -- funkcije koja mapira HDR raspon u LDR raspon na "pametan" način:

Ovo daje S-krivu (sigmoid) kada se nacrta na grafiku:

Output (LDR)
    1.0 |                        _______________
        |                   ____/
        |               ___/
        |           ___/
    0.5 |       ___/
        |    __/
        |  _/
        | /
        |/
    0.0 +------------------------------------->
        0.0              5.0             100.0+
                    Input (HDR)

Kriva nikad ne dostiže 1.0 u potpunosti (asimptotski prilazi), što znači da uvek postoji neka razlika između svetlijih i tamnih piksela, čak i u jako svetlim oblastima. Detalji u highlight-ima su sačuvani!

16.6.4 Reinhard Tone Mapping

Jedan od najjednostavnijih i najpoznatijih tone mapping operatora. Formula je elegantno prosta:

output = input / (1.0 + input)

Osobine:

Primer:
  input = 0.1  → output = 0.1 / 1.1 = 0.091   (skoro linearan)
  input = 0.5  → output = 0.5 / 1.5 = 0.333
  input = 1.0  → output = 1.0 / 2.0 = 0.5
  input = 5.0  → output = 5.0 / 6.0 = 0.833
  input = 100  → output = 100 / 101 = 0.99     (blizu 1.0, ali ne 1.0)

Proširena verzija dozvoljava kontrolu nad belom tačkom:

output = input × (1 + input / (Lwhite²)) / (1 + input)

Gde je Lwhite luminance vrednost koja se mapira na čisto belo (1.0). Ovo daje veću kontrolu nad tim koliko svetli pikseli mogu biti pre nego što budu clipovani.

Prednosti Reinhard-a:

Mane Reinhard-a:

16.6.5 Filmic Tone Mapping

Filmic tone mapper je dizajniran da imitira karakteristiku filmske trake (film stock). Filmska traka ima specifičnu S-krivu koja daje karakter koji većina ljudi asocira sa "filmskim" izgledom:

John Hable (koji je radio na Uncharted 2) popularizovao je filmic tone mapping operator u gaming industriji. Njegova formula (poznata kao "Uncharted 2 Tonemapping"):

float3 FilmicTonemap(float3 x) {
    float A = 0.15; // Shoulder Strength
    float B = 0.50; // Linear Strength
    float C = 0.10; // Linear Angle
    float D = 0.20; // Toe Strength
    float E = 0.02; // Toe Numerator
    float F = 0.30; // Toe Denominator
    return ((x*(A*x+C*B)+D*E) / (x*(A*x+B)+D*F)) - E/F;
}

Ova formula je postala veoma popularna u gaming industriji jer daje rezultate koji su vizualno slični filmskoj traci, sa lepim kontrastom i prirodnom desaturacijom u highlight-ima.

16.6.6 ACES Tone Mapping

ACES (Academy Color Encoding System) tone mapping je trenutni industrijski standard i default u UE5. Detaljnije u sekciji 16.7, ali ovde ćemo pokriti tone mapping aspekt.

ACES tone mapping koristi RRT (Reference Rendering Transform) koji definiše kako se scene-referred HDR vrednosti mapiraju na display-referred vrednosti. Kriva ima:

ACES aproksimacija (Stephen Hill):
float3 ACESFilm(float3 x) {
    float a = 2.51;
    float b = 0.03;
    float c = 2.43;
    float d = 0.59;
    float e = 0.14;
    return saturate((x*(a*x+b)) / (x*(c*x+d)+e));
}

16.6.7 Kako tone mapping utiče na saturaciju

Jedan važan aspekt tone mapping-a koji mnogi preview je desaturacija u highlight-ima. U stvarnom svetu (i na filmskoj traci), veoma svetli objekti teže beloj boji -- gube svoju hromatinost. Ovo se zove highlight desaturation ili highlight roll-off.

Razmislite: crveno svetlo niske jačine je jasno crveno. Ali crveno svetlo ekstremno visokog intenziteta (npr. usijani metal) izgleda gotovo belo sa blagim crvenkastim tonom. Ovo je delimično fizički efekat (sensori oka se saturišu) i delimično perceptualni.

Dobar tone mapper simulira ovaj efekat:

Niska svetlost:   (1.0, 0.0, 0.0) → (0.8, 0.0, 0.0)    čisto crveno
Srednja svetlost:  (5.0, 0.0, 0.0) → (0.95, 0.3, 0.2)   crvenkasto sa belim
Visoka svetlost:   (50.0, 0.0, 0.0) → (0.99, 0.85, 0.8)  skoro belo, blagi crveni tint

Ovo je jedan od razloga zašto ACES i filmic tone mapping-i izgledaju "filmski" -- ta prirodna desaturacija u highlight-ima daje realističan izgled.

U UE5, možeš kontrolisati ovo ponašanje:

16.6.8 UE5 Tone Mapper opcije

UE5 nudi nekoliko tone mapping opcija:

1. ACES (default):

2. Mobile Tonemapper:

3. Custom Tone Curve:

U Post Process Volume:

Post Process Volume → Tone Mapper
├── Slope: 0.88 (default) -- nagib linearnog dela
├── Toe: 0.55 (default) -- jačina toe regiona
├── Shoulder: 0.26 (default) -- jačina shoulder regiona
├── Black Clip: 0.0 (default) -- koliko je "podignuta" crna tačka
├── White Clip: 0.04 (default) -- koliko pre 1.0 se clip-uje belo
├── Expand Gamut: 1.0 -- širi gamut za ACES
└── Blue Correction: 0.6 -- koriguje plavo za ACES

Važan savet: Nemoj menjati ove parametre bez dobrog razloga. Default ACES vrednosti su rezultat godina istraživanja i testiranja. Ako ti se ne sviđa izgled, prvo probaj color grading parametre (contrast, saturation, itd.) pre nego što diraš tone mapper krivu.


16.7 ACES Workflow

16.7.1 Šta je ACES?

ACES (Academy Color Encoding System) je standardizovani sistem za upravljanje bojama u filmu, televiziji, i digitalnoj produkciji. Razvila ga je AMPAS (Academy of Motion Picture Arts and Sciences) -- ista organizacija koja dodeljuje Oscare.

ACES nije samo tone mapper -- to je kompletan framework za upravljanje bojama kroz čitav produkcijski pipeline, od kamere do finalnog output-a.

16.7.2 Ključni koncepti ACES-a

Scene-referred vs Display-referred:

Ovo je fundamentalna distinkcija u ACES-u:

Tone mapping je, u suštini, konverzija iz scene-referred u display-referred.

ACES color space (AP0 i AP1):

ACES definiše svoje sopstvene color space-ove:

Color Space širina (aproksimativno):
  sRGB/Rec.709: ████████░░░░░░░░░░░░  (najmanji, standardni)
  DCI-P3:       ████████████░░░░░░░░  (širi, bioskopi, Apple uređaji)
  Rec. 2020:    ██████████████████░░  (jako širok, HDR standard)
  ACES AP1:     ████████████████████  (veoma širok, za CGI)
  ACES AP0:     ████████████████████+ (obuhvata sve vidljive boje)

16.7.3 ACES Pipeline

Kompletni ACES pipeline ima tri glavna koraka:

[Ulazni signal]
      │
      ▼
[IDT - Input Device Transform]
  Konvertuje iz formata ulaznog uređaja (kamera, CGI engine)
  u ACES color space (scene-referred, linear, AP0)
      │
      ▼
[ACES Color Space - Scene Referred]
  Ovo je "zajednički jezik" -- sve je u istom prostoru
  Ovde se rade svi compositing, VFX, color correction
      │
      ▼
[RRT - Reference Rendering Transform]
  Konvertuje iz scene-referred u "idealni" display-referred
  Ovo je tone mapping + gamut mapping + highlight roll-off
  Definiše "ACES look" -- filmski karakter, desaturacija, itd.
      │
      ▼
[ODT - Output Device Transform]
  Konvertuje iz reference display-a u konkretni output uređaj
  Različiti ODT-ovi za: SDR monitor, HDR10 TV, DCI projector, itd.
      │
      ▼
[Display Output]

U novijoj verziji ACES-a (ACES 2.0), RRT i ODT su kombinovani u jedan Output Transform.

16.7.4 Zašto film i VFX industrija koristi ACES

  1. Univerzalnost: Jedan pipeline koji radi za sve kamere, sve display-ove, sve output formate. Film snimljen na ARRI kameri i VFX renderovani u Maya-i mogu da se kombinuju bez color mismatch-a.

  2. Future-proofing: Scene-referred vrednosti nisu vezane za specifičan displej. Isti sadržaj može da se re-master-uje za novi tip displeja (npr. HDR) bez ponovnog renderovanja.

  3. Konzistentnost: Svi u produkcijskom timu vide iste boje na svim uređajima (ako su kalibrisani).

  4. Kvalitet: ACES RRT daje izuzetno kvalitetan tone mapping sa filmskim karakterom.

16.7.5 ACES u UE5

UE5 koristi modifikovanu verziju ACES pipeline-a. Evo kako to funkcioniše u praksi:

Default ponašanje (ACES uključen):

[Linear sRGB rendering]
      │
      ▼
[Expand Gamut] -- opciono proširenje iz sRGB ka širem gamut-u
      │
      ▼
[ACES Tone Mapping (aproksimacija RRT + sRGB ODT)]
      │
      ▼
[Color Grading (baked u LUT zajedno sa tone mapping-om)]
      │
      ▼
[sRGB Output]

UE5 ne koristi puni ACES pipeline sa AP0/AP1 color space-ovima u default konfiguraciji. Umesto toga, renderuje u linear sRGB (Rec. 709 primaries) i koristi ACES-inspirisan tone mapping operator.

Možeš uključiti potpuniju ACES podršku:

Podešavanja u UE5:

// U Project Settings ili Post Process Volume:

// Tone Mapper tip -- ACES je default
r.TonemapperFilm = 1  // 0 = legacy, 1 = filmic (ACES-based)

// ACES-specifična podešavanja u Post Process Volume:
Expand Gamut: 1.0          // Proširuje gamut ka AP1
Blue Correction: 0.6       // Koriguje ACES-ov tretman plavih tonova
                            // (ACES ima tendenciju da pomera plavo ka purpurnom)
Tone Curve Amount: 1.0     // Koliko se ACES tone curve primenjuje

16.7.6 Problemi sa ACES-om u gaming kontekstu

ACES je dizajniran za filmsku produkciju, i neke njegove karakteristike mogu biti problematične u igrama:

  1. Pomeranje plavih tonova (blue shift): ACES RRT ima tendenciju da pomera čiste plave boje ka purpurnom/magenta tonovima. Ovo može biti neželjeno za UI elemente ili stilizovane igre. Blue Correction parametar u UE5 delimično rešava ovaj problem.

  2. Desaturacija: ACES agresivno desaturiše boje u highlight-ima. Za realistične scene ovo je odlično, ali za stilizovane igre sa jarkim bojama može biti previše.

  3. Tamni tonovi: ACES podiže crnu tačku (black level), što znači da najcrnji piksel nije potpuno crn. U filmskoj produkciji ovo je poželjno (imitira filmsku traku), ali u igrama može da smeta.

  4. Performanse: Puni ACES pipeline je skuplji od jednostavnog tone mapping-a, mada razlika nije velika jer se sve bake-uje u LUT.


16.8 Color Space-ovi izvan sRGB

16.8.1 Pregled glavnih color space-ova

Do sada smo uglavnom govorili o sRGB, ali postoji čitav niz color space-ova koji su relevantni za moderni game development:

Rec. 709 (BT.709):

DCI-P3:

Rec. 2020 (BT.2020):

Vizualni prikaz gamut-ova (CIE chromaticity dijagram, pojednostavljeno):

                     520nm (zelena)
                        *
                      /    \
                    /        \
                  /     2020    \
                /    ___/ \___    \
              /   _/   P3    \_   \
            /  _/   ___/ \___  \_  \
          / _/ __/ sRGB    \__ \_ \
        /_//  /               \  \\\_
      *     /                   \    *
 480nm    /                       \   700nm
(plava)  *-------------------------*  (crvena)

16.8.2 Wide Color Gamut displej

Moderni displej-i sve češće podržavaju wide color gamut (WCG) -- širi opseg boja od sRGB:

Šta to znači za game development? Ako renderuješ u sRGB i outputuješ sRGB signal, imaš samo trećinu boja koje moderni displej može da prikaže! Te duboke crvene, zasićene zelene i žive cyan boje jednostavno ne mogu biti prikazane u sRGB.

16.8.3 Zašto je WCG važan za HDR sadržaj

HDR i WCG idu ruku pod ruku. Razlog je fizički: vrlo svetli, intenzivni svetlosni izvori u stvarnom svetu imaju izrazito zasićene boje. Kada imaš mogućnost da prikažeš visok luminance (HDR), prirodno želiš i da prikažeš šire boje (WCG).

Primer: Neonsko svetlo

HDR10 standard zahteva:
  - Color space: Rec. 2020 (ali veoma malo sadržaja zapravo koristi pun 2020)
  - Transfer function: PQ (ST.2084)
  - Bit depth: 10-bit
  - Max luminance: tipično 1000-4000 nits (zavisi od displeja)

16.8.4 Implementacija u UE5

UE5 ima podršku za WCG output, posebno za HDR:

Project Settings → Engine → Rendering:
  ├── Working Color Space: sRGB (default) ili širi (AP1, Rec. 2020, itd.)
  ├── HDR Display Output: On/Off
  ├── HDR Display Color Gamut: Rec. 2020 / DCI-P3 / sRGB
  └── HDR Display Max Luminance: (vrednost u nits)

Kada je HDR output uključen:

  1. Engine renderuje u linear prostoru (interno koristi sRGB primaries ili šire sa Expand Gamut)
  2. Tone mapping se prilagođava za HDR output (manje agresivan)
  3. Output se konvertuje u target color space (Rec. 2020)
  4. PQ transfer function se primenjuje umesto sRGB gamma

Za većinu projekata, preporučujem sledeći pristup:

16.8.5 Praktični saveti za WCG

  1. Teksture i dalje mogu biti sRGB: Većina texture sadržaja se i dalje kreira u sRGB. Engine će ih korektno konvertovati pri čitanju. Samo ako želiš boje izvan sRGB gamut-a, trebaš teksture u širem prostoru.

  2. HDR lighting daje WCG "besplatno": Kada imaš jako svetle, obojene svetlosti (npr. neon), matematika osvetljenja prirodno proizvodi boje izvan sRGB gamut-a. ACES sa Expand Gamut ovo korektno prezervira.

  3. UI treba pažnju: UI elementi se tipično definišu u sRGB. Ako outputuješ u Rec. 2020, moraš osigurati da su UI boje korektno konvertovane (UE5 ovo uglavnom radi automatski).

  4. Testiranje na pravom HDR displeju je obavezno: HDR sadržaj se ne može proceniti na SDR monitoru. Nabavite HDR monitor za development tim ako ciljate HDR output.


16.9 Česte Color Greške u Game Developmentu

16.9.1 Greška #1: Teksturiranje i računanje u sRGB prostoru

Problem: Artist kreira teksturu u Photoshop-u (sRGB), importuje je u engine, i engine je koristi u shader proračunima bez konverzije u linear prostor.

Simptom: Osvetljenje izgleda "netačno" -- previše svetlo u nekim oblastima, previše tamno u drugim. Blendovanje boja daje čudne rezultate.

Rešenje: Osiguraj da su sve color teksture (albedo, emissive, subsurface color) markirane kao sRGB u import podešavanjima. UE5 će automatski primenjivati gamma decoding pri čitanju ovih tekstura u shaderu.

Korektno:
  Albedo tekstura → import sa sRGB = ON
  GPU automatski dekodira: sRGB → Linear pri sampleovanju
  Shader radi sa linear vrednostima ✓

Pogrešno:
  Albedo tekstura → import sa sRGB = OFF (tretirano kao linear)
  GPU NE dekodira -- vrednosti ostaju u sRGB
  Shader radi sa nelinearnim vrednostima ✗

16.9.2 Greška #2: Markiranje data tekstura kao sRGB

Problem: Suprotan problem od prethodnog! Normal mape, roughness mape, metalness mape, AO mape, i druge "data" teksture sadrže podatke koji nisu boje -- to su numeričke vrednosti koje opisuju fizičke osobine površine.

Ove teksture NE SMEJU biti markirane kao sRGB jer:

Simptom: Ako markiraš roughness mapu kao sRGB, GPU će primeniti gamma decoding, i roughness vrednosti će biti pogrešne -- površine će izgledati ili previše sjajne ili previše mat.

Rešenje:

Tip teksture sRGB flag
Albedo / Base Color ON (sRGB)
Normal Map OFF (Linear)
Roughness OFF (Linear)
Metalness OFF (Linear)
Ambient Occlusion OFF (Linear)
Height / Displacement OFF (Linear)
Emissive Color ON (sRGB)*
Opacity / Mask OFF (Linear)
Subsurface Color ON (sRGB)

*Emissive je diskutabilan -- zavisi od workflow-a. Ako su emissive vrednosti kreirane kao boje u Photoshop-u, onda sRGB. Ako su generisane programatski, onda linear.

Veza sa Poglavljem 05: U Poglavlju 05 smo detaljno objasnili UE5 texture import workflow i zašto je pravilno postavljanje sRGB flag-a kritično za korektne materijale.

16.9.3 Greška #3: Color banding od nedovoljne preciznosti

Problem: Color banding (vidljive "trake" boja umesto glatkih prelaza) se pojavljuje u gradijentima, posebno u tamnim oblastima.

Uzroci:

  1. 8-bit render target-i: Ako neki korak u pipeline-u koristi 8-bit buffer, gubite preciznost
  2. Nedovoljan dithering: Čak i sa dobrom preciznošću, kvantizacija na 8-bit output može da uzrokuje banding
  3. Post-processing na LDR vrednostima: Ako uradite color correction nakon konverzije u 8-bit, pojačavate greške kvantizacije

Simptom: Ružne trake boja u gradijentima neba, u senkama, ili u bilo kojoj oblasti sa blagim color prelazom.

Primer: Gradijent od crnog do tamno plavog u 8-bit:

Bez dithering-a:
  ████████████░░░░░░░░░░░░  ← Vidljive trake!

Sa dithering-om:
  ████▓▓██▓▓░▓░░▓░░░▓░░░░  ← Mnogo glatkiji prelaz!

Rešenje:

  1. Osiguraj da interni render target-i koriste FP16 format (UE5 default za scene color)
  2. Uključi film grain ili dithering u finalnom output-u -- ovo maskira banding
  3. U UE5, r.HDR.Display.OutputDevice i r.PostProcessing.PropagateAlpha mogu uticati na preciznost pipeline-a
  4. Razmisli o tome da koristiš 10-bit output ako target platforma podržava (HDR10 koristi 10-bit)

16.9.4 Greška #4: Over-saturacija od pogrešnog tone mapping-a

Problem: Boje izgledaju preterano zasićene, "neonske", ili neprirodne. Ovo se često dešava kada se koristi pogrešan ili loše konfigurisan tone mapper.

Uzroci:

  1. Linearan tone mapping (bez S-krive): Jednostavno skaliranje HDR vrednosti ne desaturiše highlight-e, pa boje ostaju nerealno zasićene
  2. Pre-tone-mapping color grading: Ako pojačaš saturaciju pre tone mapping-a, tone mapper je kompresuje nepredvidivo
  3. Gamut mapping problemi: Boje izvan gamut-a displeja se clipuju po komponentama, što menja hue

Simptom: Jarke boje izgledaju "plastično", crveno svetlo je agresivno crveno umesto da teži belom u highlight-ima, nebo je nerealno plavo.

Rešenje:

  1. Koristi ACES tone mapping (default u UE5) -- ima ugrađenu highlight desaturaciju
  2. Radi color grading nakon tone mapping-a (UE5 ovo radi automatski kroz LUT)
  3. Podesi Expand Gamut i Blue Correction parametre po potrebi
  4. Ako koristiš custom tone mapper, osiguraj da implementira gamut mapping i highlight desaturaciju

16.9.5 Greška #5: Ignorisanje linearnog workflow-a u asset kreaciji

Problem: Artist kreira teksture na nekalibriranom monitoru, koristi color picker vrednosti iz sRGB prostora u shader konstantama koje očekuju linear vrednosti, ili miksuje sRGB i linear vrednosti u istom proračunu.

Tipični scenariji:

Scenario A: Color Picker Problem
  Artist bira boju u UE5 color picker-u: (1.0, 0.5, 0.0) narandžasta
  Ova vrednost je u sRGB prostoru (jer color picker prikazuje sRGB)
  Ako se koristi direktno u shader-u kao linear, boja će biti MNOGO svetlija
  nego što artist očekuje.
  
  UE5 FIX: Color picker u UE5 automatski konvertuje -- ono što vidiš je 
  ono što dobijaš. Ali ako kopiraš hex code iz web-a u shader konstantu, 
  MORAŠ konvertovati ručno!

Scenario B: Mixing Color Spaces
  float3 finalColor = sRGB_texture_value * linear_light_value;
  // POGREŠNO! Množiš nelinearne sa linearnim vrednostima
  
  float3 finalColor = LinearToSRGB(sRGB_texture_value) * linear_light_value;
  // KOREKTNO! Obe vrednosti su u linear prostoru

Rešenje:

  1. Kalibriši monitore development tima (makar osnovni sRGB profil)
  2. Uvek budi svestan u kom color space-u su tvoji input-i
  3. UE5 material editor automatski konvertuje sRGB teksture u linear -- ali color konstante unete ručno moraju biti u linear prostoru
  4. Koristi UE5-ov ugrađeni color picker koji radi konverziju automatski

16.9.6 Greška #6: Zaboravljanje na display-referred vs scene-referred

Problem: Developer gleda renderovanu sliku i kaže "nebo je previše svetlo, smanjiću intenzitet sky light-a". Ali problem nije u intenzitetu svetlosti -- problem je u tone mapping-u ili exposure-u!

Objašnjenje: U scene-referred prostoru (pre tone mapping-a), nebo treba da bude mnogo svetlije od enterijera. To je fizički tačno. Problem je što tone mapping i/ili auto exposure ne kompresuju taj raspon na pravi način.

Rešenje:

  1. Ne menjaj fizičke vrednosti svetlosti da bi "popravio" izgled
  2. Umesto toga, podesi exposure (manual ili auto) i tone mapping parametre
  3. Koristi histogram (vizualizacija raspodele svetlosti) da razumeš dinamički raspon scene
  4. Razdvoji "fizičku korektnost" (scene values) od "vizuelnog izgleda" (display values)

16.9.7 Greška #7: Nekonzistentno osvetljenje zbog mešanja lightmap-ova i real-time svetla

Problem: Lightmap-ovi (baked lighting) i real-time svetla koriste različite color space-ove ili različite exposure vrednosti, pa scena izgleda nekonzistentno.

Simptom: Oblasti sa baked osvetljenjem izgledaju drugačije (po boji ili intenzitetu) od oblasti sa real-time osvetljenjem, čak i kad bi trebalo da izgledaju isto.

Rešenje:

  1. UE5 Lumen uglavnom eliminiše ovaj problem jer je primarno real-time
  2. Ako koristiš baked lighting, osiguraj da su lightmap-ovi u linear prostoru
  3. Proveri da r.AllowStaticLighting i lighting settings koriste konzistentne jedinice
  4. Koristi fizičke jedinice za sve svetlosti (lumeni, kandele) radi konzistentnosti

16.10 Praktični Primeri u UE5

16.10.1 Postavljanje baznog Color Pipeline-a

Evo preporučenog setup-a za novi UE5 projekat:

1. Project Settings → Engine → Rendering:
   ✓ Ensure render targets are FP16 (default)
   ✓ HDR Display Output: prema potrebi
   
2. Post Process Volume (Global, Unbound):
   ✓ Tone Mapper: ACES (default)
   ✓ Expand Gamut: 1.0
   ✓ Blue Correction: 0.6
   ✓ Exposure: Manual ili Auto sa razumnim opsegom
   ✓ Color Grading: bazna podešavanja za željeni look
   
3. Teksture:
   ✓ Color teksture: sRGB = ON
   ✓ Data teksture: sRGB = OFF
   ✓ Compression: podesi prema tipu
   
4. Materijali:
   ✓ Koristi UE5 material editor (automatski linear workflow)
   ✓ Color konstante: koristi color picker (konvertuje automatski)

16.10.2 Dijagnostikovanje color problema

Kada nešto ne izgleda kako treba, koristi ove alate:

UE5 Buffer Visualization:

Viewport → Show → Buffer Visualization:
  ├── Scene Color: HDR scene pre tone mapping-a
  ├── Final Image: nakon tone mapping i color grading
  ├── Scene Color / No Tone Mapping: linearna scena bez tone mapping-a
  └── Post Process Input: ulaz u post-process pipeline

Console komande za debug:

r.TonemapperFilm 0/1          -- isključi/uključi filmic tone mapper
r.EyeAdaptation.MethodOverride -- override auto exposure
ShowFlag.Tonemapper 0/1        -- isključi tone mapping potpuno
ShowFlag.ColorGrading 0/1      -- isključi color grading
ShowFlag.PostProcessing 0/1    -- isključi sav post-processing

Pixel Inspector:

16.10.3 Primer: Kreiranje cinematskog look-a

Recimo da pravimo dark fantasy igru i želimo mračan, desaturisan look sa toplim highlight-ima i hladnim senkama:

Post Process Volume podešavanja:

// Globalno
Global Saturation: (0.85, 0.85, 0.85, 1.0)  -- blago desaturisano
Global Contrast: (1.1, 1.1, 1.1, 1.0)        -- pojačan kontrast

// Senke
Shadows Gain: (0.85, 0.90, 1.05, 1.0)  -- hladne senke (više plave)
Shadows Max: 0.09

// Srednji tonovi
Midtones Saturation: (0.9, 0.9, 0.9, 1.0)  -- malo desaturisano

// Svetli tonovi
Highlights Gain: (1.1, 1.05, 0.95, 1.0)  -- topli highlights (više crvene, manje plave)
Highlights Min: 0.5

// Tone Mapper
Slope: 0.88
Toe: 0.55
Shoulder: 0.26
Black Clip: 0.005  -- blago podignuta crna tačka
White Clip: 0.04

// Exposure
Auto Exposure Min/Max: 1.0 / 8.0  -- kontrolisan opseg
Exposure Compensation: -0.5  -- ukupno malo tamnije

// Finalni touch
Film Grain Intensity: 0.03  -- veoma blag grain, maskira banding
Vignette Intensity: 0.3     -- blaga vinjeta za fokusiranje pažnje

16.10.4 Primer: HDR Output Setup

Za projekat koji cilja HDR10 display:

1. Project Settings:
   Enable HDR Display Output: ✓
   
2. Post Process Volume:
   // Exposure prilagođen za HDR
   // Veći raspon jer HDR display prikazuje više
   Auto Exposure Min Brightness: 0.5
   Auto Exposure Max Brightness: 12.0
   
   // Tone Mapper prilagođen za HDR
   // Manje agresivan -- ne moramo toliko da kompresujemo
   HDR Display Color Gamut: Rec. 2020
   HDR Display Max Luminance: 1000  // ili koliko tvoj target display podržava
   
3. UI:
   // UI luminance treba da bude niži od peak scene luminance
   // Inače UI "zaslepljuje"
   UI Nits: 200-300 (tipično)
   
4. Testiranje:
   // OBAVEZNO testiraj na pravom HDR displeju!
   // SDR monitor NE MOŽE da prikaže HDR sadržaj korektno

16.11 Matematički Dodatak: Ključne Formule

Za one koji žele dublje razumevanje, evo ključnih formula korišćenih u color pipeline-u:

16.11.1 sRGB konverzija (precizna)

Linear → sRGB:
  if (linear <= 0.0031308)
    sRGB = linear × 12.92
  else
    sRGB = 1.055 × linear^(1/2.4) - 0.055

sRGB → Linear:
  if (sRGB <= 0.04045)
    linear = sRGB / 12.92
  else
    linear = ((sRGB + 0.055) / 1.055) ^ 2.4

Primeti da precizna formula koristi eksponent 2.4 (ne 2.2!) i ima linearan segment za veoma tamne vrednosti. Za većinu praktičnih primena, gamma 2.2 je dovoljno bliska aproksimacija.

16.11.2 PQ (Perceptual Quantizer) Transfer Function

Za HDR10 output koristi se ST.2084 PQ kriva:

PQ Encoding (Linear → PQ):
  m1 = 0.1593017578125
  m2 = 78.84375
  c1 = 0.8359375
  c2 = 18.8515625
  c3 = 18.6875
  
  Ym1 = (Y / 10000) ^ m1
  PQ = ((c1 + c2 × Ym1) / (1 + c3 × Ym1)) ^ m2

Gde je Y luminance u nits-ima (cd/m²). PQ kriva je dizajnirana da bude perceptualno uniformna za ceo raspon ljudskog vida (0.0001 do 10,000 nits).

16.11.3 Color Space konverzija (Matrix Multiply)

Konverzija između color space-ova se radi množenjem sa 3×3 matricom:

sRGB → XYZ (D65 illuminant):
  | X |   | 0.4124  0.3576  0.1805 |   | R_linear |
  | Y | = | 0.2126  0.7152  0.0722 | × | G_linear |
  | Z |   | 0.0193  0.1192  0.9505 |   | B_linear |

Rec.2020 → XYZ:
  | X |   | 0.6370  0.1446  0.1689 |   | R_linear |
  | Y | = | 0.2627  0.6780  0.0593 | × | G_linear |
  | Z |   | 0.0000  0.0281  1.0610 |   | B_linear |

Da konvertuješ iz sRGB u Rec.2020, ideš sRGB → XYZ → Rec.2020 (dva matrix multiply-a, ili pre-computed jedan combined).

16.11.4 Luminance izračunavanje

Luminance (perceptualna "svetlina") iz linear RGB:

Za sRGB / Rec.709:
  Y = 0.2126 × R + 0.7152 × G + 0.0722 × B

Za Rec.2020:
  Y = 0.2627 × R + 0.6780 × G + 0.0593 × B

Primeti da zelena komponenta dominira (71.52% za sRGB) -- to je zato što je ljudsko oko najosetljivije na zelenu svetlost.


16.12 Rezime i Ključni Pojmovi

Tabela ključnih pojmova

Termin Objašnjenje
sRGB Standardni color space za web, monitore, i gaming. Nelinearan (gamma encoded). Optimizovan za skladištenje i prikaz na 8-bit uređajima.
Linear Color Space Color space gde su numeričke vrednosti proporcionalne fizičkoj svetlosti. Neophodan za korektno renderovanje i lighting proračune.
Gamma Eksponent koji opisuje nelinearni odnos između kodiranih vrednosti i svetlosti. sRGB ≈ gamma 2.2.
Gamma Encoding Konverzija linear → nelinearno (tipično x^(1/2.2)). Primenjuje se za čuvanje i prikaz.
Gamma Decoding Konverzija nelinearno → linear (tipično x^2.2). Primenjuje se pre shader proračuna.
HDR (High Dynamic Range) Rendering sa preciznošću većom od 8 bita (tipično FP16), gde vrednosti mogu biti veće od 1.0.
FP16 (Half Float) 16-bitni floating point format. Raspon ±65,504 sa 10-bit mantise. Standard za HDR render target-e.
Tone Mapping Proces kompresije HDR raspona u LDR raspon za prikaz na displeju. Koristi S-krivu da sačuva detalje.
Reinhard Tone Mapping Jednostavan tone mapper: output = input / (1 + input). Matematički elegantan ali daje "mlak" izgled.
Filmic Tone Mapping Tone mapper inspirisan karakteristikom filmske trake. Daje filmski look sa lepim kontrastom.
ACES Academy Color Encoding System. Industrijki standard za color management. Obuhvata IDT, RRT, ODT. Default tone mapper u UE5.
RRT Reference Rendering Transform. Deo ACES-a koji konvertuje scene-referred u display-referred.
ODT Output Device Transform. Deo ACES-a koji prilagođava output za specifičan displej.
Color Grading Kreativno podešavanje boja (contrast, saturation, hue shift, shadows/highlights).
LUT (Look-Up Table) 3D tekstura koja mapira ulaznu RGB boju na izlaznu RGB boju. Zamenjuje kompleksne color operacije jednim texture sample-om.
Scene-referred Vrednosti koje opisuju svetlost u sceni (bez gornje granice). Pre tone mapping-a.
Display-referred Vrednosti prilagođene za prikaz na specifičnom displeju. Posle tone mapping-a.
HDR10 Standard za HDR sadržaj: 10-bit, PQ kriva, Rec. 2020 color space, do 10,000 nits.
Dolby Vision Propreitarni HDR format sa 12-bit podrškom i dinamičkim metadata.
PQ (Perceptual Quantizer) Transfer function za HDR (ST.2084). Perceptualno uniformna za ceo raspon ljudskog vida.
Rec. 709 Color space za HDTV. Iste primaries kao sRGB, drugačija gamma.
Rec. 2020 Ultra-široki color space za UHDTV i HDR. ~76% širi od sRGB.
DCI-P3 Color space za digitalnu bioskopsku projekciju. ~25% širi od sRGB.
Wide Color Gamut (WCG) Displej ili color space širi od sRGB.
Color Banding Vidljive trake boja u gradijentima, uzrokovane nedovoljnom preciznošću ili kvantizacijom.
Double Gamma Greška gde se gamma encoding primeni dva puta, rezultujući "ispranim" izgledom.
Dithering Tehnika dodavanja malog šuma za maskiranje color banding-a.
Chromaticity Osobina boje nezavisna od luminance-a (nijansa i zasićenost bez svetline).

Rezime poglavlja

  1. sRGB vs Linear -- sRGB je za skladištenje i prikaz (perceptualno uniforman, optimalan za 8-bit). Linear je za rendering (fizički korektan, matematika radi ispravno). Nikada ne renderuj u sRGB prostoru.

  2. Gamma -- CRT monitori su imali prirodnu gamma karakteristiku (~2.2) koju smo zadržali kao standard. Gamma encoding komprimuje linear vrednosti za efikasno skladištenje. Gamma decoding ih vraća za rendering.

  3. HDR pipeline -- Renderiraj u FP16 bufferima gde vrednosti mogu biti 0 do beskonačno. Scene-referred vrednosti čuvaju pun dynamic range. Tek na kraju tone mapping kompresuje za displej.

  4. Color grading -- Kreativno podešavanje boja za željeni vizualni stil. Radi se nakon tone mapping-a. UE5 nudi bogat set parametara kroz Post Process Volume.

  5. LUT -- 3D tekstura koja zamenjuje kompleksne color operacije jednim texture lookup-om. UE5 automatski generiše interni LUT koji kombinuje tone mapping i color grading.

  6. Tone mapping -- Neophodan za kompresiju HDR u LDR. S-kriva tone mapper-i (Reinhard, Filmic, ACES) čuvaju detalje u highlight-ima. ACES je default u UE5.

  7. ACES -- Industrijski standard za color management. Definiše scene-referred → display-referred konverziju. UE5 koristi ACES-inspirisan tone mapper.

  8. WCG i HDR displej -- Moderni displej-i podržavaju šire boje (DCI-P3, Rec. 2020) i veći dynamic range (HDR10, Dolby Vision). UE5 ima podršku za HDR output.

  9. Česte greške -- Pogrešan sRGB flag na teksturama, rendering u sRGB, double gamma, color banding, over-saturacija. Razumevanje color science-a eliminiše ove probleme.


16.13 Dodatni Resursi

Za dalje učenje, preporučujem sledeće resurse:

Dokumentacija i specifikacije

Članci i prezentacije

Alati

Knjige


Veza sa Poglavljem 05: Teksture i color space -- sRGB vs linear markiranje pri importu, kompresija, i format tekstura. Veza sa Poglavljem 15: Post-processing pipeline -- tone mapping, bloom (koji zavisi od HDR), color grading, i drugi post-process efekti u praksi.


U sledećem poglavlju pokrićemo narednu temu u našem putovanju kroz UE5 rendering i optimizaciju. Color science koji smo ovde naučili je temelj na kome počiva svaka vizualna odluka koju ćeš doneti -- od odabira tekstura do finalnog look-a tvoje igre.