淺談unity中gamma空間和線性空間

原文鏈接:http://www.cnblogs.com/zblade/

一、概述   

很久沒有寫文章了,今天寫一篇對gamma空間和線性空間的個人理解總結,在查閱和學習了各個資料後,算是一個個人筆記吧。  

二、Gamma顏色空間和線性顏色空間

其實對於顏色空間的理解,我個人是這樣理解的:所有的一切顏色空間,最終的目的,都是爲了最終投入到人眼中,能夠基本重現自然界的顏色。   

記住這一個目的,對下面的一些理解就會更加的有依據了。    

2.1 人眼的感知能力

既然目標是我們人自身,那麼我們就需要對人自身的眼睛的感知能力有一個基本的認識:人眼對於光強度的感知是非線性的。   

什麼是線性,什麼是非線性,從數學的角度說,就是自變量的變化和因變量的變化是否成固定比例(默認爲1),如果成比例,即:y = kx, 那麼這個變化就是線性的。

如果不成固定比例,那麼這個變化就是非線性的,非線性是自然界最常見的變化關係。   

人類對於很多環境因素的變化的感知能力,都是非線性的,例如對於音階,就是基於等比關係,而不是線性關係;對於分貝,對於疼痛等級,等等。  

回到對光強的感知,人眼對於光強度的變化的感知,是非線性的,這是通過實驗得出的結論。如果在一個全黑的房間中,放入一根蠟燭,此時感知的光強變化比較明顯;

如果房間中已經放入100根蠟燭,再次放入一根蠟燭,此時人眼對這新加入的一根蠟燭帶來的光強度變化是沒有最初從0到1的感知強的(默認每根蠟燭的光強度增量一樣)。   

可見,人眼對於高亮部分的感知能力,是沒有暗部的感知能力強的。   

2.2 存儲空間的有限

上面說了人眼的感知能力特點,那麼自然界的光又是如何?自然界的光強度,是和其對應的功率成正比的,對應的範圍是極其大:日光下100000lux,  星光0.0003 lux...  

如果要將這麼大範圍的光強度變化都表示存儲起來,其對內存的佔用以及傳輸帶寬的佔用是無法承受的。

業界目前主流的,對於顏色亮度的表示,用的是8位,也就是8bit,從0-255來進行表示。逐漸也有32位的真彩,當然不在這次的討論中。   

2.3 Gamma空間

基於1和2的論證,那麼如何將自然採光的結果存儲到實際的圖片中,就有一個基本的思路:將自然光以接近人眼感知能力曲線的函數進行壓縮到8位圖像中,這時候得到的圖形就是經過壓縮後的顏色結果。   

所謂Gamma壓縮,其實質就是這個壓縮的函數,是以Vout = VinGamma 來進行壓縮的。   

現在業界提到的Gamma = 2.2, 是業界經過反覆測量,得到的一個數值,這樣可以在256個灰度階的範圍內更多的保留暗部的細節:

 

 

 上面的兩個圖兩個圖,就可以基本的解釋Gamma = 2.2 的來源,人眼的感知能力和n = 1/2.2的冪函數比較靠近,當然不同環境下有不同的數值,大概範圍在1.8-2.5之間。   

2.4 線性空間

理解非線性空間-Gamma空間後,自然可以理解線性空間,就是上面圖二中的 n = 1這條曲線,爲什麼要提線性空間?因爲我們的相機對於光強的感知,是基於線性空間的。  

舉一個簡單例子,兩個光子投射到相機上,其得到的光強就是2倍光子光強,當然我們已經知道人眼並不是2倍光強。   

而業界的圖片都是Gamma空間中存儲,那麼相機到最終圖片,就會經歷一個編碼過程,這就是所謂的Gamma編碼,也就是: Vout = Vin(1/2.2) 這個過程。   

 

三、Gamma補償

現在,我們通過相機拍攝的圖片,最終是以gamma空間的格式存儲(業界標準稱爲sRGB), 那麼我們在顯示器上查看圖片,是否也是以sRGB的結果顯示的?答案是否定的。

前面業界已經將原生自然界的光照進行了壓縮,那麼業界定然要通過一定的辦法將壓縮的圖片重新轉換回來,得到更接近自然界的圖像,這個過程,就是Gamma補償,也被叫做Gamma校正。   

既然我們知道是以什麼函數進行壓縮,那麼解壓的過程,自然就是一個求逆的過程,可以得到:Vout = Vin2.2     

這一步是業界的顯示器自動默認執行的,所以我們在最終向顯示器上提交的顏色,需要滿足對應的關係。

用一張圖表示整個採樣到顯示的過程: 

一句話總結: 採樣生成,使用了Gamma編碼,這是業界標準,顯示過程,使用了Gamma補償,這也是業界標準,選取gamma = 2.2, 這是業界根據人眼進行測試得到的比較靠近人眼感知能力曲線的數值。

 

四、Unity中使用線性空間和Gamma空間

 在圖形學界,技術是不斷進步和探索的,應用一直都是延遲更新的(爲了向下兼容的需要)。  

當然gamma空間的存在,以前都是忽視這部分的差異,直接基於gamma空間的存圖進行光學計算的。   

但是引擎中的光學計算(shader中),是基於線性空間的公式進行的,這樣就會帶來較大的差異,我們推算的公式基於線性空間得到的,但是輸入的數據是基於gamma空間存儲的格式,圖像採集得到的結果

作爲光學計算公式的輸入,得到的輸出自然是錯誤的。以前遊戲行業對於這個一直處於忍受階段,也可以通過美術進行調整,得到較爲差異不大的計算結果。   

最近幾年逐漸推廣的PBR技術,對於光照的計算更爲苛刻,這推動了線性空間在遊戲行業的逐步推廣。   

4.1 Gamma空間的處理過程

在gamma空間中,在shader進行光學計算的過程中,直接將圖像採樣得到結果帶入公式中進行計算,得到的color存入colorbuff中,然後提交到顯示器,進過一次gamma補償,就得到最終的顏色。  

4.2 線性空間的處理過程

線性空間中,對所有的圖片,默認認爲圖片都是線性存儲的方式。所以如果原圖是Gamma空間的sRGB的存儲方式,需要勾選sRGB的標誌,這樣在進行shader計算的時候,會首先進行一次gamma補償,

將顏色從gamma空間轉換到線性空間,然後進行正確的光照計算,得到結果最後再轉換回到gamma空間(gamma壓縮), 最後提交到顯示器,進行一次gamma補償,得到最終的顏色。  

用一張圖表示這兩種處理的流程(直接用參考文章的圖): 

 

一句話總結:unity中的gamma空間和線性空間,其實質就是對存儲sRGB格式圖片,進行不同的光照計算,不同的光照計算進行不同的流程,得到精度不同的結果,最後都需要統一爲gamma空間

的格式,提交到顯示器上進行gamma補償,得到最終的顯示圖片。

 

 參考文章:

 https://www.zhihu.com/question/27467127 該問題下的大部分回答

https://zhuanlan.zhihu.com/p/37679604 較爲簡易

https://www.cambridgeincolour.com/tutorials/gamma-correction.htm 非遊戲向的解釋gamma校正   

https://docs.unity3d.com/Manual/LinearRendering-LinearOrGammaWorkflow.html unity官網的gamma/線性介紹

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章