10 曲面着色

要使对象看起来更真实,可以使用着色,即使用灯光“绘制”表面。本章介绍了最常见的启发式着色方法。前两个,漫反射和Phong着色,是在20世纪70年代开发的,可在大多数图形库中使用。最后一种是艺术着色,它使用艺术惯例为对象指定颜色。这会产生让人想起技术图纸的图像,这在许多应用中都是可取的。

10.1 漫反射着色

世界上许多对象的表面外观松散地描述为“无光泽”,这表明该对象根本没有光泽。例如纸张、未加工的木材和干燥未抛光的石头。在很大程度上,这样的对象不会随着视点的变化而发生颜色变化。例如,如果你盯着一张纸上的一个特定点移动,同时保持你的目光固定在该点上,该点的颜色将保持相对恒定。此类蒙版对象可以被视为朗伯特对象。本节讨论如何实现此类对象的着色。一个关键点是,在应用透视变换后,本章中的所有公式都应在世界坐标中进行计算,而不是在扭曲坐标中进行计算。否则,法线之间的角度将更改,着色将不准确。

10.1.1 Lambert着色模型

Lambertian对象遵循Lambert余弦定律,该定律规定曲面的颜色c与曲面法线和光源方向之间的夹角的余弦成正比(Gouraud,1971):

c \propto \cos \theta

或者以向量的形式,

c \propto n\cdot l

其中n和l如图10.1所示。因此,曲面上的颜色将根据曲面法线和灯光方向之间角度的余弦而变化。注意,通常假定向量l不依赖于对象的位置。该假设相当于假设灯光距离对象很“遥远”。这种“远”光通常称为平行光,因为其位置仅由方向指定。

通过改变光源的强度或表面的反射率,可以使表面变亮或变暗。漫反射系数c_{r}表示曲面反射光的程度。对于不同的颜色组件,该系数将不同。例如,如果曲面反射的红色入射光比例高于蓝色入射光比例,则曲面为红色。如果我们假设表面颜色与从表面反射的光成比例,则漫反射c_{r}为RGB颜色:

c\propto c_{r} n\cdot l

等式(10.1)的右侧是RGB颜色,所有RGB分量都在\left [ 0,1 \right ]范围内。我们希望添加灯光强度的效果,同时将RGB组件保持在范围\left [ 0,1 \right ]内。建议添加一个RGB强度项c_{l},其本身的分量在\left [ 0,1 \right ]范围内:

c = c_{r}c_{l} n\cdot l

这是一种非常方便的形式,但它可以为c生成超出范围\left [ 0,1 \right ]的RGB分量,因为点积可以是负数。如图10.2所示,当表面远离光线时,点积为负值。

可将“max”函数添加到等式(10.2)中,以测试该情况:

c = c_{r}c_{l} max(0,n\cdot l)

处理“负”光的另一种方法是使用绝对值:

c = c_{r}c_{l}\left | n\cdot l \right |

虽然方程式(10.4)在物理上似乎不可信,但实际上它与方程式(10.3)相对应,两个灯光方向相反。因此,它通常被称为双面照明(图10.3)。

10.1.2 环境光着色

方程(10.3)的漫反射着色的一个问题是,其法线面远离灯光的任何点都将是黑色的。在现实生活中,光被反射到全身,有些光从各个方向入射。此外,通常有天窗提供“环境”照明。处理这种情况的一种方法是使用多个光源。一个常见的技巧是始终在眼睛处放置一个暗淡的光源,以便所有可见点都能接收到一些光线。另一种方法是使用等式(10.4)所述的双面照明。更常见的方法是添加环境项(Gouraud,1971)。这只是添加到方程式(10.3)中的恒定颜色项:

c = c_{r}(c_{a} + c_{l}max(0,n\cdot l) )

直观地说,可以将环境光颜色c_{a}视为场景中所有曲面的平均颜色。如果要确保计算的RGB颜色保持在范围\left [ 0,1 \right ] ^{3}内,则c_{a} +c_{l} \le (1,1,1)。否则,代码应该将大于1的RGB值强制改变为1。

10.1.3 基于顶点的漫反射着色

如果我们将等式(10.1)应用于由三角形组成的对象,它通常会具有多面外观。通常,三角形近似于平滑曲面。为了避免面状外观,我们可以在三角形的顶点处放置曲面法向量(Phong,1975),并使用顶点处的法向量在每个顶点处应用方程(10.3)(见图10.4)。这将为每个三角形顶点提供一种颜色,该颜色可以使用第8.1.2节中描述的重心插值进行插值。

三角形顶点着色的一个问题是,我们需要从某处获取法线。许多模型都会提供法线。如果细分自己的平滑模型,则可以在创建三角形时创建法线。如果呈现的多边形模型在顶点处没有法线,并且希望平滑着色,则可以通过各种启发式方法计算法线。最简单的方法是平均共享每个顶点的三角形的法线,并在顶点处使用该平均法线。此平均法线不会自动具有单位长度,因此在将其用于着色之前,应将其转换为单位向量。

10.2 Phong着色

有些曲面本质上类似于哑光曲面,但它们具有高光。此类表面的示例包括抛光瓷砖地板、光泽涂料和白板。随着视点的移动,高光在曲面上移动。这意味着我们必须在方程中加入一个朝向眼睛的单位向量e。若你们仔细观察高光,你们会发现它们实际上是光的反射;有时这些反射是模糊的。这些高光的颜色是灯光的颜色,表面颜色似乎没有什么影响。这是因为反射发生在对象的表面,而穿透该表面并拾取对象颜色的光被漫反射和散射。

10.2.1 Phong光照模型

我们希望在正确的位置添加与光源颜色相同的模糊“点”。如图10.5所示,点的中心应绘制在眼睛方向e与自然反射方向r“lines up”的位置。这里的“lines up”在数学上等同于其σ为零。我们希望高光有一些非零区域,以便眼睛在σ很小的地方看到一些高光。

给定r,我们想要一个启发式函数,当e=r时它是明亮的,当e离开r时它会逐渐消失。一个明显的候选者是它们之间夹角的余弦:

c = c_{l} (e\cdot r )

使用这个方程有两个问题。首先,点积可以是负数。这可以通过一个“if”语句来计算解决,当点积为负数时,该语句将颜色设置为零。更严重的问题是,这个等式产生的亮点比现实生活中看到的要宽得多。最宽的是在正确的地方,它是正确的颜色,但它只是太宽了。我们可以将其缩小,而不降低其最大颜色,方法是将其增大到一个幂:

c = c_{l} max(0,e\cdot r)^{p}

这里p称为Phong指数;这是一个正实数(Phong,1975)。改变Phong指数对高光的影响如图10.6所示。

为了实现方程(10.5),我们首先需要计算单位向量r。给定单位向量lnr是关于n的向量l。图10.7显示,该向量可计算为:

r = -l+2(l\cdot n)n

其中点积用于计算\cos \theta

基于方程式(10.5)的另一种启发式模型无需检查用作幂运算基础的数字的负值(Warn,1983)。代替r,我们计算h,即介于le之间的单位向量(图10.8):

h=\frac{e+l}{\left \| e+l \right \| }

h接近n时,即当\cos \omega =h\cdot n接近1时,会出现高光。这表明了一条规则:

c = c_{l} (h\cdot n)^{p}

此处的指数p将具有与等式(10.5)中的指数类似的控制行为,但hn之间的夹角是er之间夹角的一半,因此细节略有不同。使用nh之间的余弦的优点是,它对平面上方的眼睛和光线总是正的。缺点是需要平方根和除法来计算h

实际上,我们希望大多数材质除了具有高光外,还具有漫反射外观。我们可以将方程(10.3)和(10.7)结合起来得到:

c = c_{r}(c_{a}+c_{l}max(0,n\cdot l) )+c_{l} (h\cdot n)^{p}

如果我们想让用户调暗高光,我们可以添加一个控制变量c_{p}

c = c_{r}(c_{a}+c_{l}max(0,n\cdot l) )+c_{l}c_{p} (h\cdot n)^{p}

变量c_{p}是RGB颜色,它允许我们更改高光颜色。这对于c_{p} = c_{r}的金属非常有用,因为金属上的高光呈现金属色。此外,将c_{p}设置为小于1的中性值通常很有用,以便颜色保持在1以下。例如,设置c_{p} = 1 - M,其中Mc_{r}的最大成分,对于一个光源和无环境项,将使颜色保持在1以下。

10.2.2 曲面法向量插值

与具有相同几何体的朗伯特曲面相比,具有高光的平滑曲面往往会快速改变颜色。因此,法向量处的着色可能产生干扰伪影。通过在多边形上插值法向量,然后在每个像素处应用Phong着色,可以减少这些问题。这允许您在不将三角面修改的很小的的情况下获得良好的渲染效果。

回想第3章,当光栅化三角形时,我们计算重心坐标\left ( \alpha ,\beta ,\gamma \right )来插值顶点颜色c_{0}c_{1}c_{2}

c = \alpha c_{0} +\beta c_{1} +\gamma c_{2}

我们可以使用相同的方程来插值曲面法线n_{0}n_{1}n_{2}

c = \alpha n_{0} +\beta n_{1} +\gamma n_{2}

然后可以使用在每个像素处计算的法向n来计算等式(10.9)。注意,由方程式(10.11)得出的n通常不是单位法向。如果在用于着色计算之前将其转换为单位向量,将获得更好的视觉效果。这种类型的法线插值通常称为Phong法线插值(Phong,1975)。

10.3 艺术着色

Lambert着色和Phong着色方法基于启发式方法,旨在模拟真实世界中对象的外观。艺术着色的设计是模仿人类艺术家的绘画。这种着色在许多应用中似乎都有优势。例如,汽车制造商雇佣艺术家为车主手册绘制图表。这比使用“真实”的照片要昂贵得多,因此当需要某些类型的渲染结果时,艺术家的技术可能有一些固有的优势。在本节中,我们将展示如何使微妙的着色线条画让人想起人类绘制的图像。创建这样的图像通常称为非照片级真实感渲染,但我们将避免使用该术语,因为许多非照片级真实感技术用于与任何艺术实践无关的应用中。

10.3.1 线绘制

我们在人类绘画中看到的最明显的东西,是在现实生活中看不到的剪影。当我们有一组共享边的三角形时,当共享边的两个三角形中的一个朝向观察者,而另一个三角形远离观察者时,我们应该绘制一条边作为轮廓。这种情况可通过测试两个三角面的法向n_{1}n_{1}来进行判断:

如果:

\left ( e\cdot n_{0} \right ) \left ( e\cdot n_{1} \right ) \le 0

则绘制边。

其中e是从边到眼睛的向量。这可以是边上的任意点,也可以是任意一个三角形。或者,如果f_{i} (p)=0是两个三角形的隐式平面方程,则可以改写为:

f_{0} (e)f_{1} (e)\le 0

我们还希望绘制多边形模型的可见边。要做到这一点,我们可以使用第12章中的任何一种隐藏曲面方法绘制背景色,然后以黑色绘制每个三角形的轮廓。事实上,这也将捕捉轮廓。不幸的是,如果多边形代表一个平滑的曲面,我们真的不想绘制部分的边。但是,我们可能希望在几何体中确实有一个角的位置绘制所有折痕。我们可以使用设置阈值用于绘制折痕:

\left ( n_{0}\cdot n_{1} \right ) \le threshold

在这种情况下绘制折痕。这与轮廓测试相结合,将得到好看的线条图。

10.3.2 冷色到暖色着色

当艺术家给线条画着色时,他们通常使用低强度着色,以给表面留下一些曲线的印象,然后为对象绘制颜色。朝向一个方向的曲面将使用冷颜色(如蓝色)进行着色,而朝向相反方向的曲面将使用暖颜色(如橙色)进行着色。通常这些颜色不是很饱和,也不是很暗。这样,黑色的轮廓就很好地展现出来了。总的来说,这给了一个卡通般的效果。这可以通过设置“温暖”灯光l的方向并使用余弦调制颜色来实现,其中温暖系数k_{w}\left [ 0,1 \right ]上范围内:

k_{w}=\frac{1+n\cdot l}{2}

然后,颜色c只是冷色c_{c}和暖色c_{w}的线性混合:

c= k_{w}c_{w}+(1-k_{w})c_{c}

有许多可能的c_{w}c_c将产生合理的外观结果,比较好的颜色设置是:

\begin{array}{c}
c_{w}=\left ( 0.4,0.4,0.7 \right ) \\
c_{c}=\left ( 0.8,0.6,0.6 \right )
\end{array}

图10.9显示了传统Phong着色和这种艺术着色之间的比较效果。

常见问题

  • 这一章中所有的阴影看起来都是巨大的缺陷。这是真的吗?

对。然而,它们是经过精心设计的,在实践中证明是有用的。从长远来看,我们可能会有更好的动机算法,包括物理、心理学和色调映射。然而,图像质量的改善可能是渐进的。

  • 我不想调用pow函数。在进行Phong着色时有没有办法避免这种情况?

一个简单的方法是,只有指数本身是二的幂,即2,4,8,16。实际上,对于大多数应用程序来说,这并不是一个有问题的限制。也可以使用查找表,但通常不会提供很大的加速。