天天看點

伽馬空間與線性空間

随着真實性更高的基于實體渲染(PBR)的到來,線性空間(Linear space)光照計算也越來越被經常提及。雖然線性空間和與之“對立”的伽馬空間(gamma space)是簡單而重要的概念,但很多開發者對它們的真正意義并不了解。這篇文檔将會介紹伽馬空間和線性空間、它們之間的差別以及在Unity引擎中的應用。

LINEAR SPACE

線性空間是什麼?簡單的說,線上性空間對數字化的顔色和光照強度進行相加相乘計算得到的結果依然能與真實的結果一緻。不具備這條性質就被稱為“非線性”空間。見下圖:

伽馬空間與線性空間

GAMMA SPACE

伽馬(gamma)的産生原因主要有兩點:第一是CRT顯示器的曆史原因,對顯示圖像的處理是非線性的。第二是因為人眼對明暗色域的辨識度不一樣,有時需要對圖像進行非線性處理來獲得合适的辨識度,這些非線性處理叫做伽馬糾正(gamma correction),具體實作是對圖像中的每個像素做一次幂函數運算。伽馬特指這個幂函數的指數值。見下圖:

伽馬空間與線性空間

上圖中,很顯然除1以外的伽馬值都是非線性的。下圖展示了用上圖中的不同伽馬值對圖像做伽馬糾正得到的結果:

伽馬空間與線性空間

重要!!!現實中絕大部分的圖檔都是被伽馬值為0.45糾正過的,也就是說圖檔檔案存儲的都是伽馬糾正過的顔色值。做伽馬糾正幾乎是每台相機、每個圖像編輯軟體在存儲圖像時預設要做的事。

但為什麼圖像很夠正确顯示,而不是像左圖一樣看起來過爆呢?這是顯示器顯示的時候做了非線性處理導緻的。CRT顯示器顯示圖像的時候做了伽馬值為2.2的糾正,之後的LCD顯示器為了相容性也做了同樣的糾正。2.2為0.45的倒數,互相抵消得到了與原始一緻的圖像。如果圖檔沒有做伽馬糾正,顯示的圖像将是像右圖一樣,顔色被壓黑。

COLOR SPACES AND THE RENDERING PIPELINE

在實時渲染管線中,如果采用伽馬空間,那麼伽馬糾正過的貼圖在着色器(shader)中直接參與光照計算,得到的圖像被顯示器伽馬糾正後輸出顯示。這個過程很簡單,但實體上是不正确的。在真實世界中,光照行為是線性的,着色器中的數字化的光照計算也是線性的,而輸入的貼圖和顔色是非線性的,這意味說着色結果是不準确的。在越來越追求畫面沉浸感和真實性的今天,伽馬空間的光照計算滿足不了需求。

是以,PBR使用了線性空間,貼圖和顔色去除了伽馬糾正轉換到線性空間,再傳遞給着色器進行光照計算着色,之後的後期處理(post effects)也同樣線上性空間下進行,最後獲得的圖像再做伽馬值0.45糾正,以抵消顯示器顯示時2.2的伽馬糾正。下圖是渲染管線采用伽馬空間和線性空間的流程和結果對比:

伽馬空間與線性空間

上圖中簡單球體的渲染差異可以注意到:伽馬空間高光的更亮,衰減範圍更大。這些都是缺乏真實性的渲染結果。

COLOR SPACES IN UNITY

Unity引擎渲染管線預設采用伽馬空間,目前隻有PC、 Xbox和PlayStation平台支援線性空間,可在編輯的此處進行切換:

Edit -> Project Settings -> Player -> Other Settings -> Color Space

切換到線性空間後,傳遞給着色器的将是無伽馬糾正的貼圖和顔色。如果在開發中的項目進行切換,場景看起來跟切換前會不一樣,需要重新調整光照和貼圖來達到想要的效果,燈光貼圖也需要重新烘焙。

如果同時設定了線性空間和HDR,那Unity所有的後期處理(post effects)全将線上性空間進行。如果隻設定了線性空間,那Unity仍使用伽馬幀緩沖(framebuffer),但當對幀緩沖進行讀或寫時,Unity會自動對顔色進行糾正來保證後期處理仍然線上性空間進行。

盡管Unity預設對移動平台不支援線性空間。但可以在着色器裡來做類似實作:對傳進來的貼圖做幂為2.2的pow()函數處理,然後在顔色傳回值前做幂為0.45的pow()函數處理。這種實作有計算開銷,不能濫用。

CONCLUSION

掌握伽馬空間和線性空間的不同,這樣在實際遊戲項目中可以規避一些顔色管理上的常識性錯誤,進而保證畫面品質。總之,線性空間的使用是獲得畫面沉浸感和真實性上的重要一環。

附原文連結:

http://www.kinematicsoup.com/news/2016/6/15/gamma-and-linear-space-what-they-are-how-they-differ

繼續閱讀