未来雨 發表於 2025-5-29 01:33:00

《Fundamentals of Computer Graphics》第五章 表面着色

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


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:TiredInkRaven,转载请注明原文链接:https://www.cnblogs.com/TiredInkRaven/p/18896208</p><br><br>
来源:https://www.cnblogs.com/TiredInkRaven/p/18896208
頁: [1]
查看完整版本: 《Fundamentals of Computer Graphics》第五章 表面着色