您的位置:首页 > 移动开发 > Unity3D

Unity - 杂 - 使用Linear还是Gamma

2016-09-12 16:58 357 查看

概述

线性渲染就是渲染场景所有输入都是线性的。一般来说存在的纹理都是经过Gamma矫正了的,也就是说当纹理被采样到一个材质上时,颜色值已经不是线性的了。如果这些纹理用通常的计算方式去计算光照和图片效果,在非线性空间计算,这将导致轻微的偏差。(而这种偏差就是需要Gamma矫正的原因)

线性渲染保证了在shader中输入与输出都是在正确的颜色空间得出更正确的结果。

Gamma矫正

所谓伽玛校正就是对图像的伽玛曲线进行编辑,以对图像进行非线性色调编辑的方法,检出图像信号中的深色部分和浅色部分,并使两者比例增大,从而提高图像对比度效果。计算机绘图领域惯以此屏幕输出电压与对应亮度的转换关系曲线,称为伽玛曲线(Gamma Curve)。以传统CRT(Cathode Ray Tube)屏幕的特性而言,它的输入电压和显示出来的亮度关系不是线性的,而是一个类似幂律(pow-law)曲线的关系,而这个关系又恰好跟人眼对光的敏感度是相反的。这个巧合意味着,虽然CRT显示关系是非线性的,但对人类来说感知上很可能是一致的。

Gamma 校正补偿了不同输出设备存在的颜色显示差异,从而使图像在不同的监视器上呈现出相同的效果。

保存颜色信息本身矫正称为encoding gamma,显示器对颜色的矫正称为display gamma,所以一个完整的图形系统中需要两个Gamma值,两次矫正刚好在一定程度上抵消(但一般不是完全抵消)。

Gamma管线(Gamma Pipeline)

在Gamma渲染管线中,所有颜色和纹理在Gamma空间被采样,在shader应用了之后前,不会对shader输入做任何处理。即使这些值是在Gamma空间中的,所有shader计算对待他们输入都当做在线性空间,此外,当把shader输出写到内存中时,没有对最终像素应用Gamma矫正。很多时候是可以接受两次偏差一定程度上相互抵消。但是这是不正确的。

两种情况:

线性输入

输入颜色值在线性空间下,而在shader中按照线性空间下的计算,这些都是正确的,但最终输出的时候也没有做任何处理(主要Gamma矫正),所以在屏幕显示时,屏幕进行了一次display gamma,这样的转换后得到非预期的亮度,通常表现为整个场景比较昏暗。

非线性输入

输入颜色值在非线性空间下(通常表现为纹理),而在shader中把该值当成是线性空间下计算的(产生了偏差),这是不正确的,在最终输出的时候也没有做任何处理,但在屏幕显示时,进行了display gamma,虽然这样产生两次偏差会在一定程度上进行抵消,但这样的抵消是不正确的。

为了直接显示时可以正确显示,大多数图像文件都进行了提前的校正,即已经使用了一个encoding gamma对像素值编码。

线性管线(Linear Pipeline)

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

sRGB模式是在近代的GPU上才有的东西。如果不支持sRGB,我们就需要自己在shader中进行伽马校正。

对非线性输入纹理的校正通常代码如下:

float3 diffuseCol = pow(tex2D(diffTex, texCoord), 2.2);


在最后输出前,对输出像素值的校正代码通常长下面这样:

fragColor.rgb = pow(fragColor.rgb, 1.0/2.2);
return fragColor;


但是,手工对输出像素进行伽马校正在使用混合的时候会出现问题。这是因为,校正后导致写入color buffer的颜色是非线性的,这样混合就发生在非线性空间中。一种解决方法时,在中间计算时不要对输出进行伽马校正,在最后进行一个屏幕后处理操作对最后的输出进行伽马校正,但很显然这会造成性能问题。 还有一些细节问题,例如在进行屏幕后处理的时候,要小心我们目前正在处理的图像到底是不是已经伽马校正后的。

总之,一切工作都是为了“保证所有的输入都转换到线性空间,并在线性空间下做各种光照计算,最后的输出(最最最最后的输出)进行伽马校正后再显示”。

Linear Rendering 和 Gamma Rendering的区别

Linear Rendering就是在shader中所有计算会在线性空间下进行,Gamma Rendering就是在shader中不进行转换到线性空间下,直接计算。然就是计算方程式不同,也就意味例如光照表面会有不同的响应曲线和图片效果,表现不相同。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unity