实验 Unity Linear Color Space 发现结果不符合预期

  美术前上个礼拜找我问光照图老是烘焙过暗的问题,一时兴起我在 Gamma 和 Linear 两个颜色空间切换了下,发现一个 Shader 明暗不一样,另外一个 毫无变化,因而激发了我去研究下在 Unity 里使用 Linear 的细节。(虽然最后发现美术的问题跟这个不太有关系)html

  这里不想在过多冗长的去复述关于全部 Gamma 校订的历史和概念,假设已经阅读过相关资料,好比如下(包括但不限于):缓存

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

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

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

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

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

  这里仅仅讨论下 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。blog

图片A     

                        A                                                            B                                                           C图片

  能够发现,A 保持颜色不变,B 和 C 的颜色都变暗,都被作了 Gamma 校订 2.2,因此更暗;尤为是 C,本来 187 的颜色被矫正后,正好变成127,这是符合预期的。get

  接下来在场景中建立三个材质,使用 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

相关文章
相关标签/搜索