概述
線性渲染就是渲染場(chǎng)景所有輸入都是線性的。一般來(lái)說(shuō)存在的紋理都是經(jīng)過(guò)Gamma矯正了的,也就是說(shuō)當(dāng)紋理被采樣到一個(gè)材質(zhì)上時(shí),顏色值已經(jīng)不是線性的了。如果這些紋理用通常的計(jì)算方式去計(jì)算光照和圖片效果,在非線性空間計(jì)算,這將導(dǎo)致輕微的偏差。(而這種偏差就是需要Gamma矯正的原因)
線性渲染保證了在shader中輸入與輸出都是在正確的顏色空間得出更正確的結(jié)果。
Gamma矯正
所謂伽瑪校正就是對(duì)圖像的伽瑪曲線進(jìn)行編輯,以對(duì)圖像進(jìn)行非線性色調(diào)編輯的方法,檢出圖像信號(hào)中的深色部分和淺色部分,并使兩者比例增大,從而提高圖像對(duì)比度效果。計(jì)算機(jī)繪圖領(lǐng)域慣以此屏幕輸出電壓與對(duì)應(yīng)亮度的轉(zhuǎn)換關(guān)系曲線,稱為伽瑪曲線(Gamma Curve)。以傳統(tǒng)CRT(Cathode Ray Tube)屏幕的特性而言,它的輸入電壓和顯示出來(lái)的亮度關(guān)系不是線性的,而是一個(gè)類似冪律(pow-law)曲線的關(guān)系,而這個(gè)關(guān)系又恰好跟人眼對(duì)光的敏感度是相反的。這個(gè)巧合意味著,雖然CRT顯示關(guān)系是非線性的,但對(duì)人類來(lái)說(shuō)感知上很可能是一致的。
Gamma 校正補(bǔ)償了不同輸出設(shè)備存在的顏色顯示差異,從而使圖像在不同的監(jiān)視器上呈現(xiàn)出相同的效果。
保存顏色信息本身矯正稱為encoding gamma,顯示器對(duì)顏色的矯正稱為display gamma,所以一個(gè)完整的圖形系統(tǒng)中需要兩個(gè)Gamma值,兩次矯正剛好在一定程度上抵消(但一般不是完全抵消)。
下圖展示了Gamma矯正對(duì)顏色值的影響。
sRGB
個(gè)人電腦使用的一個(gè)標(biāo)準(zhǔn)叫sRGB,它使用的encoding gamma大約是0.45(1/2.2),這個(gè)值為了配合display gamma為2.5的設(shè)備工作的,這樣兩次gamma矯正后產(chǎn)生偏差為0.45 * 2.5 = 1.125,從而在視覺(jué)上進(jìn)行了補(bǔ)償。
非線性輸入
大部分圖像文件都進(jìn)行了提前矯正,就是保存文件時(shí)已經(jīng)使用了encoding gamma對(duì)像素值編碼,這意味著它是非線性的,如果在shader中直接使用就是在非線性空間計(jì)算,使得結(jié)果和真實(shí)世界結(jié)果不一致。
Gamma管線(Gamma Pipeline)
在Gamma渲染管線中,所有顏色和紋理在Gamma空間被采樣,在shader應(yīng)用了之后前,不會(huì)對(duì)shader輸入做任何處理。即使這些值是在Gamma空間中的,所有shader計(jì)算對(duì)待他們輸入都當(dāng)做在線性空間,此外,當(dāng)把shader輸出寫(xiě)到內(nèi)存中時(shí),沒(méi)有對(duì)最終像素應(yīng)用Gamma矯正。很多時(shí)候是可以接受兩次偏差一定程度上相互抵消。但是這是不正確的。
兩種情況:
線性輸入 輸入顏色值在線性空間下,而在shader中按照線性空間下的計(jì)算,這些都是正確的,但最終輸出的時(shí)候也沒(méi)有做任何處理(主要Gamma矯正),所以在屏幕顯示時(shí),屏幕進(jìn)行了一次display gamma,這樣的轉(zhuǎn)換后得到非預(yù)期的亮度,通常表現(xiàn)為整個(gè)場(chǎng)景比較昏暗。
非線性輸入 輸入顏色值在非線性空間下(通常表現(xiàn)為紋理),而在shader中把該值當(dāng)成是線性空間下計(jì)算的(產(chǎn)生了偏差),這是不正確的,在最終輸出的時(shí)候也沒(méi)有做任何處理,但在屏幕顯示時(shí),進(jìn)行了display gamma,雖然這樣產(chǎn)生兩次偏差會(huì)在一定程度上進(jìn)行抵消,但這樣的抵消是不正確的。
為了直接顯示時(shí)可以正確顯示,大多數(shù)圖像文件都進(jìn)行了提前的校正,即已經(jīng)使用了一個(gè)encoding gamma對(duì)像素值編碼。
Gamma是非線性的,Gamma空間就是所謂的非線性空間。
線性管線(Linear Pipeline)
如果開(kāi)啟了線性渲染(Linear Rendering),Unity會(huì)背地里把輸入紋理設(shè)置為sRGB模式,這種模式下硬件在對(duì)紋理進(jìn)行采樣時(shí)會(huì)自動(dòng)將其轉(zhuǎn)換到線性空間中;并且,也會(huì)設(shè)置一個(gè)sRGB格式的buffer,此時(shí)GPU會(huì)在shader寫(xiě)入color buffer前自動(dòng)進(jìn)行伽馬校正。如果此時(shí)開(kāi)啟了混合(像我們之前的那樣),在每次混合是,之前buffer中存儲(chǔ)的顏色值會(huì)先重新轉(zhuǎn)換回線性空間中,然后再進(jìn)行混合,完成后再進(jìn)行伽馬校正,最后把校正后的混合結(jié)果寫(xiě)入color buffer中。這里需要注意,Alpha通道是不會(huì)參與伽馬校正的。
sRGB模式是在近代的GPU上才有的東西。如果不支持sRGB,我們就需要自己在shader中進(jìn)行伽馬校正。
對(duì)非線性輸入紋理的校正通常代碼如下:
float3 diffuseCol = pow(tex2D( diffTex, texCoord ), 2.2 );
1
在最后輸出前,對(duì)輸出像素值的校正代碼通常長(zhǎng)下面這樣:
fragColor.rgb = pow(fragColor.rgb, 1.0/2.2);
return fragColor;
1
2
但是,手工對(duì)輸出像素進(jìn)行伽馬校正在使用混合的時(shí)候會(huì)出現(xiàn)問(wèn)題。這是因?yàn)椋U髮?dǎo)致寫(xiě)入color buffer的顏色是非線性的,這樣混合就發(fā)生在非線性空間中。一種解決方法時(shí),在中間計(jì)算時(shí)不要對(duì)輸出進(jìn)行伽馬校正,在最后進(jìn)行一個(gè)屏幕后處理操作對(duì)最后的輸出進(jìn)行伽馬校正,但很顯然這會(huì)造成性能問(wèn)題。 還有一些細(xì)節(jié)問(wèn)題,例如在進(jìn)行屏幕后處理的時(shí)候,要小心我們目前正在處理的圖像到底是不是已經(jīng)伽馬校正后的。
總之,一切工作都是為了“保證所有的輸入都轉(zhuǎn)換到線性空間,并在線性空間下做各種光照計(jì)算,最后的輸出(最最最最后的輸出)進(jìn)行伽馬校正后再顯示”。
Linear Rendering 和 Gamma Rendering的區(qū)別
Linear Rendering就是在shader中所有計(jì)算會(huì)在線性空間下進(jìn)行,Gamma Rendering就是在shader中不進(jìn)行轉(zhuǎn)換到線性空間下,直接計(jì)算。然就是計(jì)算方程式不同,也就意味例如光照表面會(huì)有不同的響應(yīng)曲線和圖片效果,表現(xiàn)不相同。
Light Falloff
光照表現(xiàn)一般受光源的距離和法線兩個(gè)因素影響(在同等光強(qiáng)下)。首先當(dāng)我們用Linear Rendering時(shí),執(zhí)行Gamma矯正將會(huì)使光照范圍變大。第二種會(huì)使邊緣模糊,分不清界限。這更準(zhǔn)確的表現(xiàn)了表面光照強(qiáng)度下降。
表面響應(yīng)強(qiáng)度
隨著光強(qiáng)的增加,非線性方式計(jì)算的表面會(huì)更亮一些。這導(dǎo)致了光照在表面很多地方曝光過(guò)度,而且給場(chǎng)景模型一個(gè)褪色(變白色了)的感覺(jué)。當(dāng)你用線性渲染時(shí),表面顏色仍然隨著光照強(qiáng)度線性增加的,這樣就使表面材質(zhì)和顏色更接近現(xiàn)實(shí)
混合
混合是在幀緩沖區(qū)發(fā)生的,當(dāng)使用Gamma Rendering,這表示顏色之間混合是在非線性空間下計(jì)算的。然而這是不正確的。
上圖是在Linear Space中混合結(jié)果,顏色之間過(guò)度不是很明顯。
上圖是Gamma Space中混合結(jié)果,顏色交界處出現(xiàn)了明顯的其它顏色,顏色更亮,出現(xiàn)褪色的現(xiàn)象。
Mipmaps
計(jì)算紋理Mipmap是種線性計(jì)算,需要對(duì)某個(gè)方形區(qū)域內(nèi)像素取平均值,如果紋理存儲(chǔ)在非線性空間,那么計(jì)算時(shí)也是在非線性空間里計(jì)算,這樣就會(huì)得到錯(cuò)誤的結(jié)果。正確的做法是先轉(zhuǎn)換到線性空間在計(jì)算mipmap。
Lightmapping
切換linear 和gamma方式,需要重新烘焙相關(guān)的Lightmapping。
寫(xiě)在最后
總結(jié)了最近學(xué)習(xí)的gamma correction,圍繞unity中l(wèi)inear和gamma討論,參考了大神們寫(xiě)的文章,加上自己學(xué)習(xí)的理解,就當(dāng)做自己的學(xué)習(xí)筆記,可能有些地方翻譯或理解不夠準(zhǔn)確,希望能和大家交流討論。