好久沒有寫文章了,今天寫一篇對gamma空間和線性空間的我的理解總結,在查閱和學習了各個資料後,算是一個我的筆記吧。 html
其實對於顏色空間的理解,我我的是這樣理解的:全部的一切顏色空間,最終的目的,都是爲了最終投入到人眼中,可以基本重現天然界的顏色。 函數
記住這一個目的,對下面的一些理解就會更加的有依據了。 學習
既然目標是咱們人自身,那麼咱們就須要對人自身的眼睛的感知能力有一個基本的認識:人眼對於光強度的感知是非線性的。 測試
什麼是線性,什麼是非線性,從數學的角度說,就是自變量的變化和因變量的變化是否成固定比例(默認爲1),若是成比例,即:y = kx, 那麼這個變化就是線性的。編碼
若是不成固定比例,那麼這個變化就是非線性的,非線性是天然界最多見的變化關係。 3d
人類對於不少環境因素的變化的感知能力,都是非線性的,例如對於音階,就是基於等比關係,而不是線性關係;對於分貝,對於疼痛等級,等等。 htm
回到對光強的感知,人眼對於光強度的變化的感知,是非線性的,這是經過實驗得出的結論。若是在一個全黑的房間中,放入一根蠟燭,此時感知的光強變化比較明顯;blog
若是房間中已經放入100根蠟燭,再次放入一根蠟燭,此時人眼對這新加入的一根蠟燭帶來的光強度變化是沒有最初從0到1的感知強的(默認每根蠟燭的光強度增量同樣)。 遊戲
可見,人眼對於高亮部分的感知能力,是沒有暗部的感知能力強的。 圖片
上面說了人眼的感知能力特色,那麼天然界的光又是如何?天然界的光強度,是和其對應的功率成正比的,對應的範圍是極其大:日光下100000lux, 星光0.0003 lux...
若是要將這麼大範圍的光強度變化都表示存儲起來,其對內存的佔用以及傳輸帶寬的佔用是沒法承受的。
業界目前主流的,對於顏色亮度的表示,用的是8位,也就是8bit,從0-255來進行表示。逐漸也有32位的真彩,固然不在此次的討論中。
基於1和2的論證,那麼如何將天然採光的結果存儲到實際的圖片中,就有一個基本的思路:將天然光以接近人眼感知能力曲線的函數進行壓縮到8位圖像中,這時候獲得的圖形就是通過壓縮後的顏色結果。
所謂Gamma壓縮,其實質就是這個壓縮的函數,是以Vout = VinGamma 來進行壓縮的。
如今業界提到的Gamma = 2.2, 是業界通過反覆測量,獲得的一個數值,這樣能夠在256個灰度階的範圍內更多的保留暗部的細節:
上面的兩個圖兩個圖,就能夠基本的解釋Gamma = 2.2 的來源,人眼的感知能力和n = 1/2.2的冪函數比較靠近,固然不一樣環境下有不一樣的數值,大概範圍在1.8-2.5之間。
理解非線性空間-Gamma空間後,天然能夠理解線性空間,就是上面圖二中的 n = 1這條曲線,爲何要提線性空間?由於咱們的相機對於光強的感知,是基於線性空間的。
舉一個簡單例子,兩個光子投射到相機上,其獲得的光強就是2倍光子光強,固然咱們已經知道人眼並非2倍光強。
而業界的圖片都是Gamma空間中存儲,那麼相機到最終圖片,就會經歷一個編碼過程,這就是所謂的Gamma編碼,也就是: Vout = Vin(1/2.2) 這個過程。
如今,咱們經過相機拍攝的圖片,最終是以gamma空間的格式存儲(業界標準稱爲sRGB), 那麼咱們在顯示器上查看圖片,是否也是以sRGB的結果顯示的?答案是否認的。
前面業界已經將原生天然界的光照進行了壓縮,那麼業界定然要經過必定的辦法將壓縮的圖片從新轉換回來,獲得更接近天然界的圖像,這個過程,就是Gamma補償,也被叫作Gamma校訂。
既然咱們知道是以什麼函數進行壓縮,那麼解壓的過程,天然就是一個求逆的過程,能夠獲得:Vout = Vin2.2
這一步是業界的顯示器自動默認執行的,因此咱們在最終向顯示器上提交的顏色,須要知足對應的關係。
用一張圖表示整個採樣到顯示的過程:
一句話總結: 採樣生成,使用了Gamma編碼,這是業界標準,顯示過程,使用了Gamma補償,這也是業界標準,選取gamma = 2.2, 這是業界根據人眼進行測試獲得的比較靠近人眼感知能力曲線的數值。
在圖形學界,技術是不斷進步和探索的,應用一直都是延遲更新的(爲了向下兼容的須要)。
固然gamma空間的存在,之前都是忽視這部分的差別,直接基於gamma空間的存圖進行光學計算的。
可是引擎中的光學計算(shader中),是基於線性空間的公式進行的,這樣就會帶來較大的差別,咱們推算的公式基於線性空間獲得的,可是輸入的數據是基於gamma空間存儲的格式,圖像採集獲得的結果
做爲光學計算公式的輸入,獲得的輸出天然是錯誤的。之前遊戲行業對於這個一直處於忍受階段,也能夠經過美術進行調整,獲得較爲差別不大的計算結果。
最近幾年逐漸推廣的PBR技術,對於光照的計算更爲苛刻,這推進了線性空間在遊戲行業的逐步推廣。
在gamma空間中,在shader進行光學計算的過程當中,直接將圖像採樣獲得結果帶入公式中進行計算,獲得的color存入colorbuff中,而後提交到顯示器,進過一次gamma補償,就獲得最終的顏色。
線性空間中,對全部的圖片,默認認爲圖片都是線性存儲的方式。因此若是原圖是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/線性介紹