目录
- 一、前言
- 二、色彩知识
- 2.1 色彩理论
- 2.1.1 成像原理
- 2.1.2 色彩模型和色彩空间
- 2.1.3 色彩属性
- 2.1.4 直方图
- 2.1.5 色调曲线
- 2.1.6 线性空间与Gamma空间
- 2.1.7 HDR和色调映射
- 2.2 颜色操作
- 2.2.1 基础操作
- 2.2.2 颜色插值
- 2.2.3 颜色混合
- 2.3 常用曲线
- 2.3.1 线性曲线
- 2.3.2 指数曲线
- 2.3.3 三角函数
- 2.3.4 贝塞尔曲线
- 2.3.5 Catmull–Rom曲线
- 2.3.6 其它曲线
- 2.1 色彩理论
- 特别说明
- 参考文献
一、前言
首先申明:这是一篇涵盖技术、美术、审美、摄影等知识的文章,不是纯粹的技术文章!!准确地说是一篇TA向的文章。
可能有些人会好奇,笔者乃一介码夫,为何会涉及摄影、美术、TA的领域。
其实跟个人的兴趣爱好有关。笔者虽当了多年码农,本该潜心钻研技术,奈何禁不住心中对美的追求,玩起了摄影,并且一玩就是好几年,也拍了一些能拿得出手的作品。
作品《余荫阁•秋思》,2019年9月摄于余荫山房,出镜:宝儿
作品《九尾狐仙》,2019年4月摄于鹤之洲,出镜:冰冰
作品《粉色的记忆》,2019年1月摄于中山影视城,出镜:婷婷
作品《超跑与美女》,2019年1月摄于某超跑俱乐部,出镜:血狼
这几年,对摄影艺术有了一定的认知,并且艺术是相通的,摄影艺术跟图形渲染的美术艺术有着千丝万缕的联系。笔者在实际工作中,也会尝试去利用摄影接触的艺术知识引入其中,最直接的体现就是用UE制作PBR材质。久而久之,有了不少心得体会,于是斗胆撰写了此篇文章。
当然,这不是一篇入门教学,要求读者了解UE,接触过PBR材质。比较适合阅读的人群:
- 美术
- TA
- 程序员(对材质底层和艺术感兴趣)
- 摄影师(对游戏引擎、摄影基础感兴趣)
- 其他(对UE材质感兴趣)
如果对UE或UE的材质系统不熟悉,建议直接阅读UE官方文档和材质系统。
二、色彩知识
本章不涉及PBR相关的讲解,先详细地讲解一些前置知识--色彩的原理、理论、操作,为后面PBR的制作奠定基础。毫不夸张地说:只有扎实地掌握了颜色的基础理论和操作,才能更好地制作出真实且美观的PBR材质,进而更好地为产品服务。
2.1 色彩理论
色彩就是颜色,本质是人眼能够感知的可见光。本节将重点介绍色彩相关的知识和理论。
2.1.1 成像原理
光的本质是在可见光频段(波长在380nm~780nm)的单一或复合电磁波。
虽然真实物理世界的光绝大多数是连续的复合光,但人眼能够感知的光波长分别是红(Red,波长为700nm)、绿(Green,波长为546.1nm)、蓝(Blue,波长为438.8nm)的光,其它颜色皆由这三种原色光混合而成。
上图的上部分是自然界存在的连续的自然光,下部分是离散的红、绿、蓝光,刚好跟人类视觉成像原理匹配,所以人类无法发现它们之间的差别。也就是说,人类的视觉是有损的,将无限维度的复合光简化成了三维视觉空间。
人眼见到的颜色不仅取决于光源的颜色,还取决于物体的表面特征,如颜色反射率、粗糙度、导电性、各向异性等等,最直观的是颜色反射率。
一束白光(复合光)照在成熟的苹果表面上,由于苹果表面吸收了除红色以外的光,反射较多红色光,使得其表面呈现红色的特征。
这些物体的表面特征就是PBR材质研究的范畴,也是本文要重点研究和阐述的对象。后续章节将会重点介绍PBR抽象出的属性和特性。
最简单、最直接的光照公式如下:
\[ 人眼感知的物体颜色 = 光源颜色 * 物体表面颜色反射系数 \]
但是以上公式只考虑了光源和物体表面反射系数,实际上,还需要考虑粗糙度、导电性、各向异性、透明度等等因素,可扩展一下,加入\(衰减因子\),以涵盖其它因素对物体表面反射系数的影响:
\[ 人眼感知的物体颜色 = 光源颜色 * (物体表面颜色反射系数 * 衰减因子) \]
其中\(衰减因子\)的计算决定了以上公式是基于物理的还是基于经验值或是其它模式的,也决定了渲染效果的真实可信度。例如,Cook-Torrance就是一种计算高光反射衰减因子的PBR光照模型:
\[ 人眼感知的物体高光颜色 = 光源颜色 * (物体表面颜色反射系数 * 衰减因子_{Cook-Torrance}) \]
2.1.2 色彩模型和色彩空间
色彩模型是用一定规则来描述(排列)颜色的方法。常见的色彩模型有RGB、HSV、HSL、LAB、CYMK等。
然而,色彩模型无法确切地描述颜色的具体信息和含义,例如:RGB 模型用规定红、绿、蓝 3 个分量描述颜色,然而并没有确定红色、绿色、蓝色到底是什么波长亮度多少的光,更无法描述它们能够表达的范围。
这就需要引入色彩空间,以确切地描述色彩模型的具体信息和含义。比如,使用 RGB 色彩模型的 sRGB 色彩空间最大红色的定义就是CIE XYZ: 0.4360657, 0.2224884, 0.013916。其中 CIE XYZ 是一个特殊的色彩空间,根据人眼三刺激值实验测试结果而建立。
一个色彩模型下可以有多个不同的色彩空间,它们根据排列的条件的不同会有不同的色域(所能表示色彩的范围)和含义,色彩模型只有具体到一种色彩空间上才有实用性。例如,RGB色彩模型下有sRGB、Adobe RGB、ProPhoto RGB等色彩空间。
2.1.2.1 CIE 1931 XYZ
CIE 1931 XYZ色彩空间(也叫做CIE 1931色彩空间)是其中一个最先采用数学方式来定义的色彩空间,它由国际照明委员会(CIE)于1931年创立。
CIE XYZ色彩空间是从1920年代后期W. David Wright和John Guild做的一系列实验中得出的。他们的实验结果合并到了CIE RGB色彩空间的规定中,CIE XYZ色彩空间再从它得出。
这种色彩空间是基于RGB三原色测量而成,刚好覆盖所有人类可见的色彩范围(下图)。
2.1.2.2 LAB
Lab色彩空间(Lab color space)是颜色-对立空间,带有维度L表示亮度,a和b表示颜色对立维度,基于了非线性压缩的CIE XYZ色彩空间坐标。
不像RGB和CMYK色彩空间,Lab颜色被设计来接近人类视觉。它致力于感知均匀性,它的L分量密切匹配人类亮度感知。因此可以被用来通过修改a和b分量的输出色阶来做精确的颜色平衡,或使用L分量来调整亮度对比。这些变换在RGB或CMYK中是困难或不可能的——它们建模于物理设备的输出,而不是人类的视觉感知。
对于不同的亮度值L,所呈现的二维图将有较大差异:
2.1.2.3 RGB
RGB色彩模型采用与人眼成像原理相似的R、G、B分量表达颜色,是一种在黑色介质上叠加色彩原色的模型。
RGB呈现的立体色彩三维图如下,是面向设备的一种色彩模型,当今的绝大多数显示设备都采用RGB色彩模型。
RGB色彩模型下拥有较多的色彩空间,常见的有sRGB、AdobeRGB、ProPhotoRGB等,它们能够表达的色域范围依次递增(下图)。
sRGB色彩空间是惠普与微软于1996年一起开发的用于显示器、打印机以及因特网的一种标准RGB色彩空间。这种标准得到了W3C、Exif、英特尔、Pantone、Corel以及其它许多业界厂商的支持。也是目前应用和支持得最广泛的一种色彩空间。
sRGB使用的是Gamma校准系数为2.2的色彩空间,也是CRT显示器在这种情况下的平均线性电压响应。
sRGB中定义的R、G、B及白色分别位于CIE xy颜色坐标系中的[0.6400, 0.3300]、[0.3000, 0.6000]、[0.1500, 0.0600]、[0.3127,0.3290]的D65。(下图)
Adobe RGB色彩空间是一种由Adobe Systems于1998年开发的色彩空间。开发的目的是为了尽可能在CMYK彩色印刷中利用计算机显示器等设备的RGB颜色模式上囊括更多的颜色。Adobe RGB色彩空间包括了约50%的Lab色彩空间中的可视色彩,主要在青绿色(cyan-green)色系上有所提升。
Adobe RGB中定义的R、G、B及白色分别位于CIE xy颜色坐标系中的[0.6400, 0.3300]、[0.2100, 0.7100]、[0.1500, 0.0600]、[0.3127,0.3290]的D65。(下图)
2.1.2.4 HSV
由于RGB是面向显示设备的色彩模型,对人眼来说,难以分辨各个分量合成的颜色。例如,50%的红色分量和80%的绿色混合后的颜色,人类无法快速感知。
于是引入了HSV色彩模型,以便人类更加方便描述和感知色彩。
HSV分别代表了Hue(色相)、Saturation(饱和度)、Value(明度),是一种面向人类的色彩模型。它的色彩三维图如下:
HSV的值可由RGB三原色计算出来,具体过程如下:
设\((r, g, b)\)分别是一个颜色的红、绿和蓝坐标,它们的值是在\(0.0\)到\(1.0\)之间的实数,设\(max\)等价于\(r\), \(g\)和\(b\)中的最大值,设\(min\)等于这些值中的最小值。要找到在HSV空间中的 \((h, s, v)\)值,这里的\(h\) ∈\([0, 360)\)度是角度的色相角,而\(s, l ∈ [0.0,1.0]\)是饱和度和明度,计算公式:
\[ v = max \]
同样地,HSV坐标空间的颜色也可以转成RGB坐标空间:
HSV也被称为HSB,与之相类似的还有HSL(色相、饱和度、亮度)。它们都是面向人类的色彩模型,区别仅仅是饱和度、亮度的定义略有不同(下图)。
HSV广泛地应用在DDC软件中的颜色选取、变色及其它颜色操作中,也是UE和UE材质编辑器中最常用的一种色彩模型。
UE的颜色拾取器,上半部分是HSV图形选择界面,下半部分左侧是RGB色彩模型的值,半部分右侧是HSV色彩模型的值。
2.1.2.5 CMYK
CMYK分别代表Cyan(青色)、Magenta(洋红、品红)、Yellow(黄色)、Black(黑色),是一种在白色介质上吸收原色色彩的模型,常用于印刷。
2.1.2.6 YUV
YUV是电视等数码领域常用的一种色彩空间,“Y”表示明亮度(Luminance、Luma),“U”和“V”则是色度、浓度(Chrominance、Chroma)。Y'UV, YUV, YCbCr,YPbPr等专有名词都可以称为YUV。
以下是YUV色彩空间的UV分布图:
Y′UV, YUV, YCbCr, YPbPr所指涉的范围,常有混淆或重叠的情况。从历史的演变来说,其中YUV和Y'UV通常用来编码电视的模拟信号,而YCbCr则是用来描述数字的影像信号,适合影片与图片压缩以及传输,例如MPEG、JPEG。 但在现今,YUV通常已经在计算机系统上广泛使用。
若将图片分解成YUV各分量,可得到以下的画面:
最上是正常的图片,下面三幅图分别是分解出来的Y、U、V分量图。
除了以上色彩模型和色彩空间,实际上还有很多其它的色彩模型和空间,但与PBR关联较强的只有RGB和HSV色彩模型。故其它不在此讨论,有兴趣的可以查阅这篇文章:深入理解color model(颜色模型)。
2.1.3 色彩属性
2.1.3.1 色环
色环也叫色轮,其实就是HSV或HSL中的色相分量,可由一个2D的圆形表示出来(下图)。
其中0度是红色,60度是黄色,120度是绿色,180度是青色,240度是蓝色,300度是品红。
在色环中,相距60度以内的色彩被称为相邻色,也被称为类似色;相距100~179度的色彩被称为对比色;相距180度的色彩被称为互补色。例如,对于红色,它的相邻色是黄色和品红,对比色是绿色和蓝色,互补色是青色。
在色环中,常见的RGB和CYM的相邻和互补色如下图:
在色环中,还存在冷暖色系,代表着相同物体在不同温度下所发出的颜色,也代表着其它很多含义(活泼度、紧张度、情绪度、强烈度、夸张度、食欲度、成熟度等等)。其中,暖色代表物体温度较低时发出的颜色,以橙色为中心的半圆;冷色是物体温度较高时发出的颜色,以蓝色为中心的半圆:
在良好的色彩搭配当中,色彩数量不宜过多,控制在3种以内;色彩之间搭配合理、得当,充分利用相邻色、互补色及冷暖调以达到画面的统一、和谐或增加对比度、冲击力。
上图大面积的冷色表明了山湖环境的宁静和寒冷,而小范围的暖色突出了屋子灯光的暖和,强烈的冷暖对比给人以高反差的视觉观感。
当然实际应用中,不宜受条条框框的限制,应以主题为目标,充分发挥色环的作用。更多色彩搭配理论推荐阅读:《色彩设计的原理》。
UE材质编辑器提供了色相修改节点HueShift
:
2.1.3.2 色阶
色阶反应了HSV色彩模型的分量V:明度,表达了人眼能够感受到的色彩的亮度级别。
值得一提的是,人眼对R、G、B三原色的亮度感知程度是不一样的。绿色提供最多的亮度贡献值,红色、蓝色次之,可用以下公式表达:
\[ 颜色亮度 = R*0.3 + G*0.6 + B*0.1 \]
仔细观察上述公式,可发现R、G、B的3个亮度贡献值相加刚好为\(0.3+0.6+0.1=1.0\),这也保证了能量守恒。
在摄影学中,通常将颜色的亮度划分为若干等分,每个等分跨度一致,一个等分成为色阶。
其中亮度靠近黑色的色阶被称为暗调(low tone,也叫低调、阴影、黑色、黑场),亮度位于中间的色阶被成为中调(mid tone,也叫中间调、曝光),亮度靠近白色的被称为亮调(high tone,也叫高调、白色、高光、白场)。
至于色阶被划分的数量及命名并没有统一的规定。例如,Photoshop的Camera Raw中,将色阶划分为:高光、亮调、暗调、阴影:
而Light Room中,将色阶划分为:白色、高光、曝光、阴影、黑色。
虽然划分和名称不一,但我们只需要记住:靠近黑色的是低调,中间部分是中调,靠近白色的是高调。
理解和掌握色阶色调,有助于操作PBR材质、后处理、色调映射、颜色操作等。例如,如果需要对PBR的漫反射贴图进行调整,而且需要对各个色阶进行精确控制,则可以用UE的材质节点3PointLevels
:
上图中的Black Value
、Middle Value
、White Value
分别代表暗调、中调、亮调。
2.1.3.3 色纯
色纯也叫色彩饱和度,表达了色纯的鲜艳程度。纯度越高,色彩越艳越浓,纯度越低则色彩变灰变淡。
上图从左到右饱和度依次降低,可以看见,饱和度越高,色彩越浓越艳丽,饱和度越低,色彩趋向灰白色。
利用饱和度的这种特点,可以将画面分为高饱和、中饱和、低饱和画面,分别代表着不同的风格和意义。比如,高饱和画面充满激情、热烈,但不耐看,容易视觉疲劳;低饱和画面代表冷淡、平静,但也会给人一种压抑的感觉。
相同的画面,由于左边饱和度低,给人以压抑和情绪感;而右边饱和度高,给人以清新明丽的感觉。图片来源
所以,充分利用色彩纯度,可以突出色彩的作用和画面的风格。
UE材质编辑器也提供了相应节点,可方便地调整饱和度:
2.1.3.4 色温
色温是可见光在摄影、录像、出版、图形渲染等领域具有重要应用的特征。光源的色温是通过对比它的色彩和理论的热黑体辐射体来确定的。在摄影学中,也被称为白平衡。
下面是黑体物质在温度慢慢升高的颜色变化图:
但是,上图只是近似变化图,实际上,发光物体的色温跟很多因素有关,计算公式可由普朗克辐射定律(Planck's Radiation Law)描述:
\[ U(λ,T) = \frac{8\pi hcλ^{-5}} { e^{\frac{hc}{λkT}}-1 } \]
公式中各符号代表的意义如下:
- \(U\) - 辐射能量
- \(λ\) - 电磁波波长,单位:米
- \(T\) - 温度,单位开尔文(Kelvin)
- \(h\) - 普朗克常量,值为\(6.626×10^{-34} J·s\)
- \(k\) - 波尔兹曼常量,值为\(1.381×10^{-23} J·K^{-1}\)
- \(c\) - 真空光速,值为\(3.0 × 10^8 m \cdot s^{-1}\)
在生活中,常见发光物体对应的色温如下表:
色温 | 发光物体 |
---|---|
1700 K | 火柴光 |
1850 K | 蜡烛 |
2800 K | 钨灯(白炽灯)的常见色温 |
3000 K | 卤素灯及黄光日光灯的常见色温 |
3350 K | 演播室“CP”灯 |
3400 K | 演播室台灯,、照相泛光灯(不是闪光灯)等... |
4100 K | 月光、浅黄光日光灯 |
5000 K | 日光 |
5500 K | 平均日光、电子闪光(因厂商而异) |
5770 K | 有效太阳温度 |
6420 K | 氙弧灯 |
6500 K | 最常见的白光日光灯色温 |
9300 K | 电视屏幕(模拟) |
5000K和6500K的黑体的颜色分别接近于普通D50和D65的发光物,这通常用于颜色再现的场合(摄影、出版,等等)。在摄影中,5000K又是最常作为太阳发出的白色光色温。
同一张画面,不同的色温将呈现出不同的效果:
左图是正常色温画面,右图是色温偏向暖调,给人以太阳强烈照射的暖色感。
在UE中,灯光可通过属性面板开启色温调节,以模拟不同类型的发光源:
2.1.3.5 对比度
对比度(Contrast)是描述整副图像的明暗反差程度,反映的是色彩的明度(亮度)关系。
对比度越高,明暗反差越明显,暗部更加暗,亮部更加亮(下图)。
左图通过加强对比度之后,形成明暗反差更加强烈的右图。
适当提高对比度可增加画面的冲击力,提升画面的通透度,但同时,要注意过犹不及,过高的对比度,会出现死黑和死白现象,导致画面诡异或不合理。
UE材质编辑器也提供了对比度调整节点CheapContrast
:
2.1.3.6 清晰度
清晰度(Clarity)是反映画面的可识别度和可辨别度。清晰度越高的照片,能呈现的细节越多,反之,图片将变得越模糊。
左图是正常清晰度的照片,右图降低了清晰度,显而易见,图片变得非常模糊不清。
同样地,UE材质编辑器也有相应节点调整颜色清晰度:
2.1.3.7 锐利度
锐利度(Sharpness)跟清晰度比较类似,但也有区别。清晰度反映的是画面像素之间的反差程度,而锐利度反映的是画面轮廓或边缘的反差程度。更通俗地说,清晰度表述的是所有像素,而锐利度只表述轮廓、边缘或反差较大的局部像素。
右图经过提升锐利度后,脸部、头发、衣服、草丛等的边缘和轮廓变得更加清晰了。
可能有人会疑惑:色彩既然有了清晰度的属性为什么还需要锐利度?
从摄影学上更好回答这个问题:对含有人物(特别是美女)的画面,为了使画面更加美观,往往不需要在皮肤上增加清晰度,只需要在脸部和五官轮廓处增加,而锐利度恰好符合这一特点,使得摄影师或者设计师能够快速地得到美观而清晰的画面。
在Photoshop中,增加锐利度的方法有很多,常见的有:USM锐化、边缘锐化、智能锐化、高反差保留等等。
在UE材质编辑器中,也有材质节点增加锐利度:
上图的HighPass
就是PS里的高反差保留锐化。
对UE渲染的画面而言,在后处理节点执行锐化是非常有必要的。因为UE默认采用了延迟着色模式并且开启了TAA(时间抗锯齿),而TAA算法的特性会导致画面变模糊,在最后阶段增加锐利度,可一定程度上抵消TAA带来的画面模糊,提升画面通透度和美观感。
2.1.4 直方图
直方图是反应一副图像中所有像素在各个亮度色阶的数量分布情况。
通常情况下,直方图左侧是暗调,中间是中调,右边是亮调。例如,下图左侧是一副正常后期过的图片,它对应的直方图在右上角。
通过直方图,我们可以清晰地观察到,上述图片大量像素亮度集中在高调部分,属于一副高调风格的片子。此外,还可以通过调整色阶,实时查看图片的直方图以观察整副图片的亮度变化情况。
2.1.5 色调曲线
色调曲线(Tone curve)是一种将颜色值的输入值一一映射到输出值的曲线函数,可以精确地控制处于不同色阶的像素的亮度。若将色调曲线设为\(f_{tone}\),则颜色调整公式为:
\[ x' = f_{tone}(x) \]
其中\(x'\)是调整后的颜色值,\(x\)是原始颜色值,可以是RGB的任一分量。
下列是一些特殊色调曲线的调整和对应的效果图。
正常的画面和色调曲线,此时的色调曲线呈45度的直线。
加强明暗对比的画面和色调曲线,此时的色调曲线暗部处于直线下方,中间调位于直线上,亮部位于直线上方。
自定义的色调曲线,曲线大范围偏离到直线下部,使得整体画面亮度变暗,对比度变小。
由此可见,色调曲线给予了非常精确、自由、灵活的色彩调整功能,在摄影学、数码硬件、DDC、图像处理、计算机图形学、计算机视觉乃至PBR制作中,都有着举足轻重的作用。
2.1.6 线性空间与Gamma空间
本质上,Gamma曲线是一种特殊的色调曲线,线性曲线又是一种特殊的Gamma曲线。
线性空间(Linear Space)是RGB颜色都处于色调曲线的对角直线状态(下图),处于线性空间的颜色值是线性变化的,而不会有任何非线性改变,用公式来表达是:\(x'=f(x) = x\)。
与线性空间相对立的是Gamma空间,它是有着指数级的色调曲线的变换空间,Gamma曲线计算公式:
\[ x'= f(x) = x^n = pow(x, n) \]
其中,\(x\)是颜色\(r,g,b\)任一分量的值,值域是\([0.0, 1.0]\),\(n\)是Gamma校正指数。下图中,分别是\(n\)取\(0.45\),\(1.0\),\(2.2\)的Gamma空间色调曲线图。
1.0是线性空间,输入输出值一样;0.45和2.2是Gamma曲线,处于此空间的色彩将被提亮或压暗,并且\(0.45 \cdot 2.2 \approx 1.0\),以保证两次Gamma校正之后能够恢复到线性空间:
\[ x' = f_{gamma2.2}(f_{gamma0.45}(x)) = ({x^{0.45}})^{2.2} = x^{0.45 \cdot 2.2} = x^{0.99} \approx x \]
从左到右:0.45的Gamma校正图像,1.0的线性空间的原始图像,2.2的Gamma校正图像。
上图左执行2.2的Gamma校正后将得到中间图像;同样,上图右执行0.45的Gamma校正后也可以得到中间图像。
线性空间对于计算机图形学中,有着至关重要的作用,它能够保证在GPU的shader中经过多次复杂的计算后,依然能够得到正确的颜色值;反之,如果是在Gamma空间执行shader计算,将得到误差很大的画面效果。
上半部分是线性空间,在不同光强度的反应下,能够得到正确的结果;下半部分是Gamma空间的计算,对光强度的反应过于强烈,会得到过曝的画面。
正因为线性空间能够得到更加准确的渲染结果,所以主流商业引擎(UE、Unity、CryEngine、Frostbite等)都支持了线性空间渲染管线。
线性空间渲染管线(下半部分)在shader前期去除了Gamma校正,在shader后期恢复Gamma校正。
那为什么线性空间的渲染管线要在前期和后期分别去掉又加回Gamma校正呢?
这其实是历史遗留的问题。
早期的电视机采用CRT显像管,由于电压的强度与人眼感知的亮度不成正比,成指数为0.45的指数级曲线。为了解决这个问题,就引入指数为2.2的Gamma校正,强行提升显示图像的数据让电压与人眼感知亮度成线性比例。久而久之,之后的很多硬件设备、色彩空间(如sRGB)、文件格式(如jpeg,png等)、DDC软件(如ps)默认都执行了Gamma校正,并且一直沿用至今。
虽然当今的液晶显示器不再需要Gamma校正,但为了兼容已经广泛存在的有着Gamma校正的色彩空间及标准,也不得不保留Gamma校正。所以在shader后期还是要恢复Gamma校正,以便图片能够在显示设备正常显示。
更多关于线性空间和Gamma空间的知识,请参阅:Gamma & Linear Color Space。
2.1.7 HDR和色调映射
HDR(High Dynamic Range)即高动态范围,拥有更高的对比度和更广的色域,可分为基于软件的后处理HDR和基于硬件的显示设备HDR。与HDR相对立的是LDR(Low Dynamic Range,低动态范围)。
基于软件的后处理HDR是指摄影后期、图形渲染后处理阶段在亮部增加类似泛光(Bloom)的效果,但实际上依然可能是LDR(低动态范围)。
UE后处理阶段增加的泛光效果。
基于硬件的HDR显示设备里有两个重要参数:
- Paper White:直译是白纸的白,表示白色的亮度,单位为尼特(nits)。
- Max Luminance:表示显示设备能达到的最大亮度,单位也是尼特(nits)。
在LDR设备上,Paper White和Max Luminance是一样的,一般是100 尼特。而在HDR显示设备上,Paper White还是100左右,Max Luminance可以达到400~1000尼特。
所以,基于硬件的HDR显示设备才是真正意义上的HDR,因为它们可以显示超过很多倍标准白色的亮度。
当然,拥有HDR显示设备还不够,需要应用程序在渲染阶段支持HDR数据,最直观的一点就是shader里的数据允许颜色值超过255(或归一化的1.0)。
目前,主流商业引擎都支持了HDR的渲染流程,下图是UE的LDR和HDR对比图:
UE的LDR(上)和HDR(下)对照图,可明显看出HDR色彩更鲜艳,亮度对比更显著。
启用HDR的应用程序面临一个问题:应用程序阶段的HDR数据格式很可能与显示设备所需的HDR格式不一致,或者显示设备压根不支持HDR,只支持LDR格式。
为了解决以上这个问题,就需要引入色调映射(Tone Mapping),它可以将HDR颜色变换成LDR格式或者另一种HDR格式(VDR)。
常见的色调映射方法有:
- Reinhard Tone Mapping
该方法是Reinhard在2002年通过论文Photographic Tone Reproduction for Digital Images提出的色调映射方法。
它的特点是通过压缩亮部和暗部的存储空间,以提升中间调的细节和对比度。曲线如下图所示:
利用Reinhard可较好地保留亮部和暗部细节:
上图未采用色调映射,下图采用了Reinhard色调映射法,可清楚看到亮部细节被很好地保留了。
Reinhard的实现非常简单,在早期对性能要求苛刻的实时渲染领域,非常适用。它的shader实现代码:
// color是线性空间的HDR颜色值,adapted_lum是根据整个画面统计出来的亮度
float3 ReinhardToneMapping(float3 color, float adapted_lum)
{
const float MIDDLE_GREY = 1; // 中性灰,基于经验获得
color *= MIDDLE_GREY / adapted_lum;
return color / (1.0f + color);
}
- CryEngine Tone Mapping
2007年发布的孤岛危机(Crysis)使用的是CryEngine渲染引擎,CryEngine使用了更加简单暴力的色调映射,它的曲线如下图:
由于该方法更大地压缩了亮部和亮度的对比度,所以可以得到比Reinhard更加高对比和色彩的画面。
启用了CE色调映射的Crysis游戏画面。
- Filmic Tone Mapping
2010年,冒险动作主机游戏神秘海域2(Uncharted 2)公布了它的色调映射方法,被称为Filmic Tone Mapping(电影级色调映射)。
该方法的源自艺术家或者TA用专业数码设备模拟出的胶片感,再加上用DDC软件手动色调映射的结果,然后用拟合软件得到色调映射曲线。将它应用到渲染领域,能得到人工调整的结果,从而得到高质量的电影胶片感。
从上图看看到,Filmic Tone Mapping曲线在暗部拥有非常长非常缓的坡度,表明极大压缩了暗部的显示区域,腾出空间给中部和亮部。下图是神秘海域2的游戏画面:
它的实现代码稍微较长:
float3 F(float3 x)
{
// 多项式的系数
const float A = 0.22f;
const float B = 0.30f;
const float C = 0.10f;
const float D = 0.20f;
const float E = 0.01f;
const float F = 0.30f;
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
}
float3 Uncharted2ToneMapping(float3 color, float adapted_lum)
{
const float WHITE = 11.2f; // 白色位置,基于经验获得
return F(1.6f * adapted_lum * color) / F(WHITE);
}
Gamma校正也可以和Filmic色调映射合并在一起,从而提升渲染性能。
- ACES Tone Mapping
ACES(Academy Color Encoding System,学院色彩编码系统)是一套专门管理和编解码色彩的体系。而它的创立者Academy of Motion Picture Arts and Sciences是颁发好莱坞奥斯卡的官方机构。
ACES提供了一套通用格式以兼容LDR和各种HDR颜色数据格式,对于实时渲染领域,只需用下列的色调曲线将线性空间的颜色转成HDR格式:
如果用代码实现,则是以下所示:
float3 ACESToneMapping(float3 color, float adapted_lum)
{
const float A = 2.51f;
const float B = 0.03f;
const float C = 2.43f;
const float D = 0.59f;
const float E = 0.14f;
color *= adapted_lum;
return (color * (A * color + B)) / (color * (C * color + D) + E);
}
UE4中使用的胶片色调映射器也符合ACES标准,所采用的曲线如下图:
相较旧的色调映射器,新的渲染结果更加接近物理真实:
上图是UE旧的色调映射,下图采用了ACES的色调映射,可见新的色调映射在自发光率足够大时,颜色开始变白,更符合物理真实。
与色调映射常常一起出现的概念还有色彩分级(Color Grading)和颜色查找表(LUT),它们都是属于后处理的范畴,更多可参阅虚幻官方文档:颜色分级和胶片色调映射器和高动态范围显示输出。
2.2 颜色操作
本节将深入分析颜色的各类常见操作,以及结果的变化趋势,以便为后续的PBR制作打下更加扎实的基础。
2.2.1 基础操作
本小节将分析颜色的基本操作加减乘除,由于加与减、乘与除本质上是一样的,所以只需分析加法和乘法。
2.2.1.1 颜色相加
颜色相加是最常用到的一种操作,通常用于若干个光源叠加,或者若干种颜色分量叠加。当然,PBR制作也经常用到颜色相加,以调整颜色的结果。颜色相加操作本质上是对颜色执行线性曲线的平移,抽象成函数:
\[ f(x) = x + c \]
其中\(c\)就是相加操作数。
颜色相加操作的分析主要可分两种情况:一是操作数是灰白色;二是操作数是彩色。
如下图,是第一种情况,可以看到彩色\((0.75, 0.5, 0.25)\)加了灰白色\((0.25, 0.25, 0.25)\),得到右边的新颜色\((1.0, 0.75, 0.5)\)。
彩色操作数的HSV是\((30,0.67,0.75)\),新颜色HSV是\((30,0.51,1.0)\)。由此可得出结论:颜色与灰色相加,得到的新颜色色相不变,饱和度降低,亮度增加。
现在看第二种情况,将灰色改成彩色:
颜色操作数1的HSV是\((30,0.67,0.75)\),颜色操作数2的HSV是\((216,0.82,0.59)\),结果颜色的HSV是\((300,0.07,0.84)\)。由此可得出结论:颜色与彩色相加,得到的新颜色色相会改变,饱和度也会改变,亮度会增加。
实际上,加法还有其它一些特殊情况,诸如黑色、同色相颜色相加的情况,结果颜色的变化见下表:
加法操作数 | 色相变化 | 饱和度变化 | 亮度变化 | 对比度变化 |
---|---|---|---|---|
灰色 | 不变 | 降低 | 增加 | 降低 |
彩色 | 改变 | 改变或不变 | 增加或不变 | 降低或不变 |
黑色 | 不变 | 不变 | 不变 | 不变 |
同色相彩色 | 不变 | 改变或不变 | 增加或不变 | 降低或不变 |
白色 | 变成0 | 变成0 | 大于等于1 | 变成0 |
上表针对的是加法操作,减法的结果与加法有着规律的对比,降低的变增加,增加的变降低,不变的依然保持不变。
2.2.1.2 颜色相乘
颜色相乘也是最常用、最基本的操作,代表着颜色随着某种系数衰减或者增强。颜色相乘操作本质上是对颜色执行线性曲线的缩放,抽象成函数:
\[ f(x) = c \cdot x \]
其中\(c\)就是乘法操作数。
颜色相乘操作也可分为灰色和彩色因子两大类,其中灰色因子分为因子大于1或不大于1两种情况。先分析灰色因子,如下图:
上图是小于1的因子,新颜色的色相和饱和度不变,亮度降低;下图是大于1的因子,新颜色的色相和饱和度不变,亮度增加。
上图中,两个彩色相乘,得到的结果色相、饱和度、亮度都发生了改变。
结合一些特殊的情况,可得到如下表:
乘法操作数 | 色相变化 | 饱和度变化 | 亮度变化 | 对比度变化 |
---|---|---|---|---|
灰色(大于1) | 不变 | 不变 | 增加 | 增加 |
灰色(小于1) | 不变 | 不变 | 降低 | 降低 |
白色 | 不变 | 不变 | 不变 | 不变 |
黑色 | 变成0 | 变成0 | 变成0 | 变成0 |
彩色 | 改变 | 改变 | 改变 | 改变 |
除法与乘法有着类似的规律,只是灰色(大于1)和灰色(小于1)反过来,并且与黑色相除的结果无定义。
2.2.2 颜色插值
颜色插值是通过一组插值系数在多个操作数中取不同权重的值的操作,在PBR制作、后处理、数码后期等领域使用得非常多,常见的插值方式有线性、S形、三角插值等等。
2.2.2.1 线性插值
线性插值需要两个操作数\(a\),\(b\)和一个插值系数\(x\),则它们的插值公式是:
\[ f(x) = a + (b - a) * x \]
其中\(x\)的值域是\([0, 1]\),以上公式对应的曲线图如下:
UE材质编辑器也提供了线性插值节点:
2.2.2.2 S插值
线性插值在操作数附近过渡比较生硬,不够自然,而S形插值则可以解决这个问题。S形插值可用很多方式模拟,如\(\sin\)、色调映射、贝塞尔曲线等。
其中,用\(\sin\)模拟的S形插值的公式是:
\[ f(x) = \sin(x\cdot \pi-\frac{\pi}{2})\cdot 0.5 + 0.5 \]
模拟出的曲线如下图:
从上图可以看出,在曲线两端,斜率由水平逐渐过渡,从而达到平滑插值的目的。
UE默认不提供上述曲线的插值材质节点,需要手动实现,笔者实现的材质函数SineLerp
如下图:
由于UE的内置Sine
材质节点在内部乘了\(\pi\)且做了偏移,所以实现起来跟上面提到的公式略有不同,会更加简便,但也会给不熟悉UE材质编辑器的人带来困惑。
2.2.2.3 其它插值
其它插值诸如法线融合、三角插值、方格插值、高度图插值,对应不同的应用场景,在PBR材质中较少用到,有兴趣的同学自行查阅相关资料或到UE材质编辑器摸索。
UE材质编辑器提供的各式插值方式。
2.2.3 颜色混合
颜色混合是指将一种颜色与目标颜色通过某种方式相融合的操作,这些操作被称为混合模式(Blend Mode)。
不同的混合模式将得到不同的混合结果,通常涉及两个颜色:混合颜色(Blend Color,记作\(a\))和底色(Base Color,记作\(b\)),部分混合模式还涉及混合系数\(alpha\)。
它也是Photoshop的图层混合模式,同时UE也提供了相应的混合材质节点。混合模式很多,可分为普通、变暗、变亮、饱和度、差集、颜色等几大类。(下图)
Photoshop的图层混合模式,相信美术、TA、摄影、设计等领域的同学都不陌生。
- 正常(Normal)
正常混合模式是最普通、最常用的一种混合模式,其实就是在两个图层中进行线性插值。它的公式如下:
\[ f(a, b, alpha) = a \cdot alpha + b \cdot (1 - alpha) \]
用UE实现的效果如下图:
- 正片叠底(Multiply)
正片叠底就是将混合颜色和底色相乘,通常会得到更低亮度和饱和度的颜色。公式如下:
\[ f(a, b) = a \cdot b \]
用UE实现的效果如下图:
- 颜色加深(Color Burn)
在此混合模式中,若混合颜色\(a\)越暗,则在最终结果中使用该颜色越多。如果颜色\(a\)为白色,则不进行任何更改。它的公式:
\[ f(a,b) = 1- \frac{1-b}{a} \]
UE的材质节点Blend_ColorBurn
实现了这种混合模式:
- 线性加深(Linear Burn)
将底色颜色与混合颜色相加,然后从结果中减去 1。它的公式:
\[ f(a,b) = a + b - 1 \]
UE的材质节点Blend_LinearBurn
的内部实现及效果:
- 颜色减淡(Color Dodge)
通过将底色颜色反转并将其除以混合颜色,使结果变亮。混合公式:
\[ f(a,b) = \frac{b}{1-a} \]
UE的材质节点Blend_ColorDodge
可实现这种混合模式:
- 线性减淡(Linear Dodge)
将“底色”(Base)颜色与“混合”(Blend)颜色相加。混合公式:
\[ f(a,b) = a + b \]
UE的材质节点Blend_LinearDodge
可实现这种混合模式:
- 线性光(Linear Light)
线性光是 Overlay(覆盖)的线性版本,用于提供更粗糙的结果。此函数对混合颜色执行比较,从而每当混合比 50% 灰度亮时,就通过筛滤(Screen)操作对底色和混合颜色进行组合。如果混合颜色比 50% 灰度暗,那么将像“乘”功能一样,将底色与混合相乘。公式如下:
\[ f(a,b)={ \begin{cases} ab, &{\mbox{if }}a<0.5 \\2a+b-1,&{\mbox{else}} \end{cases} } \]
UE的材质节点Blend_LinearLight
的混合效果:
- 变暗(Darken)
针对底色和混合颜色的每个像素,选择较暗的值。如果混合颜色为白色,则不会产生变化。公式:
\[ f(a,b) = \min(a, b) \]
UE材质编辑器的Blend_Darken
实现及效果:
- 变亮(Lighten)
对底色和混合颜色的每个像素进行比较,并返回较亮的结果。公式:
\[ f(a,b) = \max(a, b) \]
UE材质编辑器的Blend_Lighten
实现及效果:
- 差异(Difference)
通过从混合中减去底色,然后取结果的绝对值,创建反转样式的效果。公式:
\[ f(a,b) = | a - b| \]
UE材质编辑器的Blend_Difference
实现及效果:
- 排除(Exclusion)
将底色和混合纹理二等分,对其进行组合,然后对结果执行部分反转。公式:
\[ f(a,b) = 0.5 - 2(a - 0.5)(b - 0.5) \]
UE材质编辑器的Blend_Exclusion
实现及效果:
- 强光(Hard Light)
强光与覆盖(Overlay)的粗糙版本相似,它会对底色和混合进行筛滤或相乘。此函数对混合颜色执行比较,从而每当混合比 50% 灰度亮时,就通过筛滤(Screen)操作对底色和混合进行组合。如果混合比 50% 灰度暗,那么将像“乘”功能一样,将底色与混合相乘。然后,提高最终结果的对比度,以产生粗糙输出。公式如下:
\[ f(a,b)={\begin{cases}2ab, &{\mbox{if }}a<0.5 \\1 - (1-2(a-0.5))(1-b),&{\mbox{else}}\end{cases}} \]
UE材质编辑器的Blend_HardLight
实现的效果:
- 覆盖(Overlay)
覆盖在PS被称为叠加,对底色和混合进行筛滤或相乘。此函数对混合颜色执行比较,从而每当混合比 50% 灰度亮时,就通过筛滤(Screen)操作对底色和混合进行组合。如果混合比 50% 灰度暗,那么将像“乘”功能一样,将底色与混合相乘。公式:
\[ f(a,b)={ \begin{cases} 2ab, &{\mbox{if }}a<0.5 \\1-2(1-a)(1-b),&{\mbox{else}} \end{cases} } \]
UE的材质节点Blend_Overlay
的混合效果:
- 点光(Pin Light)
点光与Overlay(覆盖)相似,它使底色和混合一起变亮或变暗。此函数对混合颜色执行比较,从而每当混合比 50% 灰度亮时,就通过筛滤操作对底色和混合进行组合。如果混合比 50% 灰度暗,那么将像“乘”功能一样,将底色与混合相乘。对比度会软化,这使此函数成为 Overlay(覆盖)的不太粗糙版本。公式:
\[ f(a,b)={ \begin{cases} \min(2a,b), &{\mbox{if }}a<0.5 \\ \max(2(a-0.5),b),&{\mbox{else}} \end{cases} } \]
UE的材质节点Blend_PinLight
的混合效果:
- 筛滤(Screen)
筛滤(Screen)在PS里叫滤色,按混合颜色使底色变亮。其工作方式如下:对这两种颜色都执行“一减”,将它们相乘,然后对结果执行“一减”。公式:
\[ f(a,b) = 1 - (1 - a)(1 - b) \]
UE材质编辑器的Blend_Screen
实现及效果:
- 柔光(Soft Light)
柔光是 Overlay(覆盖)的柔和版本。此函数对混合颜色执行比较,从而每当混合比 50% 灰度亮时,就通过筛滤操作对底色和混合进行组合。如果混合比 50% 灰度暗,那么将像“乘”功能一样,将底色与混合相乘。对比度会软化,这使此函数成为 Overlay(覆盖)的不太粗糙版本。公式:
\[ f(a,b)={ \begin{cases} (a+0.5)\cdot b, &{\mbox{if }}a<0.5 \\ 1 - (1-(a-0.5))(1-b),&{\mbox{else}} \end{cases} } \]
它也是Photoshop后期处理中用得比较多的一种混合模式,可以加大画面对比度,提升通透感。UE的材质节点Blend_SoftLight
的混合效果:
2.3 常用曲线
从上两节可以看到,颜色的原理、理论和操作大量运用了曲线函数,这节将PBR制作中常用的曲线总结出来并加以分析。
2.3.1 线性曲线
线性曲线在颜色插值、色调映射、后处理、混合等操作中经常用到,抽象的公式如下:
\[ f(x) = ax + b \]
其中\(x\)是变量,\(a\)和\(b\)是实数。当\(a=0.6,b=-0.1\)时的曲线如下所示:
2.3.2 指数曲线
指数曲线是指变量\(x\)的指数\(n\)大于1,可由若干个多项式抽象出来:
\[ f(x) = \sum_{i=1}^{n}a_ix^i + b \]
其中\(a_i\)是每个项的实数。当然,我们实际应用中,极少用到多项式,一般只需一项,即取\(a_n=1,a_i=0(i
\[ f(x) = x^n \]
进一步地,取\(n=2\)可得到曲线\(f(x)=x^2\),对应的曲线图:
由上图可知:在指数级曲线中,当底数小于1时,数值比原来的值要小。
常用的还有不同指数的曲线:
细心的童鞋应该发现了,当\(n=2.2\)和\(n=0.45\)时,就是前面提到的Gamma校正曲线。
2.3.3 三角函数
三角函数有正弦、余弦、切线、余切等等,但PBR制作中常用的是正弦和余弦,而正弦和余弦本质是一样的,只是偏移不同,故下面只列出正弦公式:
\[ f(x) = a\cdot\sin(x\cdot t + \theta) + b \]
其中\(a\)是振幅,\(t\)是周期缩放因子,\(\theta\)是相位偏移,\(b\)是振幅偏移。当\(a=1,t=1,\theta = 0, b = 0\)就是\(f(x)=\sin(x)\),对应曲线如下:
当\(a=0.5,t=\pi,\theta = -\frac{\pi}{2}, b = 0.5\)就可获得S形插值曲线:
\[ f(x) = 0.5 \cdot \sin(x\cdot \pi-\frac{\pi}{2}) + 0.5 \]
2.3.4 贝塞尔曲线
贝塞尔曲线是一种由若干控制点控制的平滑曲线。假设控制点数量是\(n\),则控制点可表示为\(P_0, P_1,...,P_{n-1}(n\ge2)\)。
当控制点数量是2时,贝塞尔曲线公式如下:
\[ \boldsymbol B(t) = P_0 \cdot t + P_1 \cdot (1-t), t\in[0,1] \]
实际上就是线性插值和正常混合公式。
当控制点数量是3时,贝塞尔曲线公式和曲线图如下:
\[ \boldsymbol B(t) = P_0 \cdot (1-t)^2 + P_1 \cdot 2t(1-t) + P_2\cdot t^2, t\in[0,1] \]
当控制点数量是4时,公式将更加复杂:
\[ \boldsymbol B(t) = P_0 \cdot (1-t)^3 + P_1 \cdot 3t(1-t)^2 + P_2\cdot 3(1-t)t^2 + P_3 \cdot t^3, t\in[0,1] \]
对应的示例图如下:
2.3.5 Catmull–Rom曲线
贝塞尔曲线的特点是模拟出来的曲线不经过控制点,而Catmull–Rom曲线恰恰补足了这个特性,模拟出来的曲线具体平滑且经过控制点的特性。(下图)
曲线公式和计算可以参见Centripetal Catmull–Rom spline。
它正因为有这种优点,所以被广泛应用于动画插值、颜色混合、曲线调整当中,例如Photoshop、LightRoom、UE中的曲线调整:
在Lightroom利用色调曲线的若干控制点精确调整图片色调,此处的控制点就采用了Catmull–Rom曲线。
2.3.6 其它曲线
实际上,还有很多很多曲线,但限于篇幅,只介绍以上常用的几类曲线,其它曲线可以参看以下链接:
- List of Famous Curves
- 缓动函数速查表
其中缓动函数速查表列举了大量实用的曲线,并且附带了动态图,可以直观地看到曲线平滑度和坡度:
特别说明
感谢所有参考文献的作者们!
原创文章,未经许可,禁止转载!
系列文章,未完待续,后面更精彩!!
参考文献
- 由浅入深学习PBR的原理和实现
- PBR Materials Guide
- THE PBR GUIDE - 2018 EDITION
- Making Realistic PBR Materials - Part 1
- Making Realistic PBR Materials - Part 2: Metal
- Materials (PBR)
- Real Shading in Unreal Engine 4
- Procedural PBR Material Creation using Substance Designer for Visualization
- Unreal Engine 4 Game Development in 24 Hours
- PBR: Implications of its application to Unreal 4 engine map and material creation
- Unreal Engine Document: Materials How-To's
- Unreal Engine Document: Physically Based Materials
- Unreal Engine Document: Materials
- 25 tips for Unreal Engine 4
- Create a PBR Material in Twinmotion
- SUBSTANCE IN UNREAL ENGINE 4: MATERIALS MADE EASY
- DDO Painter + UE4: Master Materials - Quixel
- Intro to Materials in UE4
- Materials I - PBR materials, inputs & material editor within UE
- Unreal Engine 4 Shaders and Effects Cookbook
- DONTNOD Physically based rendering chart for Unreal Engine 4
- Working with Physically-Based Shading: a Practical Approach
- Artist's PBR Guide/淘宝美工PBR白皮书3——色彩空间与色彩模型
- Artist's PBR Guide/淘宝美工PBR白皮书4——Linear与Gamma
- 深入理解color model(颜色模型)
- 《李涛:简单后期教程》
- 《刘杨:造像之术》
- 《色彩设计的原理》
- 《老邮差数码照片处理技法--色彩篇》
- Understanding Physically Based Rendering in Arnold
- Color Model
- Color Space
- 再谈色彩(RGB通道和HSV)
- 学会后期调色,从认识颜色开始
- 材质
- 材质表达式参考
- 材质函数参考
- Lab色彩空间
- CIE1931色彩空间
- 日系海边照片怎么修?看完这篇你就会!
- 伽马空间与线性空间
- Gamma & Linear Color Space
- 如何支持HDR显示设备
- Tone mapping进化论
- Coloure-temperature
- 色温
- Blend modes
- YUV
- Formulas for Photoshop blending modes
- Centripetal Catmull–Rom spline