Gamma在CG制作Linear Work Flow中的重要性

首先,物质世界的颜色是无穷连续变化的,是一个线性量,但人的眼睛对亮度的感觉却并非呈线性分布,而是呈指数分布的。人眼只是对亮度的比率敏感,而并非对亮度本身敏感,我们观察到的亮度从0.10到0.11之间的差别与0.50到0.55之间的差别是一样的。这种非线性在日常生活中很容易感觉,比如你把灯泡功率从20W调到80W再调到140W,你会发现20W到80W之间亮度的增加比后一次调节来得更大。所以,当真实世界中线性无穷的颜色量到达人眼时,它们实际上被人眼感觉的非线性做了一次“校正”,只是这种“校正”从某种意义上说是错误的背离真实的,但我们自身无法避免,这是人类眼睛的特质,没有办法,所以我们只能对源色彩向相反的方向进行指数校正(也就是让颜色不呈线性分布,而呈指数分布),来让我们觉得亮度分布均匀。
设想一下,当我们开始用电脑制作某CG内容时,我们首先是通过电脑显示器来与应用程序之间发生交互和信息交换的,如果显示器本身不能很好的还原数字化内容本身的真实颜色,也不能准确显示标准的颜色,那么这就意味着,只要你开始选择一个颜色,就是错误的。然后接下来不管怎么样都会是错误的。
这样,我们就得明白一个问题,显示器为什么会失真,我们如何校正?
拿CRT显示器来说,显示器的亮度变化是因为其输入电压发生变化,但是由于输入电压的变化函数和亮度的变化关系是不成正比的,这就存在了失真。
说得通俗点就是,当显示器要表现一数字化图像内容时,假如我们这时把这个内容看成是一个线性连续量,这时显示器的电压变化就不能很好的表现这个连续量,就出现了失真。换句话说,我们可以这样理解,显示器在显示那个数字化内容时,做了一个不正确的校正,非常巧合的,这个校正的函数关系也是指数关系。工业上我们一般把显示器的这种错误校正或者说失真度,用一个参数来衡量,那就是Gamma。
如果我们把显示设备要显示的原始数据称之为输入(Input),把原始数据通过显示设备后显示出来的结果称之为(Output),那么它们之间的关系实际就是:
Output=InputGamma
不难发现,这就是一个指数关系,而输出的结果,实际上就是给输入做了一个gamma值大小的指数级映射变化,Gamma,也就是衡量了这个指数变化的程度,当Gamma为1时,也就是Output=Input,因此,如果Gamma值为1就意味着不发生改变,或不校正,不失真,输入和输出相等,而Gamma值越大时,失真也就越大。
事实上,不同的CRT显示器其失真度都不相同,也就是Gamma值都不尽相同,但一般来说都是2.2-2.5这个范围,假如一个显示器的gamma值为2.5,这意味着什么呢,就是一个线性连续图像在显示时会被做一个gamma2.5的错误校正,或一个gamma2.5的失真,线性分布的图像会变成指数分布的图像,可见,显示器的这种错误“校正”使得中性灰在指数关系下变黑了,总体的表现就是暗部增加,图像整体变暗,暗部细节丢失。
那么,知道了错误发生的症结,我们该如何校正这一错误呢?由于显示器的Gamma是显示器的固有特性,我们是无法改变的,所以,思路应该是这样,既然显示器做了一个gamma2.5的改变,而我们需要的是让Gamma保持为1,这样输出结果就是无失真的,那么我们只要再显示器输出过程之前多做一次Gamma校正,让最终的Gamma值为1就可以了。也就是:
Display_Gamma=CRT Gamma * 校正Gamma=1
以CRT Gamma为2.5为例,那就是要做一个Gamma0.4的校正,这样
Display_Gamma=2.5*0.4=1
在计算机系统中,在显示器之前做的这个Gamma校正事实上由显卡完成,但问题在于,上述的例子是我们事先知道显示器CRT_Gamma为2.5的情况下,我们用一个Gamma0.4来做校正,但显卡并不知道我们的显示器实际是什么Gamma值,更坏的情况是,也许做为用户的我们,自己都不知道自己的显示器CRT_Gamma为何值。
操作系统怎么解决这个问题呢?它提供了一个LUT系统(Look UP Table),也就是查色表,当我们知道自己的显示器的CRT_Gamma值后,告诉LUT,现在这台显示器的Gamma值为多少,LUT得知后,调用对应的Gamma校正函数,用合适的Gamma值来控制显卡输出校正后的电频信息给显示器,所以,我们也把这个校正Gamma数值称之为LUT_Gamma。又由于这是系统内部做的校正,我们又称它为系统Gamma(System_Gamma)。
但问题还没得到完全解决,那就是,如果我不知道自己的显示器CRT_Gamma值呢?事实上,这才是问题的关键。
当我们用一部数码单反相机拍下一张自然风景照片,并且存储为RAW格式的图像文件时,问题还不是很大,因为RAW是浮点格式的高精度存储格式,我们可以认为它近似线性连续地记录下了我们的原始数据,但一旦你将它转换为一些非浮点低精度图像格式,如JPG、BMP、TIFF等格式时,因为这些格式是以整数来记录数据的,这样就造成数据被离散化,不再那么连续,导致失真。
并且,另一个问题是,线性的RAW文件格式中的数据被映射在0-255这样的整数范围时,是否也是线性分布呢?这可不一定,所以在这里引入一个新的概念,编码Gamma,也就是Encode_Gamma,如果系统或软件在写入某文件格式时,将原有的线性数据也按线性映射在整数范围内,那么它的Encode_Gamma就是1,即不改变,这时数据的失真仅仅是因为近似无限连续的线性数据变成了离散化的线性数据。如果写入时将原有的线性数据按指数分布映射在整数范转内时,Encode_Gamma就不为1了,此时Encode_Gamma代表的就是这个指数。反应的就是数据存进文件后有了怎样程度的失真。当然,有写就有读,既然有编码Gamma自然就有解码Gamma,也就是Decode_Gamma,当一个软件打开并读取一个图像文件时,它是否对这个图像数据做变换处理,这个度是好多,就由Decode_Gamma来决定,如果Decode_Gamma为1,就是不改变,不校正,如果不为1,就表示要改变或校正,它的数值决定了做多大程度和什么样的改变。
绝大多数情况下Encode_Gamma和Decode_Gamma都是为1的,比如,默认的操作系统中IE浏览器的Decode_Gamma就为1,ACDsee看图软件在没设置的默认情况下,Decode_Gamma也为1,所以用它们两个去看一张标准的线性图片是会有问题的,因为显示器的CRT_Gamma是2.2-2.5左右,而默认情况下LUT_Gamma为1 ,所以我们实际看到的图像的Gamma也就是CRT_Gamma,是非线性的,这就发生了错误。
而如果你用Adobe photoshop去打开这张图片往往和那两个软件中看到的不一样,并且结果是对的,因为Adobe photoshop默认是进行色彩管理的,就是在软件使用过程中调用了LUT查色表并让LUT_Gamma不为1,所以这时就做了对的校正处理。 事实上,我们不难在应用软件中发现Encode_Gamma和Decode_Gamma 的应用身影,比如在MAX的优先设置面板中,在GAMMA子选项里,有这么一组参数。
这个里面的InputGamma呢,指的是当MAX调入任何一张图片格式时,做什么样的Gamma校正,这个操作显然是读操作,假如InputGamma为2.2,那么当MAX调入一张贴图时,这个贴图就会在调入内存时被事先校正,MAX通过把InputGamma,也就是2.2这个值告诉LUT查色表,查色表接着告诉MAX应该对贴图进行了一个Decode_Gamma为0.4545的校正,这里是很容易产生混淆的一个概念,很多人会以为InputGamma取值为2.2时,是MAX对文件调入内存之前做Gamma2.2的校正,这是错误的,当InputGamma取值为1时,LUT查色表告诉MAX需要对其做Decode_Gamma为1的校正,也就是不校正,不发生改变。反过来,再去理解OutputGamma就和上面的情况类似了,只不过它的校正发生在即将写入文件数据之前,是写入操作时发生的校正,并且通过将OutputGamma值传递给LUT告诉MAX该用什么样的Encode_Gamma作校正。
这时,你可能要问,是不是总是应该保持Encode_Gamma和Decode_Gamma为1 呢,这样反正就保持原样了,岂不省事?这就要具体情况具体分析了。
如果你用单反数码相机拍照存成了RAW文件,并转换成诸如JPG、TIFF、BMP这样的格式,这时,就会有一个问题,因为数码相机感光器的特性,从相机里输出的文件,比如RAW都是做过了一个Gamma0.45校正的,这时,往往在写入文件时编码就应该做一个 Encode_Gamma2.2的校正才能得到正确结果,或是在读文件时做一个Decode_Gamma为2.2的校正才能正确显示或使用这个图像,所以不同的情况是不一样的,如果图像本身是从计算机内部从无到有创建的,那么保持Encode_Gamma和Decode_Gamma为1是一个比较好的作法。
通常,我们把一个文件自身呈现的Gamma特性称之为File_Gamma,如果文件由外界摄取自计算机,那么:
File_Gamma=Device_Gamma * Encode_Gamma
(其中,Device_Gamma是指设备的Gamma,如果是数码单反,通常是0.45)
如果文件由计算机本身凭空创造,那么,就不存在设备,就有:
File_Gamma=Encode_Gamma
然而,为了保证整个工作流程的线性化,所以我们应时时保证文件自身的Gamma为1,也就是File_Gamma为1。
事实上,MAX在打开和存储图像文件时,都具备非常详细的Gamma选项供用户控制,其中
第一个选项Use image’s own gamma,就是使用文件自己的文件Gamma,不对其作任何改变的打开。
第二个选项Use system default gamma,就是说根据先前MAX优先设置面版里的input或output里的Gamma值对文件Gamma相应进行Encode_Gamma或Decode_Gamma的校正。
第三个选项Override,是说用户指定一个Gamma值,对这个图像进行一次这个Override_Gamma值的校正,注意,这次就和上面讲到的优选设置面板里的OutputGamma和InputGamma情况不一样,这次是直接做一个Override_Gamma取值的校正,你给2.2,就做Gamma2.2的校正,结果是图像变暗,给0.45,就做Gamma0.45的校正,结果是图像提亮,它是不会去查什么LUT查色表的,这就是实实在在做校正,要加以区别。
那么,通过这三个选项,我们就能很好地控制素材的文件Gamma,做到调进来的图是否线性化,在线性工作流程下,有一个准则,如果图像文件本身的文件Gamma不为1,那么我们就要通过设置这些参数来让它调入后为1,如果图像文件本身的文件Gamma已经为1,那么我们可以选择第一项来使用文件自己的Gamma设置就可以了,这样,你的图像至始至终都是在线性空间下工作的。这点在整个流程中也至关重要,因为校正是不可以多作的,校正多做了就是错误的结果。如果某张图像文件由数码相机拍摄并转为JPG或其它整数结构格式,这时,它的文件Gamma事实上不为1,前面我提到了,由于摄像机感光器特性,加上默认情况下软件或系统的Encode_Gamma为1,所以文件Gamma就是Camera_Gamma也就是大约0.4545,那么当我们把这个文件调入到MAX里来做贴图时,事实上该文件的数据就是非线性的,因为文件Gamma不为1嘛,我们要让它变成 1,这里我们就可以使用第三个选项,将Override_Gamma设为2.2,这样就对它做了一个Gamma2.2的校正,基本就线性化了。
那么,讲到这里,我想Gamma的概念在我们的脑袋里应该有了不同的定义,在不同的阶段不同的时候Gamma都有其特殊的意义,最后呢,我为这个小节做个总结,列出一些我在文中提到过的概念:
Camera_Gamma 摄像机Gamma,因为摄像机感光器的特性,拍下来的图像相当于会自动进行一次Gamma校正,其值一般约为0.4545
Encode_Gamma 编码Gamma,在文件形成,数据写入时,对数据变换分布所相当于造成的Gamma校正。
Decode_Gamma 解码Gamma,在文件调用至内存时,数据按新的分布方式读出所相当于造成的Gamma校正。
LUT_Gamma 系统Gamma或查色表校正Gamma,作用于显卡层面的帧缓冲,对其进行Gamma校正以适应设备输出。
CRT_Gamma 显示器自身电压特性相当于造成的Gamma校正。不可修正,一般为2.2或2.5。
根据以上概念为基础,我们还加入一些附加概念:
File_Gamma 图像文件相对于要反应的原始数据的Gamma特性,是文件自身的Gamma特性,表征了数据在存储为文件后的改动特性。
如果文件来源于外部设备如摄像机,
File_Gamma=Camera_Gamma * Encode_Gamma
如果文件来源于计算机内部创作
File_Gamma=Encode_Gamma
特殊地,如果文件在写入之前有软件功能上的人为Gamma校正,如Vray帧缓冲的Gamma曲线调节,那么
File_Gamma=Calibration_Gamma * Encode_Gamma(其中Calibration是校正的意思)
Display_Gamma 显示输出Gamma,表征显示设备最终显示的结果相对于要显示数据的改变特性
以CRT显示器为例:Display_Gamma=LUT_Gamma * CRT_Gamma
View_Gamma 全局Gamma,是所有Gamma校正和变换结果的总和,通常用来表征我们最后看到一幅图像的样子时它相对于原始是什么样的改变特性,事实 上,在我们提及的线性化流程里,我们的目标,就是要让View_Gamma为1,如果考虑到人眼自身还有一个Gamma特性的变换,我们也可以让View_Gamma最后为1.5。
而View_Gamma=File_Gamma * Display_Gamma
所以我们的线性工作流程,实际上包括两个方面的工作:
第一、 保证每一个用到的文件,其File_Gamma是1
第二、 我们在操作软件之前通过显示设备所看到的图像,本身应该是线性的,即Display_Gamma为1 只要保证了这两点,我们的线性工作流就是成功,和高效的。
第四节 MAX中的线性工作流程
之所以这一节的标题命名为MAX中的线性工作流程,是因为仅仅在MAX中实现线性工作环境这只是一个局部的概念,一个小概念,真正广义的线性工作流程可能要涉及CG制作的全环节,包括我前面讲的从外界引入素材,但是在本节,我们仅仅讨论MAX的情况:
从第三节的总结中,我们已经知道了,我们需要保证Display_Gamma和File_Gamma在MAX这个环节都要为1,File_Gamma保持为1我在第三节中基本已做了较详细的讲述,这里就省去不谈了,主要看看Display_Gamma,由于操作系统在默认情况下,对GUI应用程序界面是不做校正的,任由显示器CRT_Gamma输出,这就导致Display_Gamma不为1,我们可以在MAX中设置,让显卡对MAX中的应用程序界面进行LUT_Gamma校正,这样就能保证我们在在颜色拾取面板和材质面板中选择正确的线性颜色,并且保证正确的中性灰,来看下图:
[转载]VR高级理论---LWF线性工作流(Linear <wbr><wbr>Work <wbr><wbr>Flow <wbr><wbr>)
如图所示,打开MAX优先设置面板中的Gamma子页,勾选使用LUT_Gamma,这里,你可以看到一个Gamma参数,这个参数不是告诉MAX要做多少的Gamma校正,而是告诉MAX,你的显示器的CRT_Gamma值,如果你的显示器Gamma值为2.2,你就输入2.2,为2.5你就输入2.5,这个值最终将告诉LUT查色表来用什么LUT_Gamma来做校正,如果你不确定,或认为自己的显示器没校准得非常好,不用担心,MAX提供了一个简单的校准器,如图中的外框和内框两个灰色区域,你可以边调节Gamma数值,回车确定后眯着眼观察内框灰度和外框是否容合到一起,如果基本能容在一起,那就可以了。接着,非常重要的一步是勾选Affect Color Selectors和Affect Material Editor,这样,LUT_Gamma校正将作用于MAX的拾色器等有帧缓冲的界面,这样你对颜色的选择就比较准确了,然后呢,保持input gamma和output gamma都为1,因为即便我们想对文件的写入读出进行Gamma调整,也可以在写入和打开时单独用选项控制,不必动用这里的宏观控制。
设置完成后,基本就完成了MAX里的线性工作环境设置,但此时要注意,如果你使用MAX自己的帧缓冲渲染输出,那么就不应该再对其进行任何Gamma校正,因为在优先设置面板里你已经开启了LUT_Gamma校正,它对MAX的帧缓冲是起作用的,渲染出来的图是线性的,是校正后的。如果你使用VR的帧缓冲,因为MAX优先设置面板里的LUT_gamma校正对VR的帧缓冲不起作用,所以渲染出的结果,是直接未校正就显示在显示器上的,是不准确的,这时你就需要通过VR的Gamma校正功能来校正。
其实这里之所以要在使用VR的帧缓冲情况下单独再用VR的Gamma校正,是因为MAX的设置对VR是不起作用的,所以对于LUT_Gamma校正我们要多做一次,仅此而已。并且, VR的Gamma校正里的Gamma值和MAX优先设置里的Gamma值意义是一样的,所以为保持一至,因为都是指显示器CRT_Gamma值嘛,所以这两个值应该是一样的。
但是,以上的设置仅仅是解决了渲染结果显示问题,即这些只能做到你渲染的结果是LWF的,但当你保存为文件时,还是没有进行Gamma管理,所以我们应该在文件输出时,指定和显示输出同样的gamma校正,这非常简单,一种是你可以在保存文件时在设置里用overrideGamma来决定存盘时的gamma值,比较简单的方法是设定全局优先面板里的outputgamma就可以了.数值和设定显示的一样.
那么,基本上,按照上述思路和要注意的地方完成设置后,在MAX里就能完全在线性空间下工作了。总结一下就是: 1. 将CRT显示器利用相关工具尽可能校正准确,使亮度分布正确,并测出显示器Gamma值。 2. 始终导入文件Gamma为1的线性图像作为素材,如果不为1,应该在打开时调整Gamma校正使其为1。其实我们可以干脆把所有引入的贴图看成线性的.不需要做什么改动
3. 在MAX的Gamma设置中开启LUT_gamma校正,并填入显示器Gamma参数,保持影响拾色器和材质编辑器两个选项为勾选状态。 4. 显示方面,如果使用MAX自己的帧缓冲不需也不要做任何其它校正,看到的结果就是LWF的
5. 显示方面,如果使用VR的帧缓冲则需要单独用VR色彩映射管理里的Gamma校正再多做一次LUT_gamma校正,其值设置同MAX里设置一样。
6. 输出方面,将系统优先面板里的gamma设置中的outputgamma设为显示校正同样的数值即可,这样保存的文件也是LWF的
当然,以上是CRT显示器的情况,如果你使用的是液晶显示器,由于液晶显示器的固有Gamma为1.0 那么情况会变得更简单一些:
1. 禁用MAX里的LUT_gamma校正
2. 始终导入文件Gamma为1的线性图像作为素材,如果不为1,应该在打开时调整Gamma校正使其为1。
3. 渲染结果始终不进行校正
最后需要说明一点的是,如果在LWF模式下渲染出来的图,导入photoshop进行处理时,应该禁用photoshop的gamma校准,比如AdobeGammaloader,因为此时的文件结果已经是根据显示器校准过的了,导入时不应该再进行一次校准。