# 对线性空间和线性渲染的调研

学习资料来自:

学习笔记记于 2017/04/25

线性渲染就是渲染场景所有输入都是线性的。线性渲染保证了在 Shader 中输入与输出都是在正确的颜色空间得出的正确结果。

如果开启了线性渲染(Linear Rendering),Unity 会把输入纹理设置为 sRGB 模式,这种模式下硬件在对纹理进行采样时会自动将其转换到线性空间中;并且也会设置一个 sRGB 格式的 buffer,此时 GPU 会在 Shader 写入 Color Buffer 前自动进行伽马校正。如果此时开启了混合,在每次混合时,之前 buffer 中存储的颜色值会先重新转换回线性空间中,然后再进行混合,完成后再进行伽马校正,最后把校正后的混合结果写入 Color Buffer 中。这里需要注意,Alpha 通道是不会参与伽马校正的。

对伽马校正的调研在这里

sRGB (standard Red Green Blue) 是由 Microsoft 影像巨擎共同开发的一种彩色语言协议,微软联合爱普生、HP 惠普等提供一种标准方法来定义色彩,让显示、打印和扫描等各种计算机外部设备与应用软件对于色彩有一个共通的语言。sRGB 是 RGB 的一种特定类型。sRGB 很流行,但它的色域很有限。它使用的 Encoding Gamma 大约是 0.45(1/2.2),这个值为了配合 Display Gamma 为 2.5 的设备工作的,这样两次 Gamma 矫正后产生偏差为 0.45 * 2.5 = 1.125,从而在视觉上进行了补偿。sRGB 模式是在近代的 GPU 上才有的东西。如果不支持 sRGB,我们就需要自己在 Shader 中进行伽马校正。

Linear Rendering 就是在 Shader 中所有计算会在线性空间下进行,Gamma Rendering 就是在 Shader 中不进行转换到线性空间下,直接计算。计算方程式不同,也就意味例如光照表面会有不同的响应曲线和图片效果,表现不相同。

(1) Light Falloff

光照表现一般受光源的距离和法线两个因素影响(在同等光强下)。首先当我们用 Linear Rendering 时,执行 Gamma 矫正将会使光照范围变大,光照边缘更加清晰。第二种会使边缘模糊,分不清界限。

(2)表面响应强度

随着光强的增加,非线性方式计算的表面会更亮一些。这导致了光照在表面很多地方曝光过度,而且给场景模型一个褪色(变白色了)的感觉。当你用线性渲染时,表面颜色仍然随着光照强度线性增加的,这样就使表面材质和颜色更接近现实。

(3) 混合

混合是在帧缓冲区发生的,当使用 Gamma Rendering,这表示颜色之间混合是在非线性空间下计算的。然而这是不正确的。

上图是在 Linear Space 中混合结果,颜色之间过度不是很明显。下图是 Gamma Space 中混合结果,颜色交界处出现了明显的其它颜色,颜色更亮,出现褪色的现象。

(4) Mipmaps

计算纹理 Mipmap 是种线性计算,需要对某个方形区域内像素取平均值,如果纹理存储在非线性空间,那么计算时也是在非线性空间里计算,这样就会得到错误的结果。正确的做法是先转换到线性空间在计算 Mipmap。

(5) Lightmapping

切换 Linear 和 Gamma 方式,需要重新烘焙相关的 Lightmapping。

End.