最爱午后红茶

Illumination

日期图标
2023-05-25

在我们的真实世界中,每个不同的物体都有它们各自的颜色,而我们人眼看到的物体的颜色跟物体本身的颜色是有所区别的,最终的效果会受到光源、物体材质、环境、视角等因素的影响。在计算机图形里面,我们也需要考虑各种因素的影响以渲染出尽可能逼真的效果。

计算机渲染的图像
图一:计算机渲染的图像

我们通过光栅化可以把三维空间中的物体绘制到了二维的屏幕上,那么在实际应用中每个像素对应的颜色是如何确定的呢?先看看不进行着色的效果:

纯色立方体
图二:纯色立方体
着色立方体
图三:着色立方体

可以看到着色之后的物体有了光照阴影的效果。而且随着物体的运动,颜色也发生相应的变化,看起来更加真实。在计算机图形学中,着色Shading)是指根据光照和材质(比如金属或木头)等因素对三维模型表面进行颜色处理的过程。其基本目的是使得三维模型在渲染后可以看起来更加真实,并给人以立体感。在这门课里面,闫老师把着色定义为:对不同物体应用不同材质的过程

Blinn-Phong Reflectance Model

在 Blinn-Phong 光照模型中我们把光照下的物体分成三个部分:

  • 高光(Specular highlights)
  • 漫反射(Diffuse reflection)
  • 环境光(Ambient lighting)
光照下的物体
图四:光照下的物体

Shading point

我们可以理解光照是作用在物体表面某个点上(称为 Shading point),在足够小的范围里面,表面可以被认为是某个单位平面。接着我们需要定义一些着色需要用到的概念:

  • 曲面法线(Surface normal):垂直于平面的方向(单位向量 n\overrightarrow{n}
  • 观测方向(Viewer direction):Shading point -> 人眼(或相机)的方向(单位向量 v\overrightarrow{v}
  • 光照方向(Light direction):光源 -> Shading point 的方向(单位向量 l\overrightarrow{l}
  • 物体表面参数:颜色,亮度等
Shading point
图五:Shading point

需要注意的是,这里我们所说的着色并没有考虑 Shading point 在阴影内的情况。阴影的生成后续再说。

漫反射(Diffuse reflection)

漫反射是指当光线打到物体表明时,会被反射到各个方向。同样的光照在相同的物体表面上,明暗有可能会不一样(如前面图三),这跟物体表面接收到多少能量有关。而当我们说一个 Shading point 的能量,通常指的是它周围的一个单位面积接收到的能量。如下图所示,假设光是离散的,每根光线代表相同的能量:

物体表面接收的能量
图六:物体表面接收的能量

直观上我们就可以看到,光照方向和法线之间的夹角决定了明暗程度(也即 Shading point 漫反射部分的能量大小)。进一步分析可以知道,能量大小跟法线和光照方向的余弦值(cosθ=lncos{\theta} = \overrightarrow{l}\cdot\overrightarrow{n}成正比

接着我们简单补充下光的辐射相关的知识。如下图七,假设点光源时刻往各个方向辐射能量,并且能量随着扩散距离变长而减弱。跟点光源单位距离的球面上某个点上的能量为 II(这样表示能量强度其实并不合理,这里可以先这么认为)。则点光源扩散到单位距离的球面上的总能量(假设球面上每个点获得的能量是均匀的)为 P=4πIP = 4\pi I(球面积公式为 S=4πR2S = 4\pi R^2,此时半径 RR = 单位距离 = 1).

光的能量扩散

图七:光的能量扩散(过球心切面图)

假设点光源扩散到 rr 处球面某个点的能量为 II',假设能量是守恒的,则 rr 处球面的能量等于单位距离处的球面能量:

  • 4πI=4πr2I4\pi I = 4\pi r^{2}I'

则我们可以得到 I=I/r2I' = I/r^2。也就是说 Shading point(或者说它周围的单位面积)在任何一个位置所能接收到的能量,跟光线传播的距离成平方反比

有了以上的知识做前提,我们理解 Shading point 经过漫反射的公式就不难了:

  • Ld=kd(I/r2)max(0,nl)L_d = k_{d}(I/r^2)max(0, \overrightarrow{n}\cdot\overrightarrow{l})

也就是 Shading point 经过漫反射后的能量等于到达该点的能量(I/r2I/r^2)乘上被表面吸收的能量比例(nl\overrightarrow{n}\cdot\overrightarrow{l}),再乘上物体本身的漫反射系数kdk_d)。

  • 如果 nl\overrightarrow{n}\cdot\overrightarrow{l} 为负数,则相当于从物体内部射出光线,没有物理意义,因此最小取 0.
  • 物体本身的性质决定它会吸收多少能量
    • kd=1k_d = 1:物体不吸收能量
    • kd=0k_d = 0:物体吸收所有能量

这里我们注意整个计算过程都没有观测方向参与,也就是说观测方向并不会影响漫反射的结果。

高光(Specular highlights)

光线打在接近光滑的表面上会发生镜面反射(反射方向与法线夹角等于入射方向与法线夹角)。当观测方向跟反射方向足够接近的时候,我们就能看到高光。

高光(Specular highlights)
图八:高光

如上图八,我们要判断能否看到高光,需要判断 R\overrightarrow{R}v\overrightarrow{v} 有多接近。在实际应用中,反射方向的计算有些复杂,因此在 Blinn-Phong 模型里面,采用了另一种能达到相同效果的方法:计算半程向量跟法线的接近程度。

半程向量(Half vector)
图九:半程向量

半程向量位于入射方向和观察方向的中间位置,它的单位向量非常好计算:

  • h=bisector(v,l)=v+lv+l\overrightarrow{h} = bisector(\overrightarrow{v}, \overrightarrow{l}) = \frac{\overrightarrow{v} + \overrightarrow{l}}{\lVert{\overrightarrow{v} + \overrightarrow{l}}\rVert}

如上图九,仔细观察我们可以发现,反射方向和观测方向越接近,半程向量和法线之间的夹角 α\alpha 就越小,即这两个向量也就越接近。而我们在 Vectors 中关于点乘的部分里面分析了向量点乘结果可以判断两个向量的接近程度。因此,高光能量的公式可以写成如下表达式:

  • Ls=ks(I/r2)max(0,cosα)p=ks(I/r2)max(0,nh)pL_s = k_{s}(I/r^2)max(0, cos{\alpha})^p = k_{s}(I/r^2)max(0, \overrightarrow{n}\cdot\overrightarrow{h})^p
    • ksk_s:镜面反射系数,通常表现为白色
    • I/r2I/r^2:到达该 Shading point 的能量(由前面漫反射的知识可知)
    • nh\overrightarrow{n}\cdot\overrightarrow{h}:两个向量方向越接近,点乘的结果越接近 1
    • pp:控制高光有多大

这里需要注意的是,LsL_s 的计算并没有考虑漫反射部分的能量,在实际应用中应该加上漫反射部分。这里还需要解释的是指数 pp 的作用。如下图十,如果我们没有指数 pp(或者说 p=1p = 1),那 α\alpha 的角度在增大的过程中,高光范围的变化是接近均匀的。这不符合现实中的情况,因此需要增加一个系数进行控制,使其在 α\alpha 角度变化时能更接近真实情况,实际应用中通常 p>100p > 100

指数 p 控制高光
图十:指数 p 控制高光

一个具体的示例(加上了高光和漫反射的能量):

高光加上漫反射的能量
图十一:高光加上漫反射的能量

环境光照(Ambient lighting)

环境光照就是物体接收到来自四面八方的光线(非光源的直接光照)然后反射进入人眼(或相机)。环境光的作用就是让你可以看到物体本来的颜色,而不至于看到没有光源照射到的部分是全黑的。实际应用中的环境光非常复杂,在后续讲全局光照的内容时再展开说。这里可以假设到达 Shading point 的环境光能量都是相同的。

有了前面的假设,我们很容易得出环境光的能量公式:

  • La=kaIaL_a = k_{a}I_{a}
    • kak_a:环境光系数
    • IaI_a:到达 Shading point 的环境光能量

我们可以发现环境光的能量跟光源入射方向、观测方向、法线等变量都没有关系,而且根据上式可以把 Blinn-Phong 模型中的环境光理解为常数。

所以,整个 Blinn-Phong 模型里面把高光、漫反射和环境光进行叠加,可以得到一个较为真实的模型(对三维物体所有 Shading point 着色):

叠加三种光的 Blinn-Phong 模型(Blinn phong)

图十二:叠加三种光的 Blinn-Phong 模型

对应的公式为:

  • L=La+Ld+Ls=kaIa+kd(I/r2)max(0,nl)+ks(I/r2)max(0,nh)pL = L_a + L_d + L_s = k_{a}I_{a} + k_{d}(I/r^2)max(0, \overrightarrow{n}\cdot\overrightarrow{l}) + k_{s}(I/r^2)max(0, \overrightarrow{n}\cdot\overrightarrow{h})^p
* 未经同意不得转载。