Gamma、Linear、sRGB 和Unity Color Space,你真懂了吗?(转)

Gamma、Linear、sRGB 和Unity Color Space,你真懂了吗?

转发大佬文章,一文将Gamma空间与线性空间和Unity中使用线性空间都说清楚了。


“为什么我渲染出来的场景,总是感觉和真实世界不像呢?”

游戏从业者或多或少都听过Linear、Gamma、sRGB和伽马校正这些术语,互联网上也有很多科普的资料,但是它们似乎又都没有讲很"清楚"。

游戏界(特别是中小团队)很容易忽略这些概念造成的影响。长远来看,作为游戏从业者的你应该理解这些术语的含义,理解它们的本质联系,理解选择Linear或Gamma 空间带来的工作流变化。

本文将会简单介绍Gamma、Linear、sRGB和伽马校正的概念。接着通过实例解析统一到线性空间的步骤,最后介绍如何在Unity中实施相应的工作流。

什么是Linear、Gamma、sRGB和伽马校正

在物理世界中,如果光的强度增加一倍,那么亮度也会增加一倍,这是线性关系。

而历史上最早的显示器(阴极射线管)显示图像的时候,电压增加一倍,亮度并不跟着增加一倍。即输出亮度和电压并不是成线性关系的,而是呈亮度增加量等于电压增加量的2.2次幂的非线性关系:

2.2也叫做该显示器的Gamma值,现代显示器的Gamma值也都大约是2.2。

这种关系意味着当电压线性变化时,相对于真实世界来说,亮度的变化在暗处变换较慢,暗占据的数据范围更广,颜色整体会偏暗。

如图,直线代表物理世界的线性空间(Linear Space),下曲线是显示器输出的Gamma2.2空间(Gamma Space)

横坐标表示电压,纵坐标表示亮度

好了,正常情况下,人眼看物理世界感知到了正常的亮度。而如果显示器输出一个颜色后再被你看到,即相当于走了一次Gamma2.2曲线的调整,这下子颜色就变暗了。如果我们在显示器输出之前,做一个操作把显示器的Gamma2.2影响平衡掉,那就和人眼直接观察物理世界一样了!这个平衡的操作就叫做伽马校正。

在数学上,伽马校正是一个约0.45的幂运算(和上面的2.2次幂互为逆运算):

左(Gamma0.45) 中(Gamma2.2) 右(线性物理空间)

经过0.45幂运算,再由显示器经过2.2次幂输出,最后的颜色就和实际物理空间的一致了。

最后,什么是sRGB呢?1996年,微软和惠普一起开发了一种标准sRGB色彩空间。这种标准得到许多业界厂商的支持。sRGB对应的是Gamma0.45所在的空间

为什么sRGB在Gamma0.45空间?

假设你用数码相机拍一张照片,你看了看照相机屏幕上显示的结果和物理世界是一样的。可是照相机要怎么保存这张图片,使得它在所有显示器上都一样呢? 可别忘了所有显示器都带Gamma2.2。反推一下,那照片只能保存在Gamma0.45空间,经过显示器的Gamma2.2调整后,才和你现在看到的一样。换句话说,sRGB格式相当于对物理空间的颜色做了一次伽马校正

还有另外一种解释,和人眼对暗的感知更加敏感的事实有关。

上方:人眼对光强度的感知呈非线性增长,下方:真实世界光强度呈线性增长

如图,在真实世界中(下方),如果光的强度从0.0逐步增加到1.0,那么亮度应该是线性增加的。但是对于人眼来说(上方),感知到的亮度变化却不是线性的,而是在暗的地方有更多的细节。换句话说,我们应该用更大的数据范围来存暗色,用较小的数据范围来存亮色。这就是sRGB格式做的,定义在Gamma0.45空间。而且还有一个好处就是,由于显示器自带Gamma2.2,所以我们不需要额外操作显示器就能显示回正确的颜色。

以上内容,看完后还是不懂也没关系,在继续之前你可以先死记住以下几个知识点:

  • 显示器的输出在Gamma2.2空间。
  • 伽马校正会将颜色转换到Gamma0.45空间。
  • 伽马校正和显示器输出平衡之后,结果就是Gamma1.0的线性空间。
  • sRGB对应Gamma0.45空间。

统一到线性空间

现在假设你对上文的概念有一定认识了,我们来讲重点吧。

在Gamma 或 Linear空间的渲染结果是不同的,从表现上说,在Gamma Space中渲染会偏暗,在Linear Space中渲染会更接近物理世界,更真实:

左(Gamma Space),右(Linear Space)

为什么Linear Space更真实?

你可以这么想,物理世界中的颜色和光照规律都是在线性空间描述的对吧?(光强度增加了一倍,亮度也增加一倍)。 而计算机图形学是物理世界视觉的数学模型,Shader中颜色插值、光照的计算自然也是在线性空间描述的。如果你用一个非线性空间的输入,又在线性空间中计算,那结果就会有一点“不自然”。

换句话说,如果所有的输入,计算,输出,都能统一在线性空间中,那么结果是最真实的,玩家会说这个游戏画质很强很真实。事实上因为计算这一步已经是在线性空间描述的了,所以只要保证输入输出是在线性空间就行了。

所以为什么你的游戏画面不真实呢?因为你可能对此混乱了,你的输入或输出在Gamma Space,又没搞清楚每个纹理应该在什么Space,甚至也不知道有没用伽马校正,渲染结果怎么会真实呢?

现在假设我们的目标是获得最真实的渲染,因此需要统一渲染过程在线性空间,怎么做呢?

:统一在Linear空间是最真实的,但不代表不统一就是错的。一般来说,如果是画质要求高的作品(如3A)等,那么都是统一的。没这方面要求的则未必是统一的,还有一些项目追求非真实的渲染,它们也未必需要统一。

统一到线性空间的过程是看起来是这样的,用图中橙色的框表示(现在看不懂图没关系,跟着后面的步骤来一步步看):

我们从橙色框的左上角出发。

第一步,输入的纹理如果是sRGB(Gamma0.45),那我们要进行一个操作转换到线性空间。这个操作叫做Remove Gamma Correction,在数学上是一个2.2的幂运算 [图片上传失败...(image-a65d6-1597999949775)]

。如果输入不是sRGB,而是已经在线性空间的纹理了呢?那就可以跳过Remove Gamma Correction了。

:美术输出资源时都是在sRGB空间的,但Normal Map等其他电脑计算出来的纹理则一般在线性空间,即Linear Texture。详见后文!

第二步,现在输入已经在线性空间了,那么进行Shader中光照、插值等计算后就是比较真实的结果了(上文解释了哦~),如果不对sRGB进行Remove Gamma Correction直接就进入Shader计算,那算出来的就会不自然,就像前面那两张球的光照结果一样。

第三步,Shader计算完成后,需要进行Gamma Correction,从线性空间变换到Gamma0.45空间,在数学上是一个约为0.45的幂运算 [图片上传失败...(image-1dffca-1597999949775)]

。如果不进行Gamma Correction输出会怎么样?那显示器就会将颜色从线性空间转换到Gamma2.2空间,接着再被你看到,结果会更暗。

第四步,经过了前面的Gamma Correction,显示器输出在了线性空间,这就和人眼看物理世界的过程是一样的了!

我们再举个例子,我们取sRGB纹理里面的一个像素,假设其值为0.73。那么在统一线性空间的过程中,它的值是怎么变化的?

第一步,0.73(上曲线) * [Remove Gamma Correction] = 0.5(直线)。


第二步,0.5(直线) * [Shader] = 0.5(直线)(假设我们的Shader啥也不干保持颜色不变)

第三步,0.5(直线) * [Gamma Correction] = 0.73(上曲线)。


第四步,0.73(上曲线) * [显示器] = 0.5(直线)。


如果不进行Gamma Correction,就会变暗,因为第三步不存在了,第四步就会变成:

0.5(直线) * [显示器] = 0.218(下曲线)。


再对照上面的图琢磨琢磨?

Unity中的Color Space

我们回到Unity,在ProjectSetting中,你可以选择Gamma 或 Linear作为Color Space:

Unity PlayerSettings中的颜色空间选择

这两者有什么区别呢?

如果选择了Gamma,那Unity不会对输入和输出做任何处理,换句话说,Remove Gamma Correction 、Gamma Correction都不会发生,除非你自己手动实现。

如果选了Linear,那么就是上文提到的统一线性空间的流程了。对于sRGB纹理,Unity在进行纹理采样之前会自动进行Remove Gamma Correction,对于Linear纹理则没有这一步。而在输出前,Unity会自动进行Gamma Correction再让显示器输出。

怎么告诉Unity纹理是sRGB还是Linear呢?对于特定用途的纹理,你可以直接设置他们所属的类型:如Normal Map、Light Map等都是Linear,设置好类型Unity自己会处理他们。

贴图导入设置

还有一些纹理不是上面的任何类型,但又已经在线性空间了(比如说Mask纹理、噪声图),那你需要取消sRGB这个选项让它跳过Remove Gamma Correction过程:

到底什么纹理应该是sRGB,什么是Linear?

关于这一点,我个人有一个理解:所有需要人眼参与被创作出来的纹理,都应是sRGB(如美术画出来的图)。所有通过计算机计算出来的纹理(如噪声,Mask,LightMap)都应是Linear。

这很好解释,人眼看东西才需要考虑显示特性和校正的问题。而对计算机来说不需要,在计算机看来只是普通数据,自然直接选择Linear是最好的。

除了纹理外,在Linear Space下,Shaderlab中的颜色输入也会被认为是sRGB颜色,会自动进行Gamma Correction Removed。

有时候你可能需要想让一个Float变量也进行Gamma Correction Removed,那么就需要在ShaderLab中使用[Gamma]前缀:

[Gamma]_Metallic("Metallic",Range(0,1))=0

如上面的代码,来自官方的Standard Shader源代码,其中的_Metallic这一项就带了[Gamma]前缀,表示在Lienar Space下Unity要将其认为在sRGB空间,进行Gamma Correction Removed。

扩展:为什么官方源代码中_Metallic项需要加[Gamma]?这和底层的光照计算中考虑能量守恒的部分有关,Metallic代表了物体的“金属度”,如果值越大则反射(高光)越强,漫反射会越弱。在实际的计算中,这个强弱的计算和Color Space有关,所以需要加上[Gamma]项。

虽然Linear是最真实的,但是Gamma毕竟少了中间处理,渲染开销会更低,效率会更高。上文也说过不真实不代表是错的毕竟图形学第一定律:如果它看上去是对的,那么它就是对的

:在Android上,Linear只在OpenGL ES 3.0和Android 4.3以上支持,iOS则只有Metal才支持。

在早期移动端上不支持Linear Space流程,所以需要考虑更多。不过随着现在手机游戏的发展,越来越多追求真实的项目出现,很多项目都选择直接在Linear Space下工作。

一旦确定好Color Space,那么就需要渲染工程师、技术美术和美术商量和统一好工作流了。在中小团队或项目中,这些概念很容易被忽略,导致工作流混乱,渲染效果不尽人意。现在你懂了吗?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342