计算机图形学笔记(三)Shading

本篇博文为闫令琪大佬的Games101 P7、P8、P9课程的笔记,同时参考了《Unity Shader入门精要》的部分内容。

计算机图形学笔记(三)Shading

1. 深度缓冲

上一篇笔记以单个三角形为研究对象,研究了一个三角形的光栅化过程。而模型是由一系列的空间三角形组成的三角网格,不同的三角形之间(尤其是不同物体的三角网格)可能存在遮挡关系,因此需要对三角形按照距离相机的远近进行排序,以得到三角形之间正确的遮挡关系。对于简单的问题可以通过画家算法进行处理

“画家算法”表示画家首先绘制距离较远的场景,然后用绘制距离较近的场景覆盖较远的部分。画家算法首先将场景中的多边形根据深度进行排序,然后按照顺序进行描绘。这种方法通常会将不可见的部分覆盖,这样就可以解决可见性问题。

但对于下图所示的自相交问题,画家算法无法解决,而在真实的虚拟场景构建中,这类复杂情况其实非常普遍,因此在实际的渲染中引入了深度缓冲(Z-Buffer),深度缓冲以像素为单位对其进行深度排序。

当执行物体渲染的时候,每一个像素所生成的像素的深度(即z坐标)就保存在一个缓冲区中。这个缓冲区叫作z缓冲区或者深度缓冲区,这个缓冲区通常组织成一个保存每个屏幕像素深度的x-y二维数组。如果场景中的另外一个物体也在同一个像素生成渲染结果,那么图形处理卡就会比较二者的深度,并且保留距离观察者较近的物体。然后这个所保留的物体点深度保存到深度缓冲区中。最后,图形卡就可以根据深度缓冲区正确地生成通常的深度感知效果:较近的物体遮挡较远的物体。

对于某一帧渲染的图像,其对应的深度缓冲区的内容实际上是一张深度图(如下图所示),距离相机越近的区域值越小(颜色越黑),距离相机越远的区域值越大(颜色越白)。

对深度缓冲的操作除了能获得正确的遮挡关系外,另一个非常经典的应用是渲染半透明效果,另外通过不同的深度测试可以实现更为复杂的渲染效果。

2. 光源

小学知识告诉我们,我们所看到的物体颜色实际上是其反射了较多该颜色的波长,而吸收了其他颜色的波长,如果我们看到一个物体是黑色的,实际上是因为其吸收了绝大部分波长。在模拟真实的光照渲染出一张图像时,需要考虑三种物理现象:

  • 光从光源中发射出来
  • 光线和场景中的一些物体相交:一些光线被物体吸收,一些光则被散射到其他物体。
  • 摄像机吸收了一些光产生了一张图像。

2.1 光源

光是由光源发射出来的,在实时渲染中,通常将光源当成一个没有体积的点,用 l l l表示光照方向,通过辐照度来量化光(辐射照度表征了受辐射能照射的表面上,单位面积单位时间内接收的辐射能的多少)。对于平行光,它的辐照度可以通过计算垂直于 l l l的单位面积上单位时间内穿过的能量来得到。在渲染时,需要计算一个物体表面的辐照度,而物体表面和光线往往是不垂直的,可使用光源方向 l l l和物体表面法线 n n n之间夹角的余弦值得到, c o s θ cosθ cosθ可以通过光源方向 l l l和物体表面法向 n n n的点乘得到**。需要注意的是这里的方向矢量均为单位矢量

2.2 吸收和散射

光线线与物体相交后通常有两种结果:散射吸收
散射只改变光线的方向,不改变光线的密度和颜色。而吸收只改变光线的密度和颜色,但不改变光线的方向。光线在物体表面经过散射后,有两种方向:一种是会散射到物体内部,这种现象被称为折射(或透射);另一种将会散射到外部,这种现场被称为反射。对于不透明的物体,折射进物体内部的光线还会继续与内部颗粒进行相交,其中一些光线最后会重新发射出物体表面,而另一些则被物体吸收。那些从物体表面重新发射出来的光线将具有与入射光线不同的方向分布和颜色。

在光照模型中使用了不同的计算来区分它们,高光反射Specular)部分表示物体表面是如何反射光线的,而漫反射(diffuse)部分则表示有多少光线会被折射、吸收和散射出表面。根据入射光线的数量和方向,我们可以计算出射光线的数量和方向,通常用出射度来描述它,辐照度和出射度之间满足线性关系,而他们之间的比值就是材质的漫反射和高光反射属性。

2.3 着色(Shading)

着色(Shading)是指,根据材质属性(如漫反射属性等)、光源信息(如光源方向、辐照度等),使用一个等式计算沿某个观察方向的出射度的过程。我们也把这个等式称为光照模型

3. 标准光照模型

虽然光照模型由很多种类,但在早期的游戏引擎中往往只使用一个光照模型,这个模型被称为“标准光照模型”,标准光照模型只关心直接光照,也就是那些从光源发射出来照亮物体表面后,经过物体表面的一次反射直接进入摄像机的光线。它的基本方法是,把摄像机内的光线分为4个部分,每个部分使用一种方法来计算它的贡献度:

  • 自发光:由模型自己散发的光源,这部分用于描述当给定一个方向时,一个表面本身会向该方向发射多少辐射量。
  • 高光反射(specular):用于描述当光线从光源照射进模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
  • 漫反射(diffuse):用于描述当光线从光源照射到模型表面时,该表面会向每个方向散射多少辐射量。
  • 环境光(ambient):描述了其他所有的间接光照。
    下图用来描述标准光照模型中不同光照模型计算的分布(没有体现自发光,且该图片也不是由标准光照模型计算得出的结果,仅用作帮助理解不同的光照计算对应了什么效果)

3.1 环境光

虽然标准光照模型的重点在于描述直接光照,但在真实的世界中,物体也可以被间接光照所照亮。间接光照是指,光线通常会在多个物体之间反射,最后进入摄像机,也就是说,在光线进入摄像机之前,经历不止一次的物体反射。在标准光照模型中,对间接光照进行了简化,通过使用一种被称为环境光的部分来近似模拟间接光照,它通常是一个全局变量,即场景中所有的物体都是使用这个环境光。

环境光照(Ambient Lighting):即使在黑暗的情况下,世界上也仍然有一些光亮(月亮、一个来自远处的光),所以物体永远不会是完全黑暗的。我们使用环境光照来模拟这种情况,也就是无论如何永远都给物体一些颜色。

C a m b i e n t = g a m b i e n t C_{ambient}=g_{ambient} Cambient=gambient

3.2 自发光

光线也可直接由光源发射进摄像机,而不需要与任何物体的反射。标准光照模型使用自发光来计算这部分的贡献度,它的计算也很简单,就是直接使用了该材质的自发光颜色。
C e m i s s i v e = m e m i s s i v e C_{emissive}=m_{emissive} Cemissive=memissive

3.3 漫反射

漫反射光照用是于对那些被物体表随机散射到各个方向的辐射度进行建模的,在漫反射中,视角的位置是不重要的,因为反射是完全随机的,因此可以因为在任何反射方向上的部分都是一样的。但是,入射光线的角度很重要。
标准光照模型使用兰伯特模型来反映漫反射部分,兰伯特模型的计算如下:
c d i f f u s e = ( c l i g h t ⋅ m d i f f u s e ) m a x ( 0 , n ⋅ l ) c_{diffuse}=(c_{light}·m_{diffuse})max(0,n·l) cdiffuse=(clightmdiffuse)max(0,nl)
其中 n n n是表面法线, I I I是入射光源的单位矢量, m d i f f u s e m_{diffuse} mdiffuse是材质的漫反射颜色, c d i f f u s e c_{diffuse} cdiffuse是光源颜色, m a x ( ) max() max()是为了防止法线和光源方向的点乘结果为负值, n ⋅ l n·l nl即为2.1节描述的对于同一盏光源在不同位置的辐照度。
兰伯特模型的示意图如下图所示:

下图是随着漫反射系数增大的效果对比,用于帮助理解漫反射达到什么视觉效果。

3.4 高光反射

这里的高光反射是一种经验模型,它并不完全符合真实世界中高光反射现象。它可以用于计算哪些沿着完全镜面反射方向被反射的光线,这让一些物体看起来是有光泽的,例如金属材质。高光反射效果如下图所示(其余白色照亮部分由漫反射、环境光贡献)。

高光反射的计算原理参考下图,首先对于理想的完全镜面反射的物体,光线 l l l的反射方向为 R R R,由于物体表面存在一定的粗糙度,则反射光线分布在 R R R的周围(物体越粗糙,分布范围越大,亮点越大,反之亮点越小)。且只有当视角方向在 R R R附近时才能看到高光现象。

高光反射可通过Phong模型计算:
c s p e c u l a r = ( c l i g h t ⋅ m s p e c u l a r ) m a x ( 0 , v ⋅ R ) m g l o s s c_{specular}=(c_{light}·m_{specular}){max(0,v·R)}^{m_{gloss}} cspecular=(clightmspecular)max(0,vR)mgloss
其中, m g l o s s m_{gloss} mgloss是材质的光泽度,也被称作反光度, m g l o s s m_{gloss} mgloss越大,上图中的亮点就越小,这描述了不同材质的反射强度,物体表面越粗糙则反光度越低,亮点越大,反之则亮点越小; m s p e c u l a r m_{specular} mspecular是材质的高光反射颜色,用于控制该材质对于高光反射的强度和颜色; c l i g h t c_{light} clight是光源的颜色和强度; R R R可通过下列公式计算得出(关于反射方向的向量推导,可参考这篇博文), v ⋅ R v·R vR描述了视角方向是否接近反射方向。
r = 2 ( n ⋅ I ) n − I r=2(n·I)n-I r=2(nI)nI
和Phong模型相比,Blinn提出了一种简单的修改方法实现类似的效果,其计算远原理如下图所示,视角方向 v v v和光线反射方向 R R R相近意味着 l l l v v v的半程向量 h h h与表面法向量 n n n接近,则 v ⋅ R v·R vR就被转化为 h ⋅ n h·n hn

Blinn模型的计算公式为:
c s p e c u l a r = ( c l i g h t ⋅ m s p e c u l a r ) m a x ( 0 , h ⋅ n ) m g l o s s c_{specular}=(c_{light}·m_{specular}){max(0,h·n)}^{m_{gloss}} cspecular=(clightmspecular)max(0,hn)mgloss
其中
h = v + I ∣ v + I ∣ h=\frac{v+I}{|v+I|} h=v+Iv+I

3.5 总结

标准光照模型仅仅是一个经验模型,它并不完全符合真实世界中的光照现象。标准光照模型也被称为Phong光照模型,因为裴祥风(Bui Tuong Phong)首先提出使用漫反射和高光反射进行建模的基本思想,并提出了基于经验的计算高光反射方法。而后Blinn的方法简化了计算,外面把这种模型称为Blinn-Phong光照模型

4. 着色频率

上述内容描述了基本光照模型的计算公式,通常来说有两种选择来计算这些光照模型:在片元着色器中计算,也被称为逐像素光照;在顶点着色器中计算,也被称为逐顶点光照
在逐像素光照中,以每个像素为基础,得到它的法线(可以是对顶点法线插值得到,也可以是从法线纹理中采样得到),然后进行光照模型计算。这种在面片之间对顶点法线进行插值的技术被称为Phong着色(Phong shading),也被称为Phong插值或法线插值着色技术。这不同于上述中的Phong光照模型。
逐顶点光照也被称为高洛德着色,在逐顶点光照中,我们在每个顶点上计算光照模型,然后会在渲染图元中进行线性插值,最后输出成像素颜色。由于顶点数量往往远小于像素数目,因此逐顶点的计算量要小于逐像素光照。但由于逐顶点光照依赖于线性插值得到像素光照,因此,当光照模型中有非线性计算时(如高光反射计算),逐顶点光照就会出现问题。

下图是逐顶点和逐像素高光好色的对比效果。

Reference

  1. 《Unity Shader入门精要》 冯乐乐著
  2. GAMES101-现代计算机图形学入门-闫令琪 P7、P8
  3. 手动计算反射方向

猜你喜欢

转载自blog.csdn.net/qq_15017307/article/details/126611612