To make objects appear to have more volume, it can help to use shading, i.e., the surface is “painted” with light. This chapter presents the most common heuristic shading methods.
为了使物体看起来有更多的面,我们可以使用阴影。即:表面是用光“绘制”的。本章介绍最常见的启发式着色方法。
Diffuse Shading
世界上许多物体的表面外观是“哑光”(matte)的,这表明该物体根本没有光泽。例如,纸张。这样的物体的颜色不会随着视角的变化而发生变化。
Such matte objects can be considered as behaving as Lambertian objects.
这种哑光物体可以被认为是朗伯对象。本章讨论的就是 shading of such objects
key:本章所有公式都应在世界坐标中计算,而不是在透视变换后的坐标中计算。否则,法线之间的角度会改变,阴影将是不准确的。
Lambertian Shading Model
一个Lambertian物体是遵循 Lambert’s cosine law的。该定律表示:物体表面的颜色c 正比于
物体表面法线与光照方向夹角的余弦值 θ\thetaθ (如图10.1)
当物体表面法线 n 和 光照方向 I 都是单位向量的时候,该正比关系可以描述成:
所以物体的颜色就会因这个θ\thetaθ角的不同而不同。通常假设光照方向 I与物体的位置没有关系。其相当于假设光相对于物体的大小来说是“遥远的”。这种“远距离”的光通常被称为定向光(directional light),因为它的位置仅由一个方向来确定(即光源的方向,与物体位置方向无关)
物体表面的明暗是由光照强度和物体表面反射光的多少决定的。漫反射系数crc_rcr?(reflectance)是被表面反射的光的比例。对于不同的颜色成分这个反射光的比例也不同,就像红色表面的物体,其反射红色比反射蓝色要多的多。若假设物体表面颜色正比于反射的光,那么则有:
该式子右边是一个RGB颜色,所有的RGB分量都在[0,1]范围内。上面说光照强度也是一个影响因素,若我们想添加上这个光照强度,并且不改变RGB分量都在[0,1]范围内,我们就可以增加一个本身的分量在[0,1]范围内的RGB强度项:clc_lcl?(light)
上面这个式子有一个bug, 点乘(dot product)可能是一个负值(因为cos在二三象限的时候为负值,即角度为(90-270)之间时)。如下图:即物体背对着光源的那一面
所以有两种方法处理:
- c=crclmax(0,n?l)c = c_r c_l max(0,n * l)c=cr?cl?max(0,n?l) (1)
- c=crcl∣n?l∣c = c_r c_l | n * l |c=cr?cl?∣n?l∣ (2) (这个式子等同于使用两个具有相同颜色但是相对的光源 —— 双面照明)
Ambient Shading
上面漫反射 shading 的一个问题是:任意一个法线远离光照方向的点都将是黑色的。但是在真实世界中,光会四面八方的反射。There is often skylight giving “ambient” lighting。所以即使背对着光源我们也可以通过环境反射来看到一些物体。
解决这个问题的方法: 1. 是使用多个光源。一个常见的技巧是总是在眼睛处放一个昏暗的光源,这样所有可见的点都会收到一些光。
2. 是使用上面所描述的双面照明。但更常见的是添加一个常量颜色项:
c=cr(ca+clmax(0,n?l))c = c_r ( c_a + c_l max(0,n * l) )c=cr?(ca?+cl?max(0,n?l))
这个cac_aca?是场景中所有表面的平均颜色。If you want to ensure that the computed RGB color stays in the range [0, 1]3, then ca+clc_a + c_lca?+cl? ≤ (1, 1, 1). Otherwise your code should “clamp” RGB values above one to have the value one.
Vertex-Based Diffuse Shading
我们通常使用三角形来近似一个光滑的表面。当我们使用表面法线来进行着色的时候,很可能表面就不那么平滑了。所以我们考虑使用顶点法线。然后在每个顶点上使用公式:c=crclmax(0,n?l)c = c_r c_l max(0,n * l)c=cr?cl?max(0,n?l) 。这样每个三角形顶点就会着上一个颜色,并且这个颜色可以进行重心插值。
计算三角形顶点法线的一个最简单的方法是:对共享每个顶点的三角形的法线取平均值,并在顶点处使用这个平均值。需要注意的是:在使用它做为shading之前,要将它转换成单位向量。(因为最后计算中光的方向一般为单位向量,所以平面法向量也为单位向量,那么cos的值可以直接通过dot(LightDirection,normal)来求得。)
Phong Shading
有些表面其本质上是哑光表面,但是它们有highlights。如:抛光瓷砖地板,有光泽的油漆和白板等等。这这些物体上,highlights随着视角的移动而在表面上移动。这意味着我们必须在式子里加入一个朝向眼睛的单位向量e。
这些highlights其实是光的反射,光是什么颜色,highlights就是什么颜色,与物体表面的颜色无关。(原因是:这种高光的反射是发生在物体表面。而前文的漫反射是穿透物体表面的光,这种光才能捕捉到物体的颜色)
Phong Lighting Model (specular)
We want to add a fuzzy “spot” the same color as the light source in the right place. The center of the dot should be drawn where the direction e to the eye “lines” up with the natural direction of reflection r
这里的高光,其实就是视角方向所对应的单位向量e 与光自然反射的方向r对齐,即眼睛看向的是光反射的方向,如图所示:
除了视角方向正好在光反射方向上之外,我们还希望高光有一些别的区域,以便眼睛在σ很小的地方看到一些高光。
给定光的反射向量r,我们想要一个启发式函数完成如下操作:当e = r时,有高光,当e远离r时,高光逐渐减弱
一个比较简单的方法是使用e 和 r之间夹角的余弦值:
c=cl(e?r)c = c_l (e * r)c=cl?(e?r)
使用这个式子有两个问题:
- 点乘有可能为负值。这个可以借鉴上面的方法:在点积为负时将颜色设置为零
- 这个式子产生的高光比现实生活中看到的范围要广得多。其最大值是在正确的地方,它是正确的颜色,但它就是太大了。我们可以在不减少其最大颜色的情况下缩小它:
c=clmax(0,e?r)pc = c_l max (0, e * r)^pc=cl?max(0,e?r)p
这里p被叫作Phong exponent,它是一个正实数。改变Phong指数在高亮显示上的效果如图所示:
c=clmax(0,e?r)pc = c_l max (0, e * r)^pc=cl?max(0,e?r)p,这个式子中,需要计算单位向量r。r是光照的反射方向的单位向量。如图:
r可以计算成:r=?l+2(l?n)nr = -l + 2(l * n)nr=?l+2(l?n)n
式子的推导如下:
另一种基于c=clmax(0,e?r)pc = c_l max (0, e * r)^pc=cl?max(0,e?r)p的启发式模型消除了检查e?re * re?r是否为负值的需要。其不计算r,而是计算l和e中间的半程单位向量h,如图所示:
h=e+l∣∣e+l∣∣h = \frac{e + l} {||e + l || }h=∣∣e+l∣∣e+l?
当h接近n,即cos ω = h·n接近1时的时候高光出现。 因此: c=cl(h?n)pc = c_l(h * n)^pc=cl?(h?n)p
什么是半程向量呢?顾名思义,半程向量就是两个向量的角平分线所在方向,方向和两个向量之和的方向一致。
那么为什么可以作这样的等价呢?我们知道,平面的法线就是l和 r的半程向量,所以当r和 e足够接近时,法线方向n 和半程向量h也会足够接近。我们可以用两个向量的点乘表达它们的接近程度,这是因为对于方向向量来说,它们的点乘等于它们夹角的余弦,即n · h = cosθ\thetaθ ,当θ\thetaθ足够小,也就是两个向量足够接近时, n · h 趋近于1 。
使用n和h之间的余弦,优点是:对于平面上的眼睛和光线,余弦总是正的。缺点是:需要平方根和除法来计算 h。
结合前面的高光,我们可以得出:
我们想让用户调暗高光,我们可以添加一个控制项cpc_pcp?:
cpc_pcp?是RGB颜色,它允许我们改变高光颜色。当cp=crc_p = c_rcp?=cr?时,对金属很有用,因为金属上的高光显示出金属的颜色。另外,将cpc_pcp?设为小于1的中性值通常是有用的,这样颜色就会保持在1以下。例如,设置cpc_pcp? = 1?M,其中M是crc_rcr?的最大组成部分,将保持一个光源的颜色低于1,没有环境项。
Surface Normal Vector Interpolation
对比于Lambertian表面,具有高光的平滑表面颜色变化会更快。因此,在法向量上的阴影可以产生干扰的伪影(artifact)。
这个问题可以通过这种方法解决:在多边形上插值法向量,然后在每一个像素上应用Phong shading
在光栅化一个三角形时,我们计算重心坐标(α, β, γ)来插值顶点颜色c0, c1, c2:
c=αc0+βc1+γc2c = \alpha c_0 + \beta c_1 + \gamma c_2c=αc0?+βc1?+γc2?
我们可以使用相同的方法来插值表面法线n0n_0n0?, n1n_1n1?和n2n_2n2?:
n=αn0+βn1+γn2n = \alpha n_0 + \beta n_1 + \gamma n_2n=αn0?+βn1?+γn2?
然后对每个像素处应用公式:c=cr(ca+clmax(0,n?l))+clcp(h?n)pc = c_r (c_a + c_lmax(0, n·l)) + c_lc_p(h·n)^pc=cr?(ca?+cl?max(0,n?l))+cl?cp?(h?n)p 需要注意的是,插值得到的法向量往往不是单位向量,所以在使用公式进行shading之前,要将其化成单位向量。
这种类型的法向插值通常被称为Phong法向插值
Artistic Shading (这个自己用的比较少,就粗略看一下)
Lambertian和Phong阴影方法是基于启发式设计来模仿真实世界中物体的外观。Artistic Shading是为了模仿人类艺术家的绘画而设计的。
In this section, we show how to make subtly shaded line drawings reminiscent of human-drawn images. Creating such images is often called non-photorealistic rendering, but we will avoid that term because many non-photorealistic techniques are used for efficiency that are not related to any artistic practice.
在本节中,我们将展示如何制作巧妙的阴影线图纸,让人想起人类绘制的图像。创建这样的图像通常被称为非真实感渲染,但我们将避免使用这个术语,因为许多非真实感技术用于提高效率,与任何艺术实践无关。
Line Drawing
我们在人类绘画中看到的最明显的东西是我们在现实生活中看不到的剪影(silhouettes)。如下图茶壶的这两个大黑边
当我们有一组共享边的三角形时,当共享边的两个三角形中的一个面向观看者,而另一个面向远离观看者时,我们应该画一条边作为silhouettes。即对于两个法线n1和n2n_1 和 n_2n1?和n2?:
e是一个从edge到眼睛的向量。若fi(p)=0f_i(p) = 0fi?(p)=0是这两个三角形的隐式平面方程,则上式可以写成:
We would also like to draw visible edges of a polygonal model. To do this, we can use either of the hidden surface methods of Chapter 12 for drawing in the background color and then draw the outlines of each triangle in black. This, in fact, will also capture the silhouettes. Unfortunately, if the polygons represent a smooth surface, we really don’t want to draw most of those edges. However, we might want to draw all creases where there really is a corner in the geometry. We can test for creases by using a heuristic threshold:
我们还想绘制多边形模型的可见边缘。为了做到这一点,我们可以使用第12章中的任何一种隐面方法来绘制背景色,然后用黑色绘制每个三角形的轮廓。事实上,这也将捕捉到轮廓。不幸的是,如果多边形代表一个光滑的表面,我们真的不想画大部分的边。然而,我们可能想要画出所有的折痕,那里确实有一个角落的几何。我们可以使用启发式阈值来测试折痕:
将其与上面的silhouette相结合,将会画出很漂亮的画~
Cool - to - Warm Shading
当艺术家给线条画上阴影时,朝一个方向的表面用冷色阴影,如蓝色,朝相反方向的表面用暖色阴影,如橙色。通常这些颜色不是很饱和,也不是很暗。这样,黑色的轮廓就能很好地展现出来。总的来说,这给了一个卡通般的效果。通过设置一个方向l指向暖光,并用余弦来调制颜色,可以实现这种效果。其中暖常数kwk_wkw?定义在[0,1]:
颜色c是冷色ccc_ccc?和暖色cwc_wcw?的线性混合:
冷色ccc_ccc?和暖色cwc_wcw?的初值通常设置为:
几种模型着色的对比,如图所示:
Exercises:
The moon is poorly approximated by diffuse or Phong shading. What ob- servations tell you that this is true?
Velvet is poorly approximated by diffuse or Phong shading. What observa- tions tell you that this is true?
Because diffuse and Phong shading are not particularly good representations of the rich variety of interactions with light.
In particular, the full moon is more than twice as bright as the first or third quarter moon, even though the area is exactly twice as large. This effect is called “opposition surge”.
Velvet has a complex surface reflectance as well, since it is made up of many small hairs, each of which have a specular response, and which can display some anisotropy based upon how the velvet is brushed.
BRDFs (bidirectional reflectance distribution functions) may be worked.
Why do most highlights on plastic objects look white, while those on gold metal look gold?
All specular reflection is due to Fresnel reflection at the interface which is a broadband effect.
The highlight is almost always white since it is a broadband reflection of the light source.
Due to the interband transition in gold, green and blue light gets strongly absorbed, biasing the reflected spectrum toward yellow and red.
Highlights that you might see reflected from dielectrics are white because dielectrics are relatively dispersionless (i.e. the refractive index is more-or-less independent of color) throughout the visible range. Gold is decidedly not dispersionless in the visible.
参考资料:
- https://cs184.eecs.berkeley.edu/sp21/readings (Lecture 6: Rasterization Pipeline (+Visibility and Shading))
- Shirley et al., Chapter 18, recall Chapter 8.1-8.3, Chapter 10.