转自:http://www.fseraph.com/?p=434
经常玩单机的同学肯定发现去年开始,基本所有新游戏,一开始都会让我们做一次Gamma设定。这主要是因为大家都开始注意线性渲染管线了。还是老话,在电影行业,色彩管理是很成熟的技术,而游戏界也就是这几年才开始普及。下面简单写一下为什么我们需要线性渲染管线以及什么是Gamma校正。
1.Gamma校正
首先要说明的是,Gamma校正并不是为了补偿显示器的非线性响应,而是有更深层次的原因。
我们知道以前的CRT显示器输入电压和呈现的(亮度)Light Intensity是非线性关系I=vγ。
下面是两张重要的曲线图:
第一张图是CRT显示器输入电压和呈现的亮度(Light Intensity)的非线性关系
第二张图是人眼感知的亮度(Lightness)和呈现亮度(Light Intensity)的非线性关系图
所以,人眼对暗部的细节会更敏感,也就是说,如果我们要把一个浮点数的颜色通道值量化(Quantization)成256级的电压(每个颜色通道硬件像素bit是8位),那么9到10的变化,对人眼来说是可感知的,而211到212的变化,则是不可感知的。因此我们应该把更多的位用来编码更重要的暗部信息。这意味着我们输入的图像应该用第二张图的曲线也就是power(1/gamma)来预先处理,这个过程就叫做Gamma校正,这样处理过之后,再经过显示器的power(gamma)输出,刚好就是线性的反应曲线了,所以这其实是早期电视设计的一个Trick。或者按维基百科的说法,a combination of luck and engineering which simplified the electronics in early television sets.
2.为什么我们需要在线性空间进行光照计算
渲染器是线性的,光照计算也需要在线性空间内进行,但是,如果输入的Diffuse纹理不是在线性空间,而是在Gamma校正过的空间里面,那么用这些值计算的光照也就是不是线性的了。当然效果会有问题。而一般的纹理都会做预先的Gamma校正,以便正确的显示。这个问题是经常被忽视的,而2011开始的单机游戏,大家都开始重视线性管线的重要性,所以,大家可以发现,一开始游戏都会要求玩家选择合适Gamma值了。下图是一个例子,左边是考虑到Gamma校正,在线性空间光照的图形,请注意明暗边界的突变,这是合乎物理规则,而右边是在Gamma空间进行光照的结果,明暗边界是渐变的,这其实是不正确的。对于使用基于物理光照的游戏来说,必须保证整个渲染管线是线性的,否则结果很难凑的对。更好的理论分析,可以在Jim blinn’s Corner:A Ghost in Snowstorm中找到。
3.如何保证渲染管线是线性的
因为最近在重构新引擎的渲染流水线,所以这个问题一定要先解决。否则到美术资源开始量产,就晚了。
一般来说,我们有三种数据需要考虑Gamma:
- 各种贴图纹理(比如Diffuse,Specular,Gloss等):如果贴图是Gamma校正过的,那么我们可以用D3DSAMP_SRGBTEXTURE来让硬件采样时自动的变换到线性空间(Linear=colorγ),避免我们在Shader中手动的计算,因为基本主流显卡都支持这个特性,所以速度是很快的。但是需要注意的是,有的贴图可能不是sRGB的。需要根据材质调整的需求来决定。
- 特殊Shader的输入颜色常量:常量是浮点数,所以在传入之前变换到线性空间即可
- 需要插值的顶点色:我们可以在顶点中保存Gamma颜色值,在VS中变换到线性空间,然后用TEXCOORD输出给PS,这样可以利用硬件自动做插值。
参考文献:
Jim Blinn’s Corner : What is a Pixel,A Ghost in Snowstorms
http://www.graphics.cornell.edu/~westin/gamma/gamma.html
http://radsite.lbl.gov/radiance/refer/Notes/gamma.html
http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html
http://filmicgames.com/archives/299
http://filmicgames.com/archives/327
http://en.wikipedia.org/wiki/Gamma_correction
http://www.poynton.com/notes/color/GammaFQA.html
Related posts: