實驗 Unity Linear Color Space 發現結果不符合預期


  美術前上個禮拜找我問光照圖總是烘焙過暗的問題,一時興起我在 Gamma 和 Linear 兩個顏色空間切換了下,發現一個 Shader 明暗不同,另一個 毫無變化,於是激發了我去研究下在 Unity 里使用 Linear 的細節。(雖然最后發現美術的問題跟這個不太有關系)

  這里不想在過多冗長的去復述關於所有 Gamma 校正的歷史和概念,假設已經閱讀過相關資料,比如以下(包括但不限於):

  https://www.cnblogs.com/murongxiaopifu/p/9001314.html

  https://blog.csdn.net/candycat1992/article/details/46228771

  https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch24.html

  https://www.qiankanglai.me/2014/12/24/gamma-correction/

  https://docs.unity3d.com/Manual/LinearLighting.html

  這里僅僅討論下 Unity 平台下 Linear 空間下渲染出現的和預期不一致的錯誤(姑且先叫錯誤,着實還不明白的地方),和所理解然后預期的結果不一致。測試場景也很簡單,制作三張紅色貼圖A, B 和 C,其中 A 和 B 一樣:(127,0,0),C 為(187,0,0),其中187=((127/255)^0.45)*255。A 導入選項為 Linear,不勾選 sRGB,B 勾選 sRGB,C勾選 sRGB。

圖片A     

                        A                                                            B                                                           C

  可以發現,A 保持顏色不變,B 和 C 的顏色都變暗,都被做了 Gamma 校正 2.2,所以更暗;尤其是 C,原本 187 的顏色被矯正后,正好變成127,這是符合預期的。

  接下來在場景中創建三個材質,使用 Shader:Unit/Texture 來顯示貼圖本身顏色,貼圖分別使用 A, B, C;然后創建一個 Sphere 分別使用這三個材質在 Linear 空間下渲染查看顏色。顯示效果如下:

     

                       A                                                                                 B                                                                       C

  然而預期結果為:球 A 和 C 均為 (127,0,0)B 為(55,0,0)。根據:A 貼圖為 Linear,采樣后不會被硬件 Gamma 2.2 而維持原樣,Shader 計算輸出到 ColorBuffer 時 Gamma 0.45 提亮,最終輸出到顯示器再 Gamma 2.2,最終輸出顏色(127,0,0);B 貼圖為 sRGB,采樣后被硬件 Gamma 2.2 為 ((127/255)^2.2)*255=55,然后 Shader 中計算輸出 ColorBuffer 時 Gamma 0.45 變回到127,最終被顯示器 Gamma 2.2,輸出顏色(55,0,0);

  以上可以看到實際渲染結果和預期結果的差異:實際渲染結果都被“提亮“了,都額外的被多增加了一個 Gamma 0.45。可是至少 Linear 的圖片是什么顏色就應該輸出什么顏色。於是將以上三種情況分別在手機上使用 RenderDoc 抓幀分析下。

  場景 A:

以上分別顯示了 A 場景中,圖片的格式,以及紋理緩存的格式:

  Red127_Linear 格式:GL_COMPRESSED_RGB8_ETC2,顏色為(127,0,0);

  Color Buffer 格式:GL_SRGB8_ALPHA8,顏色為(187,0,0),

  由於寫入 ColorBuffer 會做 Gamma 0.45 的校正,所以 ColorBuffer 這個顏色是正確的,配合顯示器的 Gamma 2.2 校正,應該正好為(127,0,0)。可是實際上顯示器輸出的就是 ColorBuffer 的內容(187,0,0),像是沒有經過 Gamma 2.2 校正;抑或是因為 sRGB 格式的 ColorBuffer 再次被 Gamma 0.45,然后再被顯示器 Gamma 2.2,否則如何解釋呢?暫時不明白。

  

  那么再看下場景 B:

  Red127_sRGB 格式:GL_COMPRESSED_SRGB_ETC2 顏色為(55,0,0),因為 sRGB 圖片做了 Gamma 2.2 校正;

  ColorBuffer 格式:GL_SRGB8_ALPHA8,顏色為(127,0,0),

  所以當 Color 輸出到顯示器做了 Gamma 2.2 校正后,實際顏色應該為 (55,0,0),然而貌似也少了這一步,跟情況 A 一樣。

 

  最后來看下場景 C:

  Red187_sRGB 格式:GL_COMPRESSED_SRGB_ETC2 顏色為(127,0,0),因為 sRGB 圖片做了 Gamma 2.2 校正;
  ColorBuffer 格式:GL_SRGB8_ALPHA8,顏色為(187,0,0),

  最后 ColorBuffer 輸出經過顯示器的 Gamma 2.2 矯正后應該輸出顏色 (127,0,0),然而實際卻是(187,0,0),同場景 A 和 B 的情況一模一樣。

  以上測試使用 Unity 2018.1.2f1。


 

  綜上,以上三種結果和過程分析都指向一個事實:Unity 在 Linear 顏色空間下直接將 sRGB 格式的 ColorBuffer 輸出到了顯示器,缺少了 Gamma 2.2 這一步,使得顏色都變亮了,無法得出預期的結果,或許有什么地方理解的還不到位,也或者我缺少了過程中的某個設置,目前還不得而知,如果有哪位大牛知道,還請指點下。

【本文固定地址:https://www.cnblogs.com/yaukey/p/unity_linear_color_space_unexpected_results.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM