开篇
当我们渲染三维场景的图像时,不管是使用光线追踪或者光栅化方法,以实时或者批处理进行,一个贡献于立体感的视觉印象的关键就是基于表面形状以及它们与在场景中的其它物体的关系进行着色。在物理世界中,我们所看到的绝大多数光都是反射光,而光反射的物理会被几何极大地影响,这就产生了多种多样的能被人的视觉系统有效地利用的提示来理解形状。
在计算机图形中,着色的目的就是为了给人的视觉系统提供那样的提示,尽管目标可能会因为应用场景不同。在计算机辅助设计或者科学可视化中,目标就是清晰度,着色应该被设计成能提供最清晰和最准确的三维形状印象。在另一方面的视觉效果或者广告中,目标是为了使渲染的结果与真实物体的外表之间的相似度最大化。在动画、虚拟环境、游戏中,目标在上述两者之间,着色要达到艺术的目的,这就包括描绘形状以及材质,但是又不至于从字面上复刻现实。
用于计算着色的等式叫着色模型(Shading Model),有非常多的着色模型已经被开发来用于不同的应用场景。通常的来说,它们都从那种能提供*似光反射的物理的简单模型开始。以这种模型为出发点,额外的特性可以被添加,从而接*真实渲染的物理,或者有些部分可以被修改或省略来让模型适用于更加抽象的风格。
着色模型其实很独立于渲染系统的其它部分,相同的着色模型可以被用于光线追踪或者光栅化系统中。这章描述了一个基础的模型来渲染被点光源照射的不透明表面。这个模型对于简单的应用来说很合适,这也是后面要讲的高级着色计算的起点。
点状光源(Point-like light sources)
在现实世界中,光会从所有方向落到表面上。但是对于建模光照来说,最简单的情况就是光从一个方向来的时候,当然这总是一个理想化的情况,但是可以使用它来创造一个对体积小的光源和距离远的光源有用的模型。点状光源有两种,第一种是点光源(Point Source),它小到足够能把它看成一个点,但是又位于场景中可以点亮不同的表面。第二种是定向光(Directional Source),它距离场景很远,大小相对于距离来说很小,因此也可以被看作点状光源,不过由于太远了,一般只关心它的方向。闪光灯和太阳就是上述两种光源的典型例子。
点光源光照(Point source illumination)
点光源是通过在三维空间的位置以及强度描述的,这里的强度指的是点光源能发出多少量的光。一个点光源可以是各向同性的(Isotropic),这意味着这种点光源会向四周均匀辐射能量,这通常也是一种默认情况。许多系统提供聚光灯光源,这种特殊点光源只向某些方向辐射能量,它可以像真实的舞台那样控制聚光灯来控制虚拟场景中的光照。
对于各向同性的点光源,我们应该关心有多少光会落到一定距离的表面上,假设我们有各向同性点光源,它以1瓦的功率辐射光线,当使用半径1米的薄球壳来捕获光线时,它辐射的能量应该会在薄球壳上均匀分布。总的面积是\(4\pi\,\mathrm{m}^2\),所以捕获的能量密度应该是\(1/(4\pi)\)瓦每*方米,这个密度叫做辐照度(Irradiance),它是正确的量来描述有多少光落到了表面上。因此任意距离的辐照度\(E\)应该是
\[E=\frac{P}{4\pi}\frac{1}{r^2}=\frac{I}{r^2}\]
公式里的\(I=P/(4\pi)\),它是光源的强度,和被照射的表面无关。而\(r^{-2}\)这一*方反比因子决定了辐照度会怎么随半径变化。
另一个计算辐照度的重要考量是入射角(Angle Of Incidence),它是光照方向和表面法线之间的夹角。首先想象一个小的表面正在被距离比较远的点光源照射,由于距离比较远因此各个位置上的光线方向*乎*行。假设表面刚开始是水*状态,接着我们使表面旋转一定角度,如下图所示。
这个时候发现表面接收到的光线的量减少了,因此表面上的辐照度减少了。经过计算后得出表面上的辐照度应该乘以\(\cos\theta\)。当入射角增大时,表面的辐照度随着入射角的余弦值减少的规则就叫做朗伯余弦定律(Lambert's cosine law)。把入射角考虑到一起,公式就变成了
\[E=I\frac{\cos\theta}{r^2}\]
其中\(\cos\theta/r^2\)可以被称为对于点光源来说的几何因子(Geometry Factor),它取决于光源和接受照射的表面的几何关系。
在实践中我们一般不需要\(\theta\)角而是它的余弦值,如果我们有单位法线\(\mathbf{n}\)和单位光线入射方向\(\mathbf{l}\),这个时候可以直接通过点乘计算余弦值,因此有
\[\cos\theta = \mathbf{n}\cdot\mathbf{l}\]
定向光照(Directional Illumination)
定向光仅仅指的是那些距离远但是又非常亮的光源,当光源越来越远时\(I/r^2\)会趋向于定值,因此我们直接用常量替代它,所以
\[E=H\cos\theta\]
这个常量可以被叫做法向辐照度(Normal Irradiance),定向光源是以入射方向还有法向辐照度\(H\)为特征的,它的光照和距离无关。
基础的反射模型(Basic reflection models)
现在我们已经有能力计算辐照度,它描述了有多少光落到了一个物体上,我们接下来要讨论物体是如何反射光的。这实际上取决于物体的材质是怎样的,我们接下来为有色的材质开发一个基础模型,并且支持光滑的表面。这个模型的想法可以由下图所示
材质可以有一个基层来决定物体的整体颜色,而且它还可以有一个表面提供镜子式的反射,我们接下来讨论下这两者的最简单的模型。
朗伯反射(Lambertian reflection)
最简单类型的反射就是不管光是从哪里来的,表面都会均匀地向法线方向的半球反射光线。我们令被反射的光线为\(L_r\),因此
\[L_r =kE\]
一个这么表现的表面被称为一个理想漫反射(Ideal Diffuse)表面,观察到的颜色和视点无关,是用表面的反射率(Reflectance)\(R\)描述的,它指代的是反射的那部分的辐照度。公式里的反射系数\(k=R/\pi\),因此
\[L_r=\frac{R}{\pi}E\]
不过对于不同颜色的光,反射率可以是不同的,因此可以使用三个不同的反射率,分别为红光、绿光、蓝光的反射率。这样的话着色公式就能分别处理红、绿、蓝三通道的值。
理想漫反射着色通常叫朗伯着色因为朗伯余弦定律是这种着色模型的主要影响因素。从物理方面来说,这种着色模型建模光线在物体内不断弹射,因此“忘记”它从哪来了,从而向随机方向射出。这种模型对模拟纸张、*光涂料、泥土以及别的粗糙的无法产生显眼的光滑反射的表面来说很有用。
镜面反射(Specular reflection)
许多材质都有一定的光滑程度,例如金属、塑料、植物的叶子等等。当你看着这些材质时,你会看到反射会随着视点移动而移动,你会描述它们的颜色和视点有关,这和朗伯表面恰恰相反。和视点有关部分的反射通常发生在材质的上表面,这部分反射叫做镜面反射(Specular Reflection)。
最简单类型的镜面反射发生在完美*滑的表面,例如镜子和水面。从一个方向进来的光线只会从另一个方向射出,这被称为理想镜面反射,而且会被当作一种特殊情况处理。但是很多表面都不是完美*滑的,这些表面展现了一种更加通常的反射,这在计算机图形中被称作*滑反射(Glossy Reflection)。有很多模型用于*滑反射,在十四章有更好的一个模型,不过我们先用一个简单且著名的模型,它由Phong提出被Blinn和其它人所更新,形成了一种今天最常用的模型,叫改进的Blinn-Phong模型。
因为镜面反射和视点有关,所以它的函数和观察向量(View Vector)有关,当然了也和法线\(\mathbf{n}\)还有光照方向\(\mathbf{l}\)有关。镜面反射函数的想法就是当\(\mathbf{v}\)和\(\mathbf{l}\)关于表面法线对称时,创造最亮的反射,当两个向量逐渐远离对称状态时反射会*滑地变小。
我们可以先计算光照方向\(\mathbf{l}\)和观察方向\(\mathbf{v}\)之间的半程向量\(\mathbf{h}\),然后计算半程向量与法线的点积,这样我们就能知道\(\mathbf{v}\)和\(\mathbf{l}\)关于\(\mathbf{n}\)的对称度。不过我们应该让镜面反射衰减得更快来让看到的高光只在小区域内出现,因此我们还需要指数\(p\)。公式最终变成了
\[\mathrm{max}(0,\mathbf{n}\cdot\mathbf{h})^p\]
\[\mathbf{h}=\frac{\mathbf{l}+\mathbf{v}}{||\mathbf{l}+\mathbf{v}||}\]
公式中的指数\(p\)控制着表观光滑度,更高的值会让反射更快地衰减,导致了更加闪亮的外表。然后我们还可以用\(k_s\)来控制反射颜色,和朗伯反射部分的反射率\(R\)一样,储存三个值分别处理红、绿、蓝三通道。因此公式变成了
\[k_s\mathrm{max}(0,\mathbf{n}\cdot\mathbf{h})^p\]
模型整合
把上面两个部分的模型结合起来,我们可以得到这样一个基础模型
\[L_r=(\frac{R}{\pi}+k_s\mathrm{max}(0,\mathbf{n}\cdot\mathbf{h})^{p})E\]
这个模型的\(\frac{R}{\pi}+k_s\mathrm{max}(0,\mathbf{n}\cdot\mathbf{h})^{p}\)部分叫双向反射分布函数(BRDF——Bidirectional Reflectance Distribution Function),因为它描述了反射率是怎么随\(\mathbf{l}\)和\(\mathbf{v}\)变化的,朗伯表面的BRDF值为常量,而有镜面反射的表面的BRDF值不是。使用这个模型的着色计算变成了先计算辐照度部分和计算BRDF值部分,接着把这两个部分相乘。
计算着色(Calculating shading)
当实现表面着色时,代码需要读取光源、表面、观察方向的信息,而且需要写简洁的代码支持点光源和定向光。辐照度取决于光源和表面几何,一旦计算出来了辐照度,计算的剩下部分就只依赖于表面属性和观察几何。
基础的着色计算可以在光线追踪和光栅化系统中以相同方式做到,只是输入数据的计算不同。为了计算辐照度我们需要
- 着色点\(\mathbf{x}\):表面上的三维点
- 表面法线\(\mathbf{n}\):垂直于着色点处的表面
- 光源几何:点光源的位置\(\mathbf{p}\)或定向光的方向\(\mathbf{l}\)
- 光源强度:点光源的强度\(I\)或定向光的法向辐照度\(H\)
对于点光源,我们需要计算距离和光照方向
\[r = || \mathbf{p}-\mathbf{x} ||\]
\[\mathbf{l} = \frac{\mathbf{p}-\mathbf{x}}{r} \]
对于两种类型的光源我们需要计算余弦值
\[\cos\theta=\mathbf{n}\cdot\mathbf{l}\]
当然了我们还要防止余弦值为负数的情况,综合上述信息,两种光源的辐照度计算公式分别
\[\mathrm{(点光源)}\quad E = \frac{\mathrm{max}(0,\mathbf{n}\cdot\mathbf{l})}{r^2}\]
\[\mathrm{(定向光)}\quad E = \mathrm{max}(0,\mathbf{n}\cdot\mathbf{l})H\]
一旦辐照度已知,接下来要做的是乘以BRDF值,计算BRDF值需要的是
- 光照方向\(\mathbf{l}\)
- 观察方向\(\mathbf{v}\)
- 表面属性:比如这个章节中的\(R\)、\(k_s\)、\(p\)
计算着色要注意的是\(\mathbf{l}\)、\(\mathbf{v}\)、\(\mathbf{n}\)必须为单位向量,否则会导致一些常见的错误。
环境光照(Ambient illumination)
点状光源是非常局部化的光源,能在某一方向上产生大量光。其它类型的光源则没有那么局部化,例如天空还有从墙上反射的光。虽然这种扩展类型的光源可以被详细地建模,但是对于基础的着色我们只需要简单的*似,所以我们做几个简单的假设,让场景中每个位置受到的环境光(Ambient Light)强度一样,并且环境光会被表面均匀地向四周反射,接着我们引入环境光反射系数\(k_a\),因此可以这么计算环境光照
\[L_r=k_aI_a\]
环境光强\(I_a\)和环境光反射系数\(k_a\)都是用三个值来存储,分别处理红、绿、蓝三通道的值。许多系统把环境光当作一种光源和点光源还有定向光一样出现在列表中,而其它的系统让环境光强度作为场景的参数存在。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |