Unity - 雜 - 使用Linear還是Gamma

概述

線性渲染就是渲染場景所有輸入都是線性的。一般來說存在的紋理都是經過Gamma矯正了的,也就是說當紋理被採樣到一個材質上時,顏色值已經不是線性的了。如果這些紋理用通常的計算方式去計算光照和圖片效果,在非線性空間計算,這將導致輕微的偏差。(而這種偏差就是需要Gamma矯正的原因)

線性渲染保證了在shader中輸入與輸出都是在正確的顏色空間得出更正確的結果。

Gamma矯正

所謂伽瑪校正就是對圖像的伽瑪曲線進行編輯,以對圖像進行非線性色調編輯的方法,檢出圖像信號中的深色部分和淺色部分,並使兩者比例增大,從而提高圖像對比度效果。計算機繪圖領域慣以此屏幕輸出電壓與對應亮度的轉換關係曲線,稱爲伽瑪曲線(Gamma Curve)。以傳統CRT(Cathode Ray Tube)屏幕的特性而言,它的輸入電壓和顯示出來的亮度關係不是線性的,而是一個類似冪律(pow-law)曲線的關係,而這個關係又恰好跟人眼對光的敏感度是相反的。這個巧合意味着,雖然CRT顯示關係是非線性的,但對人類來說感知上很可能是一致的。

Gamma 校正補償了不同輸出設備存在的顏色顯示差異,從而使圖像在不同的監視器上呈現出相同的效果。

保存顏色信息本身矯正稱爲encoding gamma,顯示器對顏色的矯正稱爲display gamma,所以一個完整的圖形系統中需要兩個Gamma值,兩次矯正剛好在一定程度上抵消(但一般不是完全抵消)。

Gamma管線(Gamma Pipeline)

在Gamma渲染管線中,所有顏色和紋理在Gamma空間被採樣,在shader應用了之後前,不會對shader輸入做任何處理。即使這些值是在Gamma空間中的,所有shader計算對待他們輸入都當做在線性空間,此外,當把shader輸出寫到內存中時,沒有對最終像素應用Gamma矯正。很多時候是可以接受兩次偏差一定程度上相互抵消。但是這是不正確的。

兩種情況:

  1. 線性輸入
    輸入顏色值在線性空間下,而在shader中按照線性空間下的計算,這些都是正確的,但最終輸出的時候也沒有做任何處理(主要Gamma矯正),所以在屏幕顯示時,屏幕進行了一次display gamma,這樣的轉換後得到非預期的亮度,通常表現爲整個場景比較昏暗。

  2. 非線性輸入
    輸入顏色值在非線性空間下(通常表現爲紋理),而在shader中把該值當成是線性空間下計算的(產生了偏差),這是不正確的,在最終輸出的時候也沒有做任何處理,但在屏幕顯示時,進行了display gamma,雖然這樣產生兩次偏差會在一定程度上進行抵消,但這樣的抵消是不正確的。

爲了直接顯示時可以正確顯示,大多數圖像文件都進行了提前的校正,即已經使用了一個encoding gamma對像素值編碼。

線性管線(Linear Pipeline)

如果開啓了線性渲染(Linear Rendering),Unity會背地裏把輸入紋理設置爲sRGB模式,這種模式下硬件在對紋理進行採樣時會自動將其轉換到線性空間中;並且,也會設置一個sRGB格式的buffer,此時GPU會在shader寫入color buffer前自動進行伽馬校正。如果此時開啓了混合(像我們之前的那樣),在每次混合是,之前buffer中存儲的顏色值會先重新轉換回線性空間中,然後再進行混合,完成後再進行伽馬校正,最後把校正後的混合結果寫入color buffer中。這裏需要注意,Alpha通道是不會參與伽馬校正的。

sRGB模式是在近代的GPU上纔有的東西。如果不支持sRGB,我們就需要自己在shader中進行伽馬校正。
對非線性輸入紋理的校正通常代碼如下:

float3 diffuseCol = pow(tex2D(diffTex, texCoord), 2.2);

在最後輸出前,對輸出像素值的校正代碼通常長下面這樣:

fragColor.rgb = pow(fragColor.rgb, 1.0/2.2);
return fragColor;

但是,手工對輸出像素進行伽馬校正在使用混合的時候會出現問題。這是因爲,校正後導致寫入color buffer的顏色是非線性的,這樣混合就發生在非線性空間中。一種解決方法時,在中間計算時不要對輸出進行伽馬校正,在最後進行一個屏幕後處理操作對最後的輸出進行伽馬校正,但很顯然這會造成性能問題。 還有一些細節問題,例如在進行屏幕後處理的時候,要小心我們目前正在處理的圖像到底是不是已經伽馬校正後的。

總之,一切工作都是爲了“保證所有的輸入都轉換到線性空間,並在線性空間下做各種光照計算,最後的輸出(最最最最後的輸出)進行伽馬校正後再顯示”。

Linear Rendering 和 Gamma Rendering的區別

Linear Rendering就是在shader中所有計算會在線性空間下進行,Gamma Rendering就是在shader中不進行轉換到線性空間下,直接計算。然就是計算方程式不同,也就意味例如光照表面會有不同的響應曲線和圖片效果,表現不相同。

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