摄影机和曝光效果

色调映射

渲染物理灯光级别时会遇到实际物理的 HDRI 输出的管理问题,同时显示计算机的有限动态范围。Gamma 页面对这些内容进行了详细介绍。

从这里开始...
从这里开始...
...到这里。
...到这里。

有多个着色器和算法可进行“色调映射”(这是 CG 行业中非常热门的研究领域),并提供两种架构库:一种是非常简单的着色器,只需采用膝状曲线弯曲压缩将过亮“挤压”到可管理的范围内即可;另一种是更为复杂的“摄影”版本着色器,采用基于法线摄影机的参数将实际光度亮度转化为图像。

这些着色器可以作为镜头着色器(在渲染的过程中对图像进行色调映射)或输出着色器(在后期处理过程中对图像进行色调映射)。

鉴于这些色调映射器会分别影响每个像素1,鼓励使用前一种方法(作为镜头着色器),因为其适用于采样级别,而不适用于像素级别。

而且,所提供的色调映射器均包含 Gamma 项。需要了解是否已经在图像制作流程的其他位置应用了 Gamma 校正(在图像查看器中、在合成中等),这很重要,如果进行了相应操作,请在这些着色器中将其值设置为 1.0。如果任何位置都没有应用 Gamma 校正,只是使用查看器直接在屏幕上显示图像,而不应用自身的 Gamma,应尽可能在这些着色器中使用 Gamma,将值设置为一个介于 1.8 至 2.4 之间的值。

“简单”色调映射器

mia_exposure_simple

declare shader  "mia_exposure_simple" (
        scalar  "pedestal"       default 0.0,
        scalar  "gain"           default 1.0,
        scalar  "knee"           default 0.5,
        scalar  "compression"    default 2.0,
        scalar  "gamma"          default 2.2,
        color   texture "preview",
        boolean "use_preview"
    )
    version 1
    apply lens, output
end declare 

此色调映射器的运算非常简单。不用以任何方式引用实际物理亮度值。只应用高动态范围颜色并按顺序执行下列运算:

这就是相应的原理。这些参数的实际应用为何?

更改 pedestal 等于调整“黑色级别”。正值会添加一些灯光,因此即使是最黑的黑色也会略微变灰一点。而负值会减去一些灯光,并可“破坏黑色”以达到反差性更强的艺术效果。

gain 是“亮度旋钮”。主要目的是将高动态范围值转化为低动态范围值。例如:如果知道颜色强度的大致范围(介于 0 和 10 之间),该值应大约是 0.1,将此范围限制到所需的 0 到 1 之间。

然而,色调映射的整个目的不是盲目地线性缩小该范围。仅将其值设置为 0.1 很可能会产生黑暗且单调的图像。极有可能的值为 0.15,或是 0.2。但值 0.2 会将 0 到 10 的范围映射为 0 到 2。如何处理 1.0 以上的值?

这就是进行压缩的目的。膝部级别是开始“挤压”过亮的点。由于该操作是在增益应用的,该值的范围应该在 0.0 到 1.0 之间。较好的实用范围是 0.5 到 0.75。

假设我们将其设置为 0.75。这意味着值高于 0.75 的任何颜色(与 pedestal 相加并与 gain 相乘后)将会被“压缩”。如果 compression 为 0.0,表示不进行压缩。compression 值为 5.0 时挤压的程度相当高。

最后,会针对输出设备(计算机屏幕等)对生成的“挤压”颜色进行 Gamma 校正。

use_previewpreview 参数用于使调整色调映射器的过程稍具“交互式”。

当着色器用作镜头着色器时,设定的用途如下所述:

“摄影”色调映射器

mia_exposure_photographic

摄影色调映射器应用与摄影机相关的参数(类似光圈系数和快门时间)进行爆光和应用模拟类似于电影和像摄影机效果的色调映射,将实际像素的亮度(以烛光每平方米为单位)转化为与通过摄影机看到的效果一样的图像像素。

该映射器有两种基本模式:

如果 film_iso 参数为非零,则使用“摄影”模式,如果为零,则选用“任意”模式。

declare shader "mia_exposure_photographic" (
        scalar "cm2_factor"         default 1.0,
        color  "whitepoint"         default 1 1 1,
        scalar "film_iso"           default 100,
        scalar "camera_shutter"     default 100.0,
        scalar "f_number"           default 16.0,
        scalar "vignetting"         default  1.0,
        scalar "burn_highlights"    default 0.0,
        scalar "crush_blacks"       default 0.25,
        scalar "saturation"         default 1.0,
        scalar "gamma"              default 2.2,
        integer "side_channel_mode" default 0,
        string  "side_channel",
        color   texture "preview",
        boolean "use_preview"
    )
    version 4
    apply lens, output
end declare

在“摄影”模式(非零 film_iso)中,cm2_factor 是像素值和烛光每平方米之间的转化因子。以下内容将对此进行更详细说明。

在“任意”模式中,cm2_factor 只是用于将渲染的像素值缩放为屏幕像素的倍增。这类似于 mia_exposure_simplegain 参数。

whitepoint 是指在输出中将映射到“白色”的颜色,即该色调/饱和度的传入颜色将被映射为灰度,但其强度将保持不变。

film_iso 应为胶片的 ISO 数值,也称为“胶片速度”。如上所述,如果此值为零,将启用“任意”模式,并且所有的颜色缩放都将由 cm2_factor 的值来严格定义。

camera_shutter 是摄影机快门时间(以分数秒表示,即值 100 表示摄影机快门 1/100)。在“任意”模式下,此值不会产生任何影响。

f_number 是指分数光圈数,即 11 表示光圈 f/11。摄影机的光圈数是特定的标准系列,即 f/8、f/11、f/16、f/22 等。每一个系列均称为一个“档”,实际上,真实镜头中的光圈环往往可以通过物理的“调整钮”取得这些值,每个这样的“档”表示增加每一档时照射到胶片的光量减半2。请务必注意,此着色器并不对“档”进行计数,但实际上是需要该档的光圈数。在“任意”模式下,此值不会产生任何影响。

在实际的摄影机中,光照射胶片的角度会影响曝光,会使图像的边缘变暗。vignetting 参数可模拟这一操作。当值为 0.0 时,该选项处于禁用状态,而值越大边缘越暗。请注意,此效果取决于光线照射胶片平面的角度的余弦,因此受到摄影机的视野的影响,但对正交渲染,一点儿也不起作用。理想的默认值为 3.0,类似于小型摄像机生成的效果3

参数 burn_highlightscrush_blacks 会引导图像的实际“色调映射”,即如何精确地将高动态范围图像进行调整以适合显示设备黑到白的范围。

如果 burn_highlights 为 1,crush_blacks 为零,转换就会是线性的。即该着色器,其行为就像一个简单的线性强度缩放器。

burn_highlights 可以视为定义“过度曝光”程度的参数。当该值从 1 减少到 0,越来越多的高强度将会被“压缩”成较低的强度。当值为 0 时,压缩曲线呈渐近式,即无限输入值会映射到白色输出值,也就是不再会发生过度爆光。理想的默认值是 0.5。

当动态范围的上半部分经过压缩时,自然会丢失某些以前的对比度,并且通常需要使用 crush_blacks 参数来恢复图像中的某些“孔”。但在柔和的方式下,如果该值为 0,较低的强度范围是线性的,但是当增加到接近 1 时,会将强大的“坡脚”区域添加到转换曲线,以促使低强度更加接近黑色。

压缩亮颜色分量会自动将它们指向不太饱和的颜色。有时,太强的压缩会使图像处于不可满足的不饱和状态。saturation 参数允许对最终图像的饱和度进行艺术控制。1.0 是标准的“未修改的”的饱和度,高于此值会增加饱和度,低于此值会降低饱和度。

gamma 参数用于应用显示 Gamma 校正。请注意,不要在图像制作流程中应用两次 Gamma。Gamma 页面对这些内容进行了详细介绍。

side_channelside_channel_mode 旨在用于着色器的 OEM 集成以支持“交互式”调整,以及在转化前要插入输出着色器以“显示像素的值”。

以上操作是通过应用两种着色器实现的,一种是镜头着色器,另一种是输出着色器。这两个着色器是通过“侧通道”通信的,该通道是一个单独的浮点帧缓冲区,需要在渲染前对其进行设置。

side_channel_mode 的有效值包括:

有人可能想知道,如果将色调映射用作后期处理,为什么不完全跳过应用镜头着色器?答案有两个:第一,应用镜头着色器(即使从不使用其输出),可以在渲染时进行查看,这通常是很有用的。第二,在主帧缓冲区,mental ray 过采样是由像素引导。如果这些都保留在完整的动态范围中,mental ray 可能会不必要地对“高对比度”区域中数千个额外的采样进行反射,而这些采样都会在最后阶段被色调映射为白色。

use_previewpreview 的工作方式与以上描述的 mia_exposure_simple 着色器完全一样。

示例

我们看一下调整摄影色调映射器的实例。这里有一个场景,同时显示了室内和室外的区域,在窗口使用太阳和天空、mia_material 和入口光。设置了单位,以便原始像素以烛光每平方米为单位。

原始渲染,没有使用色调映射,效果如下:

无色调映射
无色调映射

这是 Gamma=1 的非色调映射图像的典型外观。明亮的区域看上去非常不和谐,阴影部分过于刺眼且明显太暗,而且颜色过饱和。

使用以下设置并应用 mia_exposure_photographic

    "cm2_factor"         1.0,
    "whitepoint"         1 1 1,
    "film_iso"           100,
    "camera_shutter"     100.0,
    "f_number"           16.0,
    "vignetting"         0.0,
    "burn_highlights"    1.0,
    "crush_blacks"       0.0,
    "saturation"         1.0,
    "gamma"              2.2,

相应的结果图像如下所示4

“阳光 16”结果
“阳光 16”结果

我们所作的设置是遵循摄影中的“阳光 16”法则;将光圈设为 f/16,快门速度(以分数秒为单位)等于胶片速度(作为 ISO 数值),产生了室外阳光场景的“理想”曝光。我们可以看到,确实室外区域看起来很好,但室内区域明显曝光不足。

在摄影中,“胶片速度”(ISO 值)、光圈 (f_number) 和快门时间相互定义摄影机的实际曝光。因此,若要修改曝光,修改其中任一项就可得到相同的结果。例如,若要将图像亮度减半,我们可以将快门时间减半、胶片 ISO 减半或更改光圈一档(例如,从 f/16 更改到 f/22,有关详细信息,请参见页面光圈系数)。

在现实世界摄影机中,这些不同的方法会有细微的差别,但是对于此着色器,从数学角度来说,它们是相同的。

f/8
f/8
f/4
f/4

显然 f/4 图像是室内部分的最佳选择,但是,现在室外区域曝光极其过度。这是因为 burn_highlights 参数值为 1.0,所以不执行任何高光压缩。

<b>burn_highlights</b> = 0.5
burn_highlights = 0.5
<b>burn_highlights</b> = 0.0
burn_highlights = 0.0

左侧图像的过度曝光减弱了一些。右侧图像的 burn_highlights 值为零,实际上,已完全移除了任何过渡曝光。但是,此操作有一个缺点,就是会抹杀图像中的大量对比度,而实际胶片确实会对过亮执行压缩,无胶片存在魔法般地移除了过度曝光。因此,建议将 burn_highlights 的值设置得小一些,但是为非零值。在我们的示例中,选取的值为 0.5。

实际摄影机图像的边缘附近会有衰减,称为“渐晕”,此着色器支持这一选项,但要使用相同名称的参数:

<b>vignetting</b> = 5
vignetting = 5
<b>vignetting</b> = 11
vignetting = 11

右侧的图像很有趣,“帮助”我们对户外的区域过度曝光,恰好在图像的边缘,因此受到了渐晕的衰减。但是,左边缘太暗了。

我们将尝试中间版,使用 vignetting 值 6,并将 burn_highlights 的值修改为 0.25,得到的图像效果如下:

<b>vignetting</b> = 6 <b>burn_highlights</b> = 0.25
vignetting = 6 burn_highlights = 0.25

图像看起来很好,但是的确缺少“对比度”的感觉。为了加强对比度,我们使用 crush_shadows 参数:

<b>crush_shadows</b> = 0.2
crush_shadows = 0.2
<b>crush_shadows</b> = 0.6
crush_shadows = 0.6

crush_shadows 参数加深了较低端的强度曲线,现在的对比度非常好。然而,由于此图像已接近“太黑”,光谱的末端,皆在显示使整个图像变黑一点的效果。

这可以通过更改曝光来修正。我们来尝试几个不同的 shutter 值,并防止通过进一步降低 burn_highlights 值对图像进行过度曝光:

<b>shutter</b> = 50, <b>burn_highlights</b> = 0.1
shutter = 50, burn_highlights = 0.1
<b>shutter</b> = 30, <b>burn_highlights</b> = 0.1
shutter = 30, burn_highlights = 0.1

最终得到的图像十分理想。但是,由于运行了太多的高光压缩,现在丢失了大量的颜色饱和度。让我们通过以下补偿来完成该操作:

<b>saturation</b> = 1.0
saturation = 1.0
<b>saturation</b> = 1.4
saturation = 1.4

现在,我们已经找回了一些颜色,图像非常和谐。我们仍然可以看到室外有景物。这可能是我们可以执行的最好的方法:仍进行物理校正

但是,请记住,我们对窗口使用了入口光?这些具有非物理的“透明度”模式。此模式可以精确地解决此问题。虽然,我们目前得到结果是“正确”的,但是许多人直觉上希望能更清楚地看到室外场景。由于我们的眼睛对阳光照射的室外和较暗的室内动态范围之间的巨大差异所做的修正意义非凡,我们希望我们的计算机可魔法般地执行相同的操作。使用入口光的透明度特性,从视觉上可实现该操作,并不用实际上更改进入房间的任何灯光的实际强度:

入口光的 <b>transparency</b> 值为 0.5
入口光的 transparency 值为 0.5

现在,可以看到室外对象了,同时也保留了室内的对比度。室内灯光级别没有发生变化,并且仍遵循真实世界的值(并不像我们已将实际的黑色玻璃放置到窗口,这样也可以衰减入射光)。

现在,是正午时分的场景。如果我们更改当日时间和把太阳放置到低于地平线的位置会出现什么效果?该场景将更暗,我们可以通过更改曝光来修正:

7 PM
7 PM
快门速度 1/2 秒
快门速度 1/2 秒

使用相同的设置(左侧),设置新的日光角度使图像变暗。在右侧,我们所做的一切就是将快门时间更改为 2(1/2 秒)。此图像有一点黄色的投影,由于微红的太阳光,以及淡黄的白炽灯照明。为了修正这点,我们将白点改为淡黄色的颜色:

调整白点后的夜间拍摄
调整白点后的夜间拍摄

余下的问题是台灯的过度曝光(尽管实际摄影中确实存在过度曝光),所以我们将最终图像的 burn_highlights 值设置得非常低,但要使用非零值,以保持稍微“冲压”:

<b>burn_highlights</b> = 0.01
burn_highlights = 0.01

总结:与摄影相关的参数可帮助用户通过摄影经验对合适的值进行良好的判断。直观的“外观”参数可以对图像进行进一步调整,以达到令人满意的可视效果。

景深/散景

“散景”是日语术语,表示“模糊”的意思,通常用于表示摄影中焦距区域外的景色。术语“景深”(以下缩写为 DOF)在实际情况中不会描述模糊本身,但特别关注区域的“深度”。然而,提及模糊本身时,通常会谈到“DOF”。

此着色器非常类似于物理库中的 physical_lens_dof,就是对实际外观和模糊的质量有更多的控制。

declare shader "mia_lens_bokeh" (
        boolean "on"          default on,
        scalar  "plane"       default 100.0,
        scalar  "radius"      default 1.0,
        integer "samples"     default 4,
        scalar  "bias"        default 1.0,
        integer "blade_count" default 0,
        scalar  "blade_angle" default 0,
        boolean "use_bokeh"   default off,
        color texture "bokeh"
    )
    version 4
    apply lens
    scanline off
end declare

on 表示启用着色器。

plane 指从摄影机到距焦平面的距离,即摄影机在距离该点处完全聚焦。

靠近摄影机的焦点
靠近摄影机的焦点
远离摄影机的焦点
远离摄影机的焦点

radius 是指模糊半径。这是以场景单位表示的实际测量,对于实际的摄影机来说,是光圈的大约半径,即取决于摄影机的光圈系数。对于大小(以前场景单位表示)保持类似于几厘米来说,这是一个很好的经验法则,否则场景可能会失真和会被视为一个小型的摄影机5

小半径 - 深 DOF
小半径 - 深 DOF
大半径 - 浅 DOF
大半径 - 浅 DOF

samples 定义投射的光线数量。光线越少,速度越快,但颗粒性更强;光线越多,速度较慢,但更平滑:

几个采样
几个采样
多个采样
多个采样

bias 为 1.0 时,会将模糊圈作为均匀圆盘进行采样。较低的值可能会将采样推向中心,创建带有多个“雾色”效果的“较柔和” DOF 效果。较高的值可能会将采样推向边缘,创建“较硬”的 DOF 效果,其中,亮点实际解析为小圆圈。

bias = 0.5
bias = 0.5
bias = 2.0
bias = 2.0

blade_count 定义模糊“圈”有多少个“边”。值为零时,是一个完美的圆。我们也可以使用 blade_angle 参数设置角度,其中 0.0 表示 0 度,1.0 表示 360 度。

blade_count=6, angle=0.0, bias=2.0
blade_count=6, angle=0.0, bias=2.0
blade_count=4, angle=0.1, bias=2.0
blade_count=4, angle=0.1, bias=2.0

use_bokeh 参数可启用用户的特定散景映射。使用此参数后,参数 biasblade_countblade_angle 不会有任何效果。映射定义 DOF 过滤器内核的形状,因此黑色背景中填充白色的圆等同于标准的模糊。通常,我们需要更多的采样来精确地“解析”自定义散景映射,而不是具有最佳采样分布的内置散景形状。

十字形散景映射
十字形散景映射
添加颜色后的色度色差映射
添加颜色后的色度色差映射

bias 值为 1.0、samples 值为 4、blade_count 值为 0 和 use_bokeh 值为 off 时,此着色器将与旧 physical_lens_dof 着色器渲染相同的图像。


脚注
1
许多高级色调映射器会根据其他区域设置图像的不同区域的权重,以便模仿人类视觉系统的运行。这些色调映射器在“执行作业”前需要整个图像。
2
有时会发现光圈数标记为光圈系数。由于这样表示不太明确,为了明确起见,我们选择了术语光圈数
3
从技术上讲,像素强度乘以胶片平面的光线角度的余弦做为 vignetting 参数的幂。
4
有关尝试设置色调映射着色器的速度结果,请参见使用预览页面描述的使用“preview”参数的工作流。
5
光圈的直径是镜头的焦距(以场景单位表示)除以光圈数。因为此参数为半径(不是直径),是直径的一半,即 (focal_length/f_number)/2。