前言

不要问我为什么拖更,写博客重要还是陪女朋友玩《双人成行》重要?

今天开始挖一个新坑,各种cg软件中线性工作流程的使用方式,先说一下原理以及3ds Max中的使用。

 

Gamma校正

要说明白线性工作流程,首先要了解Gamma的原理。

网上关于Gamma校正的文章已经汗牛充栋,这里因为要说cg行业中的线性工作流程,Gamma校正也就顺带说一下。

首先来说Gamma是什么,简单来说,Gamma是一个现实亮度与人眼视觉亮度的映射关系。

人的眼睛是一个复杂而精密的构造,但并不足够的精确,对低亮度的变化比高亮度的变化更敏感(也许是为了在黑夜中躲避危险而进化的,耳朵等其他感官也有类似的现象)。例如在完全封闭的房间中点燃1根蜡烛和2根蜡烛,人会感受到很明显的变化;而点燃99根蜡烛和100根蜡烛,感受就很不明显了。

例如下面的图片,显然上面的人眼看起来更加符合均匀渐变,但实际上下面的才是物理数值上的均匀渐变。

换句话说,当亮度的增加从物理上是线性递增时,而亮度的递增给人眼的感受却是非线性递增的。

这里先做一下区分,亮度的物理数值还称为亮度,而人眼感受的视觉亮度以下通称为明度。

如果要在物理亮度的0和100中取到一个视觉明度的中间色的话,这个值会在22左右,也就是说自然界中的22%物理亮度给人的感受是50%的视觉明度。而反过来50%的物理亮度给人的感受则是73%左右的视觉明度,如下图所示。

根据物理亮度和视觉明度的对应关系,最终会得到下面的亮度曲线,称为Gamma曲线。

用一个函数来表示这个Gamma曲线,为 y=xⁿ  n∈[0, 1],也就是值域为[0,1],指数n为1/2.2的幂函数。

之所以值域为[0, 1]是因为通常情况下,计算机都是用0到1之间的浮点数来表示色彩亮度的,比如[0.5, 0.5, 0.5]代表的就是中灰度。

在计算机数字图像领域,目前应用最广的sRGB24位色彩模式下,RGB三个通道每通道为8位色深,也就是0~255共256个亮度等级(也就是色阶),取值范围是[0, 1]。

在亮度等级有限的情况下,如果按照物理亮度来存储颜色的亮度值的话,那么由于视觉明度的中灰度位于物理亮度的22%左右的位置,也就是只有22%的亮度等级用于存储人眼视觉的黑色到中灰色的颜色,而78%的亮度等级用于存储人眼视觉的中灰色到白色的颜色。

换句话说就是人眼会感觉暗部精度不足过渡比较粗糙而亮部精度过剩过渡很均匀。

而如果要按照视觉明度来存储颜色的亮度值的话,就需要按照这个Gamma曲线把物理亮度转换成视觉明度,再将视觉明度分成256个亮度等级进行存储。

从前面的Gamma曲线上可以看出来,如果在视觉明度上均匀取值,则物理亮度低亮度的取值会更密集,高亮度的取值会更稀疏;而如果将Gamma曲线和PhotoShop中的曲线工具进行比较就会明白,Gamma曲线实际就是对灰色区域整体的提亮,以损失亮部细节为代价保留了更多的暗部细节。

这就是所谓的Gamma校正,Gamma校正的实质就是视觉亮度和物理亮度的转化关系,达到不增加图片数据量的前提下提高可辨识精度的目的。

而当Gamma曲线的指数为1时,Gamma曲线就成了直线,实际就是按照物理亮度来存储颜色,此时就是Gamma1.0或者说线性空间。

而在计算机数字图像领域的每通道32位浮点式色彩模式(例如exr、hdr等线性图片格式)下,每通道有数亿级别的色阶,精度已经足够满足人眼的感知,因此大多数专业软件默认不对32位浮点式图片进行Gamma2.2校正,将其视为线性空间,只不过代价就是占用更多存储和计算能力。

 

线性工作流程

如上面所说,绝大多数网上的图片文件,都是sRGB的色彩空间,色深为8位,保存的内容也是被Gamma2.2曲线校正过的非线性颜色。

而计算机图形学中的算法普遍需要输入值是线性的——处于线性空间,而读入的图像却都是gamma矫正过的非线性——处于 Gamma2.2 空间,最终得到的计算结果自然也是不正确的。

当然cg领域中往往可以通过艺术家们的人为修改来得到符合期望的图像,但从数学上来说,这就是错误的。

直到前几年兴起的 Physically Based Rendering(PBR基于物理的渲染)特别强调贴图材质灯光的统一性和物理真实的渲染效果,自然不能容忍在整个系统的底层存在不正确的 Gamma 矫正导致的色彩差异问题,由此产生了线性工作流程,也就是所谓的 Linear Work Flow,或者说Gamma Corrected Pipeline。

下图是传统流程下和线性工作流程下的输出差异,线性工作流程下的光影更加真实,死黑和过曝的现象会改善很多。

所谓的线性工作流程,简单来说就是保证每次进行图形学计算前都将读入图片的亮度统一为线性空间,输出图片最好也为线性空间并设置为16位甚至32位的色深,方便后期进行调色。只有在需要显示的时候才进行gamma2.2校正。

而对于这一流程,不同的cg软件中的具体操作也不同,下面简单介绍一下3ds Max中的线性工作流程。

 

3ds Max中的线性工作流程

在3ds Max中加载贴图文件时,可以在选择贴图的窗口设置Gamma值。

默认情况下是自动模式,如果某些格式的位图文件元数据中包含内嵌的 Gamma 值,则 3ds Max 将使用该Gamma值。否则,将根据文件格式的位深度应用 Gamma 值:8 位和 16 位文件格式应用 2.2,浮点或对数文件格式应用 1.0。

但是对于凹凸贴图、法线贴图、置换贴图等图片素材来说,图片中保存的是数据信息而不是颜色信息,这种情况下不能使用Gamma校正,需要开启覆盖并设置Gamma值为1.0。

而在保存位图文件时,3ds Max 默认也会自动选择Gamma 值,8 位和 16 位格式使用 Gamma 值 2.2,浮点或对数格式使用 1.0,同样也可以根据自己需求进行修改。

如果要修改这两个Gamma默认值的话,3ds Max2014版本以前可以点击菜单自定义-首选项,打开首选项设置窗口,Gamma和LUT一栏中设置位图文件的输入和输出的默认Gamma值。

从3ds Max2014版本开始,首选项设置窗口里的这两个Gamma默认值被去除,如果需要调整可以通过以下MaxScript命令进行修改。

fileInGamma = 1.0     --设置默认输入Gamma
fileOutGamma = 1.0    --设置默认输出Gamma

这个Gamma默认设置会保存在3ds Max本地设置以及max工程文件中,因此当开启max工程时如果软件设置和工程设置的Gamma值不一致,就会出现下面这样的提示窗口,此时选择适合的Gamma设置即可。

需要说明如果修改了fileOutGamma,会影响保存出图文件窗口的自动(推荐)模式,例如fileOutGamma修改为1.0,则保存出图文件时无论图片是什么格式和精度都会以1.0模式保存。

上图是2014以后版本的Gamma设置窗口,里面的其他几个Gamma相关的设置也顺便介绍一下。

启用Gamma/LUT 校正的复选框必须勾选,下面的Gamma设置才会生效。

左侧的Gamma参数则控制在3ds Max中视图预览和渲染窗口中图片的Gamma值,修改这个值只影响预览效果,不影响输入贴图,正常情况下也不会影响输出文件,除非保存的是预览和渲染窗口中的结果。

因此为了保证预览效果和输出效果一致,需要让输出Gamma和显示Gamma的参数相同,如果预览和出图亮度有差异,可以检查这两个参数,改成相同的数值。

如果需要通过MaxScript脚本修改这两个参数可以这样使用。

IDisplayGamma.colorCorrectionMode = #gamma      --开启Gamma控制
IDisplayGamma.gamma = 2.2                       --设置预览Gamma

如果要查看贴图的Gamma值,则可以使用以下MaxScript脚本。

bitmapTexs = getClassInstances BitmapTexture
for bm in bitmapTexs do(
    print bm.bitmap.inputGamma
)

 

Vray中的Gamma设置

提到3ds Max就不能少了VRay渲染器,VRay的渲染设置中也有Gamma的参数,位于Color Mapping栏。

下面的Mode默认为Color mapping only (no gamma) ,此时输出图片时只使用3ds Max的输出Gamma进行一次校正;当Mode设置为Color mapping and gamma时,输出图片时会使用3ds Max自身的输出Gamma叠加上VRay的Gamma进行两次校正;当Mode设置为None (don’t apply anything)时,输出图片时不进行Gamma校正,但会继续计算得到一个线性的结果,最后得到的效果和Color mapping only (no gamma) 模式比较接近,这个模式已经不适合线性工作流程使用了。

 


在一个安静的位置上,
去看世界的热闹。

——周国平